/* Help4 Builder Suite 1.3.401 */
(function ($) {
    "use strict";

    const data = window.h4bsBuilderStudioData || null;
    if (!data) {
        return;
    }

    const root = document.querySelector("[data-h4bs-builder-studio]");
    if (!root) {
        return;
    }

    const PAGE_SPEC_PREFIX = "H4BS_PAGE::";
    const BLOCK_SPEC_PREFIX = "H4BS_BLOCK::";
    const FRAME_STORAGE_KEY = "h4bs.frameMode";
    const PREVIEW_SIZING_STORAGE_KEY = "h4bs.previewSizingMode";
    const PARITY_STORAGE_KEY = "h4bs.parityMode";
    const STYLE_CLIPBOARD_KEY = "h4bs.styleClipboard";
    const WIDGET_FAVORITES_KEY = "h4bs.widgetFavorites";
    const WIDGET_RECENT_KEY = "h4bs.widgetRecent";
    const WIDGET_FILTER_KEY = "h4bs.widgetFilter";
    const ELEMENT_FILTER_KEY = "h4bs.elementFilter";
    const LIBRARY_TAB_KEY = "h4bs.libraryTab";
    const SIDE_COLLAPSED_KEY = "h4bs.sideCollapsed";
    const CANVAS_FOCUS_KEY = "h4bs.canvasFocus";
    const INSPECTOR_WIDTH_KEY = "h4bs.inspectorWidth";
    const QUICK_ACTIONS_RECENT_KEY = "h4bs.quickActionsRecent";
    const PREVIEW_RECONCILE_DELAY_MS = 420;
    const MAX_COLUMNS = 24;
    const MAX_SLOT = MAX_COLUMNS - 1;
    const BOX_MODEL_KEYS = {
        margin: {
            unit: "design_margin_unit",
            top: "design_margin_top",
            right: "design_margin_right",
            bottom: "design_margin_bottom",
            left: "design_margin_left",
        },
        padding: {
            unit: "design_padding_unit",
            top: "design_padding_top",
            right: "design_padding_right",
            bottom: "design_padding_bottom",
            left: "design_padding_left",
        },
    };

    const state = {
        layout: normalizeLayout(data.layout),
        pageLayout: normalizePageLayout(data.pageLayout),
        pageTitleMode: normalizePageTitleMode(data.pageTitleMode),
        pageCss: String(data.pageCss || ""),
        pageCssHash: String(data.pageCssHash || ""),
        previewTemplateSlots: normalizePreviewTemplateSlots(data.previewTemplateSlots),
        globalDesignTokens: normalizeGlobalDesignTokens(data.globalDesignTokens),
        globalDesignRevision: Math.max(1, Number(data.globalDesignRevision || 1) || 1),
        globalDesignHash: String(data.globalDesignHash || ""),
        layoutHash: String(data.layoutHash || ""),
        pageDirty: false,
        globalDesignDirty: false,
        globalDesignConflict: false,
        savedPageStateKey: "",
        savedGlobalStateKey: "",
        modalGlobalDirty: false,
        customThemePacks: normalizeCustomThemePacks(data.customThemePacks),
        activeThemePack: String(data.activeThemePack || "").trim(),
        isTemplate: !!data.isTemplate,
        isFreshPage: !!data.isFreshPage,
        postStatus: String(data.postStatus || "draft"),
        postStatusLabel: String(data.postStatusLabel || "Draft"),
        canPublish: !!data.canPublish,
        explicitFirstSaveRequired: !!data.isFreshPage,
        startJourneyDismissed: false,
        templateUseCase: "all",
        templatePreviewSlug: "",
        templatePreviewDevice: "desktop",
        templatePreviewReturnFocus: null,
        templateConditions: normalizeTemplateConditions(data.templateConditions),
        selectedId: null,
        pendingInsertTarget: null,
        modalBlockId: null,
        modalMode: null,
        modalDirty: false,
        modalDraftBlock: null,
        htmlQuickEditTarget: null,
        modalActiveTab: "content",
        modalDraftPage: null,
        modalDesignDevice: "desktop",
        modalDesignState: "normal",
        previewDragging: false,
        previewClickTimer: null,
        viewportSlug: initialViewportSlug(),
        viewportGroup: "monitor",
        frameMode: readStoredFrameMode(),
        previewSizingMode: readStoredPreviewSizingMode(),
        parityMode: false,
        parityPreviousSizingMode: null,
        parityPendingOpen: false,
        draftPreviewUrl: "",
        draftPreviewFingerprint: "",
        sideCollapsed:
            !!(
                window.matchMedia &&
                window.matchMedia("(max-width: 1180px)").matches
            ) || readStoredBoolean(SIDE_COLLAPSED_KEY, false),
        compactWorkspace: !!(
            window.matchMedia &&
            window.matchMedia("(max-width: 1180px)").matches
        ),
        canvasFocus: readStoredBoolean(
            CANVAS_FOCUS_KEY,
            !!(
                window.matchMedia &&
                window.matchMedia("(max-width: 800px)").matches
            )
        ),
        inspectorWidth: readStoredNumber(INSPECTOR_WIDTH_KEY, 420, 360, 560),
        inspectorAutoCollapsedSide: false,
        inspectorPreviousSideCollapsed: false,
        modalReturnFocus: null,
        inspectorSettingFinderCleanup: null,
        activeLibraryTab: readStoredLibraryTab(),
        navigatorOpen: false,
        navigatorReturnFocus: null,
        navigatorCollapsed: {},
        miniPreviewOpen: false,
        quickActionsOpen: false,
        quickActionsReturnFocus: null,
        quickActionActiveIndex: -1,
        quickActionResults: [],
        reviewOpen: false,
        reviewReturnFocus: null,
        reviewedDevices: { monitor: false, tablet: false, mobile: false },
        publishing: false,
        miniPreviewSyncTimer: null,
        miniPreviewMarkupHash: "",
        activeDragPayload: null,
        modalPreviewTimer: null,
        modalInputActiveUntil: 0,
        libraryDragStartedAt: 0,
        previewRenderTimer: null,
        previewRenderInFlight: false,
        previewRenderQueued: false,
        previewRenderRequestId: 0,
        previewRenderRevision: 0,
        previewRenderLayout: [],
        previewRenderPageLayout: "default",
        previewLastSubmittedKey: "",
        previewLoadStartedAt: 0,
        previewMeasuredMs: 0,
        previewMeasuredTtfbMs: 0,
        previewMeasuredRenderMs: 0,
        draftFrameScrollX: 0,
        draftFrameScrollY: 0,
        contextMenuOpen: false,
        contextMenuBlockId: null,
        styleClipboard: null,
        elementFilter: readStoredElementFilter(),
        widgetFilter: readStoredWidgetFilter(),
        widgetFavorites: readStoredWidgetFavorites(),
        widgetRecent: readStoredWidgetRecent(),
        historyPast: [],
        historyFuture: [],
        historyLimit: 120,
        idSeed: Math.max(1, Math.floor(Math.random() * 50000)),
        boxModelDrag: null,
        dirty: false,
        saving: false,
    };
    const deferredCatalogs = new Set(
        (Array.isArray(data.deferredCatalogs) ? data.deferredCatalogs : []).map(
            function (catalog) {
                return normalizeLibraryTab(catalog);
            }
        )
    );
    const catalogLoads = {};
    ["templates", "site-kits", "themes"].forEach(function (catalog) {
        catalogLoads[catalog] = {
            loaded: !deferredCatalogs.has(catalog),
            request: null,
        };
    });

    if (state.layout.length > 0) {
        state.selectedId = String(state.layout[0].id || "");
    }
    captureSavedBaselines();

    const els = {
        blockList: document.querySelector("[data-h4bs-block-list]"),
        previewStage: root.querySelector("[data-h4bs-preview-stage]"),
        previewScale: root.querySelector("[data-h4bs-preview-scale]"),
        previewShell: root.querySelector("[data-h4bs-preview-shell]"),
        previewCanvas: root.querySelector("[data-h4bs-preview-canvas]"),
        selectionActions: root.querySelector("[data-h4bs-selection-actions]"),
        selectionLabel: root.querySelector("[data-h4bs-selection-label]"),
        selectionStatus: root.querySelector("[data-h4bs-selection-status]"),
        selectionButtons: root.querySelectorAll("[data-h4bs-selection-action]"),
        selectionInside: root.querySelector("[data-h4bs-selection-inside]"),
        selectionSlot: root.querySelector("[data-h4bs-selection-slot]"),
        insertTarget: root.querySelector("[data-h4bs-insert-target]"),
        insertTargetLabel: root.querySelector("[data-h4bs-insert-target-label]"),
        insertTargetCancel: root.querySelector("[data-h4bs-insert-target-cancel]"),
        startJourney: root.querySelector("[data-h4bs-start-journey]"),
        startActions: root.querySelectorAll("[data-h4bs-start-action]"),
        copySourcePanel: root.querySelector("[data-h4bs-copy-source-panel]"),
        copySourceSelect: root.querySelector("[data-h4bs-copy-source-select]"),
        copySourceConfirm: root.querySelector("[data-h4bs-copy-source-confirm]"),
        startStatus: root.querySelector("[data-h4bs-start-status]"),
        elementSearch: root.querySelector("[data-h4bs-element-search]"),
        elementButtons: root.querySelector("[data-h4bs-element-buttons]"),
        templateList: root.querySelector("[data-h4bs-template-list]"),
        templateSearch: root.querySelector("[data-h4bs-template-search]"),
        templateCategory: root.querySelector("[data-h4bs-template-category]"),
        templateUseCases: root.querySelector("[data-h4bs-template-use-cases]"),
        templateResults: root.querySelector("[data-h4bs-template-results]"),
        templatePreviewModal: root.querySelector("[data-h4bs-template-preview-modal]"),
        templatePreviewTitle: root.querySelector("[data-h4bs-template-preview-title]"),
        templatePreviewCategory: root.querySelector("[data-h4bs-template-preview-category]"),
        templatePreviewDescription: root.querySelector("[data-h4bs-template-preview-description]"),
        templatePreviewCount: root.querySelector("[data-h4bs-template-preview-count]"),
        templatePreviewIncludes: root.querySelector("[data-h4bs-template-preview-includes]"),
        templatePreviewStage: root.querySelector("[data-h4bs-template-preview-stage]"),
        templatePreviewClose: root.querySelector("[data-h4bs-template-preview-close]"),
        templatePreviewCancel: root.querySelector("[data-h4bs-template-preview-cancel]"),
        templatePreviewUse: root.querySelector("[data-h4bs-template-preview-use]"),
        templatePreviewSecondary: root.querySelector("[data-h4bs-template-preview-secondary]"),
        templatePreviewDevices: root.querySelectorAll("[data-h4bs-template-preview-device]"),
        siteKitList: root.querySelector("[data-h4bs-site-kit-list]"),
        siteKitSearch: root.querySelector("[data-h4bs-site-kit-search]"),
        siteKitApplyStyles: root.querySelector(
            "[data-h4bs-site-kit-apply-styles]"
        ),
        siteKitStatus: root.querySelector("[data-h4bs-site-kit-status]"),
        themeList: root.querySelector("[data-h4bs-theme-list]"),
        themeSearch: root.querySelector("[data-h4bs-theme-search]"),
        saveThemePack: root.querySelector("[data-h4bs-save-theme-pack]"),
        importThemePack: root.querySelector("[data-h4bs-import-theme-pack]"),
        exportThemePack: root.querySelector("[data-h4bs-export-theme-pack]"),
        widgetSearch: root.querySelector("[data-h4bs-widget-search]"),
        widgetList: root.querySelector("[data-h4bs-widget-list]"),
        sidePanel: root.querySelector("[data-h4bs-side-panel]"),
        sideToggle: root.querySelector("[data-h4bs-side-toggle]"),
        sideToggleLabel: root.querySelector(".h4bs-side-toggle-label"),
        sideHeading: root.querySelector("[data-h4bs-side-heading]"),
        sideDescription: root.querySelector("[data-h4bs-side-description]"),
        sideHelp: root.querySelector("[data-h4bs-side-help]"),
        sideHelpLabel: root.querySelector("[data-h4bs-side-help-label]"),
        libraryTabButtons: root.querySelectorAll("[data-h4bs-library-tab]"),
        libraryPanels: root.querySelectorAll("[data-h4bs-library-panel]"),
        inspectorEmpty: root.querySelector("[data-h4bs-inspector-empty]"),
        quickHelp: document.querySelector("[data-h4bs-quick-help]"),
        quickHelpToggle: document.querySelector("[data-h4bs-quick-help-toggle]"),
        quickHelpSearch: document.querySelector("[data-h4bs-quick-help-search]"),
        quickHelpClear: document.querySelector("[data-h4bs-quick-help-clear]"),
        quickHelpStatus: document.querySelector("[data-h4bs-quick-help-status]"),
        quickHelpEmpty: document.querySelector("[data-h4bs-quick-help-empty]"),
        quickHelpLinks: document.querySelectorAll("[data-h4bs-quick-help-link]"),
        canvasFocusToggle: document.querySelector("[data-h4bs-toggle-canvas-focus]"),
        canvasFocusLabel: document.querySelector("[data-h4bs-canvas-focus-label]"),
        toolsMenu: document.querySelector("[data-h4bs-tools-menu]"),
        commandMenu: document.querySelector("[data-h4bs-command-menu]"),
        openNavigator: document.querySelector("[data-h4bs-open-navigator]"),
        navigatorModal: document.querySelector("[data-h4bs-navigator-modal]"),
        closeNavigator: document.querySelector("[data-h4bs-close-navigator]"),
        navigatorDragHandle: document.querySelector("[data-h4bs-navigator-drag]"),
        openMiniPreview: document.querySelector("[data-h4bs-open-mini-preview]"),
        addElement: document.querySelector("[data-h4bs-add-element]"),
        parityToggle: document.querySelector("[data-h4bs-toggle-parity]"),
        parityLabel: document.querySelector("[data-h4bs-parity-label]"),
        paritySelectionHelp: document.querySelector(
            "[data-h4bs-parity-selection-help]"
        ),
        previewAssetStatus: document.querySelector("[data-h4bs-preview-asset-status]"),
        compareParity: document.querySelector("[data-h4bs-compare-parity]"),
        parityStatus: root.querySelector("[data-h4bs-parity-status]"),
        miniPreviewModal: document.querySelector("[data-h4bs-mini-preview-modal]"),
        closeMiniPreview: document.querySelector("[data-h4bs-close-mini-preview]"),
        miniPreviewDragHandle: document.querySelector("[data-h4bs-mini-preview-drag]"),
        miniPreviewFrame: document.querySelector("[data-h4bs-mini-preview-frame]"),
        miniPreviewScale: document.querySelector("[data-h4bs-mini-preview-scale]"),
        miniPreviewShell: document.querySelector("[data-h4bs-mini-preview-shell]"),
        miniPreviewWindow: document.querySelector("[data-h4bs-mini-preview-window]"),
        miniPreviewLabel: document.querySelector("[data-h4bs-mini-preview-label]"),
        miniPreviewScroll: document.querySelector("[data-h4bs-mini-preview-scroll]"),
        openQuickActions: document.querySelector("[data-h4bs-open-quick-actions]"),
        quickActionsModal: document.querySelector("[data-h4bs-quick-actions-modal]"),
        quickActionsDialog: document.querySelector("[data-h4bs-quick-actions-dialog]"),
        quickActionsCloseButtons: document.querySelectorAll(
            "[data-h4bs-quick-actions-close]"
        ),
        quickActionsSearch: document.querySelector("[data-h4bs-quick-actions-search]"),
        quickActionsList: document.querySelector("[data-h4bs-quick-actions-list]"),
        quickActionsStatus: document.querySelector("[data-h4bs-quick-actions-status]"),
        quickActionsEmpty: document.querySelector("[data-h4bs-quick-actions-empty]"),
        openReview: document.querySelector("[data-h4bs-open-review]"),
        reviewModal: document.querySelector("[data-h4bs-review-modal]"),
        reviewDialog: document.querySelector(".h4bs-review-dialog"),
        reviewCloseButtons: document.querySelectorAll("[data-h4bs-review-close]"),
        reviewPostStatus: document.querySelector("[data-h4bs-review-post-status]"),
        reviewSummaryTitle: document.querySelector("[data-h4bs-review-summary-title]"),
        reviewSummaryText: document.querySelector("[data-h4bs-review-summary-text]"),
        reviewChecks: document.querySelector("[data-h4bs-review-checks]"),
        reviewDeviceButtons: document.querySelectorAll("[data-h4bs-review-device]"),
        reviewActionStatus: document.querySelector("[data-h4bs-review-action-status]"),
        reviewPreview: document.querySelector("[data-h4bs-review-preview]"),
        reviewSave: document.querySelector("[data-h4bs-review-save]"),
        reviewPublish: document.querySelector("[data-h4bs-review-publish]"),
        pageStatus: document.querySelector("[data-h4bs-page-status]"),
        saveCommandLabels: document.querySelectorAll("[data-h4bs-save-command-label]"),
        assignedTemplateButtons: document.querySelectorAll(
            "[data-h4bs-edit-assigned-template]"
        ),
        saveBeforeLeaveLinks: document.querySelectorAll(
            "[data-h4bs-save-before-leave]"
        ),
        undoButton: document.querySelector("[data-h4bs-undo]"),
        redoButton: document.querySelector("[data-h4bs-redo]"),
        copyPageSpec: document.querySelector("[data-h4bs-copy-page-spec]"),
        pastePageSpec: document.querySelector("[data-h4bs-paste-page-spec]"),
        modal: document.querySelector("[data-h4bs-editor-modal]"),
        modalBackdrop: document.querySelector("[data-h4bs-modal-backdrop]"),
        modalBody: document.querySelector("[data-h4bs-modal-body]"),
        modalTitle: document.querySelector("[data-h4bs-modal-title]"),
        contextHelp: document.querySelector("[data-h4bs-context-help]"),
        contextHelpLabel: document.querySelector(
            "[data-h4bs-context-help-label]"
        ),
        inspectorStatus: document.querySelector("[data-h4bs-inspector-status]"),
        modalCancelButtons: document.querySelectorAll("[data-h4bs-modal-cancel]"),
        modalReviewButton: document.querySelector("[data-h4bs-modal-review]"),
        modalSaveButton: document.querySelector("[data-h4bs-modal-save]"),
        modalDeleteButton: document.querySelector("[data-h4bs-modal-delete]"),
        modalDragHandle: document.querySelector("[data-h4bs-modal-drag]"),
        modalResizeHandle: document.querySelector("[data-h4bs-inspector-width]"),
        studioWrap: root.closest(".h4bs-builder-studio-wrap"),
        saveButtons: document.querySelectorAll("[data-h4bs-save-layout]"),
        dirtyState: root.querySelector("[data-h4bs-dirty-state]"),
        estimate: root.querySelector("[data-h4bs-builder-estimate]"),
        performanceCoach: root.querySelector("[data-h4bs-performance-coach]"),
        performanceSummary: root.querySelector("[data-h4bs-performance-summary]"),
        performanceTips: root.querySelector("[data-h4bs-performance-tips]"),
        pageLayoutLabel: root.querySelector("[data-h4bs-page-layout-label]"),
        viewportIcons: root.querySelector("[data-h4bs-viewport-icons]"),
        viewportSelect: root.querySelector("[data-h4bs-viewport-select]"),
        viewportLive: root.querySelector("[data-h4bs-viewport-live]"),
        frameButtons: root.querySelectorAll("[data-h4bs-frame-mode]"),
        previewSizingButtons: root.querySelectorAll(
            "[data-h4bs-preview-sizing]"
        ),
        boxModelOverlay: null,
        contextMenu: null,
    };

    boot();

    function boot() {
        if (els.modal) {
            els.modal.hidden = true;
        }
        if (els.modalBackdrop) {
            els.modalBackdrop.hidden = true;
        }
        if (els.navigatorModal) {
            els.navigatorModal.hidden = true;
        }
        if (els.miniPreviewModal) {
            els.miniPreviewModal.hidden = true;
        }
        if (els.reviewModal) {
            els.reviewModal.hidden = true;
        }
        if (els.quickActionsModal) {
            els.quickActionsModal.hidden = true;
        }
        const initialViewport = viewportBySlug(state.viewportSlug);
        state.viewportGroup = inferViewportGroup(initialViewport);
        renderElementButtons();
        window.h4bsBuilderStudioInspectorContract = inspectorContractSnapshot;
        buildViewportControls();
        applyParityMode();
        initWorkspaceControls();
        initSidePanel();
        initInspectorResize();
        initQuickHelp();
        initLibraryTabs();
        initSelectionActionBar();
        initTemplatePreview();
        initStartJourney();
        ensureLibraryCatalog(state.activeLibraryTab, true);
        initNavigatorModal();
        initMiniPreviewModal();
        initQuickActions();
        initReviewWorkspace();
        initContextMenu();
        state.styleClipboard = readStoredStyleClipboard();
        seedHistoryBaseline();
        ensureBoxModelOverlay();
        renderAll();
        renderAssignedTemplateButtons();
        wireSaveBeforeLeaveLinks();
        wireGlobalControls();
        wireModal();
        closeBuilderModal(true);
        closeNavigatorModal();
        closeMiniPreviewModal();
        closeContextMenu();
        applyViewport();
        syncSelectedPreviewBlockVisual();
        setInterval(function () {
            if (state.dirty && !state.saving && !state.explicitFirstSaveRequired) {
                saveLayout(true);
            }
        }, 20000);
        window.addEventListener("beforeunload", function (event) {
            if (!state.dirty) {
                return;
            }
            event.preventDefault();
            event.returnValue = "";
        });
    }

    function normalizeLayout(raw) {
        if (!Array.isArray(raw)) {
            return [];
        }
        const out = [];
        raw.forEach(function (block, index) {
            if (!block || typeof block !== "object") {
                return;
            }
            const type = normalizeBlockType(block.type || "text", "text");
            if (type === "") {
                return;
            }
            const visibilityRaw =
                block.visibility && typeof block.visibility === "object"
                    ? block.visibility
                    : {};
            const includeIds = Array.isArray(visibilityRaw.include_ids)
                ? visibilityRaw.include_ids.join(",")
                : String(visibilityRaw.include_ids || "");
            const excludeIds = Array.isArray(visibilityRaw.exclude_ids)
                ? visibilityRaw.exclude_ids.join(",")
                : String(visibilityRaw.exclude_ids || "");
            const userRoles = Array.isArray(visibilityRaw.user_roles)
                ? visibilityRaw.user_roles.join(",")
                : String(visibilityRaw.user_roles || "");

            const extensions =
                block.extensions && typeof block.extensions === "object"
                    ? deepClone(block.extensions)
                    : {};
            Object.keys(block).forEach(function (key) {
                if (
                    ["schema_version", "id", "type", "settings", "visibility", "parent_id", "slot", "extensions"].indexOf(key) >= 0 ||
                    !/[:/]/.test(key)
                ) {
                    return;
                }
                if (!extensions.opaque || typeof extensions.opaque !== "object") {
                    extensions.opaque = {};
                }
                extensions.opaque[key] = deepClone(block[key]);
            });
            const normalizedSettings =
                block.settings && typeof block.settings === "object"
                    ? deepClone(block.settings)
                    : {};
            if (["list", "faq"].indexOf(type) >= 0 && typeof normalizedSettings.items === "string") {
                normalizedSettings.items = normalizeMultilineDelimiters(normalizedSettings.items);
            }
            out.push({
                schema_version: String(block.schema_version || "1.0"),
                id: String(block.id || makeId(type, index)),
                type: type,
                settings: normalizedSettings,
                visibility: {
                    scope: String(visibilityRaw.scope || "all"),
                    include_ids: includeIds,
                    exclude_ids: excludeIds,
                    user_roles: userRoles,
                    viewport: String(visibilityRaw.viewport || "all"),
                },
                parent_id: String(block.parent_id || ""),
                slot: Math.max(0, Number(block.slot || 0) || 0),
                extensions: extensions,
            });
        });
        return out;
    }

    function normalizeTemplateConditions(raw) {
        const source = raw && typeof raw === "object" ? raw : {};
        return {
            role: String(source.role || "general"),
            scope: String(source.scope || "entire_site"),
            include_ids: String(source.include_ids || ""),
            exclude_ids: String(source.exclude_ids || ""),
            include_types: String(source.include_types || ""),
            exclude_types: String(source.exclude_types || ""),
            user_roles: String(source.user_roles || ""),
            priority: String(source.priority || "10"),
        };
    }

    function normalizePreviewTemplateSlots(raw) {
        const source = raw && typeof raw === "object" ? raw : {};
        return {
            header_template_id: Math.max(
                0,
                Number(source.header_template_id || 0) || 0
            ),
            footer_template_id: Math.max(
                0,
                Number(source.footer_template_id || 0) || 0
            ),
            header_html: String(source.header_html || ""),
            footer_html: String(source.footer_html || ""),
        };
    }

    function assignedTemplateEditorByRole(role) {
        const slug = String(role || "").trim().toLowerCase();
        if (slug === "") {
            return null;
        }

        const slotKey = slug + "_template_id";
        const slotId = Math.max(
            0,
            Number(
                state.previewTemplateSlots &&
                    Object.prototype.hasOwnProperty.call(
                        state.previewTemplateSlots,
                        slotKey
                    )
                    ? state.previewTemplateSlots[slotKey]
                    : 0
            ) || 0
        );
        const sourceCatalog =
            data.assignedTemplateEditors && typeof data.assignedTemplateEditors === "object"
                ? data.assignedTemplateEditors
                : {};
        const source =
            sourceCatalog && typeof sourceCatalog[slug] === "object"
                ? sourceCatalog[slug]
                : {};

        const templateId = Math.max(
            0,
            Number(source.template_id || slotId || 0) || 0
        );
        if (templateId <= 0) {
            return null;
        }

        const fallbackBuilderBase = String(data.builderStudioBaseUrl || "");
        const fallbackEditorBase = String(data.wpEditorBaseUrl || "");
        const builderUrlRaw = String(source.builder_url || "").trim();
        const editorUrlRaw = String(source.wp_editor_url || "").trim();
        const builderUrl =
            builderUrlRaw !== ""
                ? builderUrlRaw
                : fallbackBuilderBase !== ""
                    ? fallbackBuilderBase + String(templateId)
                    : "";
        const wpEditorUrl =
            editorUrlRaw !== ""
                ? editorUrlRaw
                : fallbackEditorBase !== ""
                    ? fallbackEditorBase + String(templateId)
                    : "";
        const labelRaw = String(source.label || slug).trim();
        const label = labelRaw !== "" ? labelRaw : slug;

        return {
            template_id: templateId,
            builder_url: builderUrl,
            wp_editor_url: wpEditorUrl,
            label: label,
            role: slug,
        };
    }

    function renderAssignedTemplateButtons() {
        if (!els.assignedTemplateButtons || els.assignedTemplateButtons.length < 1) {
            return;
        }

        els.assignedTemplateButtons.forEach(function (button) {
            const role = String(
                button.getAttribute("data-h4bs-edit-assigned-template") || ""
            )
                .trim()
                .toLowerCase();
            const info = assignedTemplateEditorByRole(role);
            if (!info || String(info.builder_url || "").trim() === "") {
                button.hidden = true;
                button.setAttribute("aria-hidden", "true");
                button.setAttribute("href", "#");
                button.removeAttribute("data-h4bs-template-id");
                button.removeAttribute("data-h4bs-template-builder-url");
                button.removeAttribute("data-h4bs-template-wp-url");
                button.removeAttribute("data-h4bs-template-label");
                return;
            }

            const title =
                "Edit assigned " + String(info.label || role) + " template";
            button.hidden = false;
            button.removeAttribute("aria-hidden");
            button.setAttribute("href", String(info.builder_url || "#"));
            button.setAttribute("title", title);
            button.setAttribute("aria-label", title);
            button.setAttribute(
                "data-h4bs-template-id",
                String(info.template_id || "")
            );
            button.setAttribute(
                "data-h4bs-template-builder-url",
                String(info.builder_url || "")
            );
            button.setAttribute(
                "data-h4bs-template-wp-url",
                String(info.wp_editor_url || "")
            );
            button.setAttribute(
                "data-h4bs-template-label",
                String(info.label || role)
            );
            if (!button.__h4bsAssignedTemplateBound) {
                button.addEventListener("click", handleAssignedTemplateButtonClick);
                button.__h4bsAssignedTemplateBound = true;
            }
        });
    }

    function handleAssignedTemplateButtonClick(event) {
        if (event) {
            event.preventDefault();
        }
        const button = event && event.currentTarget ? event.currentTarget : null;
        if (!button) {
            return;
        }
        const target = String(
            button.getAttribute("data-h4bs-template-builder-url") ||
                button.getAttribute("href") ||
                ""
        ).trim();
        if (target === "" || target === "#") {
            return;
        }
        const templateLabel = String(
            button.getAttribute("data-h4bs-template-label") || "template"
        ).trim();

        if (state.modalMode && state.modalDirty) {
            updateDirtyText(
                "Save or cancel the element popup before opening the " +
                    templateLabel +
                    " template."
            );
            return;
        }
        if (state.saving) {
            return;
        }
        if (state.dirty) {
            updateDirtyText("Saving page before opening template...");
            saveLayout(false, function () {
                window.location.href = target;
            });
            return;
        }
        window.location.href = target;
    }

    function wireSaveBeforeLeaveLinks() {
        if (!els.saveBeforeLeaveLinks || els.saveBeforeLeaveLinks.length < 1) {
            return;
        }
        els.saveBeforeLeaveLinks.forEach(function (link) {
            if (link.__h4bsSaveLeaveBound) {
                return;
            }
            link.addEventListener("click", handleSaveBeforeLeaveLinkClick);
            link.__h4bsSaveLeaveBound = true;
        });
    }

    function handleSaveBeforeLeaveLinkClick(event) {
        const link = event && event.currentTarget ? event.currentTarget : null;
        if (!link) {
            return;
        }
        if (
            event &&
            (event.metaKey ||
                event.ctrlKey ||
                event.shiftKey ||
                event.altKey ||
                Number(event.button || 0) !== 0)
        ) {
            return;
        }

        const href = String(link.getAttribute("href") || "").trim();
        if (href === "" || href === "#") {
            return;
        }
        if (event) {
            event.preventDefault();
        }

        if (state.modalMode && state.modalDirty) {
            updateDirtyText(
                "Save or cancel the element popup before leaving the builder."
            );
            return;
        }
        if (state.saving) {
            return;
        }
        if (state.dirty) {
            updateDirtyText("Saving page before leaving builder...");
            saveLayout(false, function () {
                window.location.href = href;
            });
            return;
        }
        window.location.href = href;
    }

    function defaultGlobalDesignTokens() {
        return {
            colors: {
                primary: "#0f6cbf",
                primary_hover: "#0b579c",
                on_primary: "#ffffff",
                secondary: "#0a9b7a",
                secondary_hover: "#087f64",
                on_secondary: "#ffffff",
                accent: "#ff7a33",
                heading: "#152238",
                text: "#1f2937",
                muted: "#5f6f82",
                link: "#0f6cbf",
                link_hover: "#0b579c",
                surface: "#ffffff",
                surface_alt: "#f4f7fb",
                border: "#d8e2ec",
                success: "#16855b",
                warning: "#a65f00",
                danger: "#c0362c",
                info: "#2268a7",
            },
            fonts: {
                display: "Poppins",
                heading: "Poppins",
                body: "Inter",
                ui: "Inter",
                base_size: "16",
            },
            typography: {
                h1_size: "56",
                h2_size: "42",
                h3_size: "32",
                h4_size: "25",
                h5_size: "20",
                h6_size: "17",
                heading_weight: "700",
                body_weight: "400",
                heading_line_height: "1.12",
                body_line_height: "1.65",
            },
            spacing: {
                page_gap: "16",
                section_x: "24",
                section_y: "64",
                card_gap: "20",
            },
            shape: {
                radius_sm: "4",
                radius_md: "8",
                radius_lg: "16",
                shadow_sm: "0 2px 8px rgba(21,34,56,.08)",
                shadow_md: "0 16px 40px rgba(21,34,56,.14)",
            },
            components: {
                button_padding_x: "20",
                button_padding_y: "12",
                button_radius: "8",
                button_weight: "700",
                card_padding: "28",
                field_height: "46",
                field_padding_x: "14",
                field_radius: "6",
            },
            layout: {
                container_max_width: "1200",
                container_max_width_unit: "px",
                structure_columns: "2",
                structure_gap: "18",
                structure_min_height: "140",
                structure_layout_mode: "grid",
                structure_content_width_mode: "inherit",
                structure_flex_direction: "row",
                structure_flex_wrap: "wrap",
                structure_justify_content: "flex-start",
                structure_align_items: "stretch",
                structure_align_content: "stretch",
            },
        };
    }

    function normalizeGlobalDesignTokens(raw) {
        const fallback = defaultGlobalDesignTokens();
        const source = raw && typeof raw === "object" ? raw : {};
        const sourceColors =
            source.colors && typeof source.colors === "object"
                ? source.colors
                : {};
        const sourceFonts =
            source.fonts && typeof source.fonts === "object" ? source.fonts : {};
        const sourceTypography =
            source.typography && typeof source.typography === "object"
                ? source.typography
                : {};
        const sourceSpacing =
            source.spacing && typeof source.spacing === "object"
                ? source.spacing
                : {};
        const sourceShape =
            source.shape && typeof source.shape === "object" ? source.shape : {};
        const sourceComponents =
            source.components && typeof source.components === "object"
                ? source.components
                : {};
        const sourceLayout =
            source.layout && typeof source.layout === "object"
                ? source.layout
                : {};
        const colors = {};
        Object.keys(fallback.colors).forEach(function (key) {
            const incoming = String(
                Object.prototype.hasOwnProperty.call(sourceColors, key)
                    ? sourceColors[key]
                    : fallback.colors[key]
            ).trim();
            colors[key] =
                /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(incoming)
                    ? incoming
                    : String(fallback.colors[key]);
        });
        const fonts = {};
        Object.keys(fallback.fonts).forEach(function (key) {
            const incoming = String(
                Object.prototype.hasOwnProperty.call(sourceFonts, key)
                    ? sourceFonts[key]
                    : fallback.fonts[key]
            ).trim();
            fonts[key] = incoming !== "" ? incoming : String(fallback.fonts[key]);
        });

        function boundedToken(sourceGroup, fallbackGroup, key, minimum, maximum) {
            const candidate = Number(
                String(
                    Object.prototype.hasOwnProperty.call(sourceGroup, key)
                        ? sourceGroup[key]
                        : fallbackGroup[key]
                ).trim()
            );
            const fallbackValue = Number(fallbackGroup[key]);
            const resolved = Number.isFinite(candidate)
                ? Math.max(minimum, Math.min(maximum, candidate))
                : fallbackValue;
            return String(Math.round(resolved * 100) / 100);
        }

        const typography = {};
        ["h1_size", "h2_size", "h3_size", "h4_size", "h5_size", "h6_size"].forEach(
            function (key) {
                typography[key] = boundedToken(
                    sourceTypography,
                    fallback.typography,
                    key,
                    10,
                    160
                );
            }
        );
        ["heading_weight", "body_weight"].forEach(function (key) {
            typography[key] = String(
                Math.round(
                    Number(
                        boundedToken(
                            sourceTypography,
                            fallback.typography,
                            key,
                            100,
                            900
                        )
                    )
                )
            );
        });
        ["heading_line_height", "body_line_height"].forEach(function (key) {
            typography[key] = boundedToken(
                sourceTypography,
                fallback.typography,
                key,
                0.8,
                3
            );
        });

        const spacing = {};
        Object.keys(fallback.spacing).forEach(function (key) {
            spacing[key] = boundedToken(sourceSpacing, fallback.spacing, key, 0, 320);
        });

        const shape = {};
        ["radius_sm", "radius_md", "radius_lg"].forEach(function (key) {
            shape[key] = boundedToken(sourceShape, fallback.shape, key, 0, 100);
        });
        ["shadow_sm", "shadow_md"].forEach(function (key) {
            const incoming = String(
                Object.prototype.hasOwnProperty.call(sourceShape, key)
                    ? sourceShape[key]
                    : fallback.shape[key]
            ).trim();
            shape[key] = incoming !== "" ? incoming : String(fallback.shape[key]);
        });

        const components = {};
        [
            "button_padding_x",
            "button_padding_y",
            "button_radius",
            "card_padding",
            "field_height",
            "field_padding_x",
            "field_radius",
        ].forEach(function (key) {
            components[key] = boundedToken(
                sourceComponents,
                fallback.components,
                key,
                0,
                160
            );
        });
        components.button_weight = String(
            Math.round(
                Number(
                    boundedToken(
                        sourceComponents,
                        fallback.components,
                        "button_weight",
                        100,
                        900
                    )
                )
            )
        );

        const layout = {};
        const fallbackWidth = Number(fallback.layout.container_max_width || "1200");
        const candidateWidth = Number(
            String(
                Object.prototype.hasOwnProperty.call(sourceLayout, "container_max_width")
                    ? sourceLayout.container_max_width
                    : fallback.layout.container_max_width
            ).trim()
        );
        const resolvedWidth = Number.isFinite(candidateWidth)
            ? Math.max(320, Math.min(7680, candidateWidth))
            : fallbackWidth;
        layout.container_max_width = String(resolvedWidth);
        const rawUnit = String(
            Object.prototype.hasOwnProperty.call(
                sourceLayout,
                "container_max_width_unit"
            )
                ? sourceLayout.container_max_width_unit
                : fallback.layout.container_max_width_unit
        ).trim();
        const safeUnit = cssSafeUnit(rawUnit, "px");
        layout.container_max_width_unit = ["px", "%", "vw", "vh", "rem", "em"].includes(
            safeUnit
        )
            ? safeUnit
            : "px";

        const structureColumnsCandidate = Number(
            String(
                Object.prototype.hasOwnProperty.call(sourceLayout, "structure_columns")
                    ? sourceLayout.structure_columns
                    : fallback.layout.structure_columns
            ).trim()
        );
        const structureColumns = Number.isFinite(structureColumnsCandidate)
            ? Math.max(1, Math.min(MAX_COLUMNS, Math.round(structureColumnsCandidate)))
            : Number(fallback.layout.structure_columns || 2);
        layout.structure_columns = String(structureColumns);

        const structureGapCandidate = Number(
            String(
                Object.prototype.hasOwnProperty.call(sourceLayout, "structure_gap")
                    ? sourceLayout.structure_gap
                    : fallback.layout.structure_gap
            ).trim()
        );
        const structureGap = Number.isFinite(structureGapCandidate)
            ? Math.max(0, Math.min(160, Math.round(structureGapCandidate)))
            : Number(fallback.layout.structure_gap || 18);
        layout.structure_gap = String(structureGap);

        const structureMinHeightCandidate = Number(
            String(
                Object.prototype.hasOwnProperty.call(sourceLayout, "structure_min_height")
                    ? sourceLayout.structure_min_height
                    : fallback.layout.structure_min_height
            ).trim()
        );
        const structureMinHeight = Number.isFinite(structureMinHeightCandidate)
            ? Math.max(40, Math.min(2400, Math.round(structureMinHeightCandidate)))
            : Number(fallback.layout.structure_min_height || 140);
        layout.structure_min_height = String(structureMinHeight);

        layout.structure_layout_mode = safeSelectToken(
            sourceLayout.structure_layout_mode || fallback.layout.structure_layout_mode,
            ["grid", "flex"],
            "grid"
        );
        layout.structure_content_width_mode = safeSelectToken(
            sourceLayout.structure_content_width_mode || fallback.layout.structure_content_width_mode,
            ["inherit", "custom", "full"],
            "inherit"
        );
        layout.structure_flex_direction = safeSelectToken(
            sourceLayout.structure_flex_direction || fallback.layout.structure_flex_direction,
            ["row", "row-reverse", "column", "column-reverse"],
            "row"
        );
        layout.structure_flex_wrap = safeSelectToken(
            sourceLayout.structure_flex_wrap || fallback.layout.structure_flex_wrap,
            ["nowrap", "wrap", "wrap-reverse"],
            "wrap"
        );
        layout.structure_justify_content = safeSelectToken(
            sourceLayout.structure_justify_content || fallback.layout.structure_justify_content,
            [
                "flex-start",
                "center",
                "flex-end",
                "space-between",
                "space-around",
                "space-evenly",
            ],
            "flex-start"
        );
        layout.structure_align_items = safeSelectToken(
            sourceLayout.structure_align_items || fallback.layout.structure_align_items,
            ["stretch", "flex-start", "center", "flex-end", "baseline"],
            "stretch"
        );
        layout.structure_align_content = safeSelectToken(
            sourceLayout.structure_align_content || fallback.layout.structure_align_content,
            [
                "stretch",
                "flex-start",
                "center",
                "flex-end",
                "space-between",
                "space-around",
                "space-evenly",
            ],
            "stretch"
        );

        return {
            colors: colors,
            fonts: fonts,
            typography: typography,
            spacing: spacing,
            shape: shape,
            components: components,
            layout: layout,
        };
    }

    function structureLayoutDefaults() {
        const fallback =
            defaultGlobalDesignTokens().layout &&
            typeof defaultGlobalDesignTokens().layout === "object"
                ? defaultGlobalDesignTokens().layout
                : {};
        const tokens =
            state.globalDesignTokens && typeof state.globalDesignTokens === "object"
                ? state.globalDesignTokens
                : {};
        const layout =
            tokens.layout && typeof tokens.layout === "object" ? tokens.layout : {};

        const columnsCandidate = Number(
            String(layout.structure_columns || fallback.structure_columns || "2").trim()
        );
        const gapCandidate = Number(
            String(layout.structure_gap || fallback.structure_gap || "18").trim()
        );
        const minHeightCandidate = Number(
            String(
                layout.structure_min_height || fallback.structure_min_height || "140"
            ).trim()
        );

        return {
            columns: Number.isFinite(columnsCandidate)
                ? Math.max(1, Math.min(MAX_COLUMNS, Math.round(columnsCandidate)))
                : 2,
            gap: Number.isFinite(gapCandidate)
                ? Math.max(0, Math.min(160, Math.round(gapCandidate)))
                : 18,
            min_height: Number.isFinite(minHeightCandidate)
                ? Math.max(40, Math.min(2400, Math.round(minHeightCandidate)))
                : 140,
            layout_mode: safeSelectToken(
                layout.structure_layout_mode || fallback.structure_layout_mode || "grid",
                ["grid", "flex"],
                "grid"
            ),
            content_width_mode: safeSelectToken(
                layout.structure_content_width_mode ||
                    fallback.structure_content_width_mode ||
                    "inherit",
                ["inherit", "custom", "full"],
                "inherit"
            ),
            flex_direction: safeSelectToken(
                layout.structure_flex_direction ||
                    fallback.structure_flex_direction ||
                    "row",
                ["row", "row-reverse", "column", "column-reverse"],
                "row"
            ),
            flex_wrap: safeSelectToken(
                layout.structure_flex_wrap || fallback.structure_flex_wrap || "wrap",
                ["nowrap", "wrap", "wrap-reverse"],
                "wrap"
            ),
            justify_content: safeSelectToken(
                layout.structure_justify_content ||
                    fallback.structure_justify_content ||
                    "flex-start",
                [
                    "flex-start",
                    "center",
                    "flex-end",
                    "space-between",
                    "space-around",
                    "space-evenly",
                ],
                "flex-start"
            ),
            align_items: safeSelectToken(
                layout.structure_align_items ||
                    fallback.structure_align_items ||
                    "stretch",
                ["stretch", "flex-start", "center", "flex-end", "baseline"],
                "stretch"
            ),
            align_content: safeSelectToken(
                layout.structure_align_content ||
                    fallback.structure_align_content ||
                    "stretch",
                [
                    "stretch",
                    "flex-start",
                    "center",
                    "flex-end",
                    "space-between",
                    "space-around",
                    "space-evenly",
                ],
                "stretch"
            ),
        };
    }

    function normalizePageLayout(raw) {
        const layout = String(raw || "default");
        const allowed = Object.keys(pageLayoutOptions());
        if (allowed.indexOf(layout) < 0) {
            return "default";
        }
        return layout;
    }

    function normalizePageTitleMode(raw) {
        const mode = String(raw || "auto");
        return ["auto", "show", "hide"].indexOf(mode) >= 0 ? mode : "auto";
    }

    function pageTitleModeOptions() {
        const source =
            data.pageTitleModeOptions && typeof data.pageTitleModeOptions === "object"
                ? data.pageTitleModeOptions
                : null;
        return source || {
            auto: "Automatic (recommended)",
            show: "Show the page title",
            hide: "Hide the page title",
        };
    }

    function initialViewportSlug() {
        const width = Math.max(320, Number(window.innerWidth || 1440));
        if (width <= 600) {
            return "iphone_14";
        }
        if (width <= 1024) {
            return "tablet_768";
        }
        if (width <= 1500) {
            return "macbook_air_13";
        }
        return String(data.defaultViewport || "fhd_1080p");
    }

    function pageLayoutOptions() {
        const source =
            data.pageLayoutOptions && typeof data.pageLayoutOptions === "object"
                ? data.pageLayoutOptions
                : null;
        if (!source) {
            return {
                default: "Theme Default",
                full_width: "Help4 Full Width",
                canvas: "Help4 Canvas (No Header/Footer)",
            };
        }
        return source;
    }

    function makeId(type, index) {
        state.idSeed += 1;
        const nonce = Math.floor(Math.random() * 1679616)
            .toString(36)
            .padStart(4, "0");
        return (
            "block_" +
            type +
            "_" +
            Date.now().toString(36) +
            "_" + state.idSeed.toString(36) +
            "_" + nonce +
            "_" + String(index)
        );
    }

    function allowedBlockTypes() {
        return [
            "section",
            "heading",
            "text",
            "image",
            "button",
            "shortcode",
            "product_reviews",
            "commerce_indicator",
            "google_business",
            "slider",
            "html",
            "spacer",
            "divider",
            "video",
            "icon",
            "list",
            "quote",
            "cta",
            "gallery",
            "map",
            "faq",
            "collection",
            "calendar",
            "staff_directory",
            "counter",
            "progress",
            "menu",
            "container",
            "inner_section",
        ];
    }

    function normalizeBlockType(rawType, fallback) {
        const allowed = allowedBlockTypes();
        let type = String(rawType || "")
            .trim()
            .toLowerCase();

        if (/^[a-z0-9][a-z0-9_-]{1,63}(?::|\/)[a-z0-9][a-z0-9_.-]{0,95}$/.test(type)) {
            return type.replace("/", ":");
        }
        if (type !== "") {
            type = type.replace(/^drop[\s:_-]*/i, "");
            type = type.replace(/[.\s-]+/g, "_");
        }

        const aliases = {
            paragraph: "text",
            text_editor: "text",
            editor_text: "text",
            raw_text: "text",
            row: "section",
            section_container: "section",
            innersection: "inner_section",
            inner_row: "inner_section",
            inner_column: "inner_section",
            column: "inner_section",
            columns: "inner_section",
            code: "html",
            html_block: "html",
            custom_html: "html",
            raw_html: "html",
            heading_text: "heading",
            cta_box: "cta",
        };

        if (type !== "" && Object.prototype.hasOwnProperty.call(aliases, type)) {
            type = String(aliases[type] || "");
        }

        if (type !== "" && allowed.indexOf(type) >= 0) {
            return type;
        }

        const fallbackType = String(fallback || "")
            .trim()
            .toLowerCase();
        if (fallbackType !== "" && allowed.indexOf(fallbackType) >= 0) {
            return fallbackType;
        }

        return "";
    }

    function isContainerType(type) {
        const slug = String(type || "");
        return (
            slug === "section" ||
            slug === "container" ||
            slug === "inner_section"
        );
    }

    function defaultBlock(type) {
        const structureDefaults = structureLayoutDefaults();
        const map = {
            section: {
                columns: structureDefaults.columns,
                gap: structureDefaults.gap,
                min_height: structureDefaults.min_height,
                column_labels: "Column 1|Column 2",
                column_widths: "",
                layout_mode: structureDefaults.layout_mode,
                content_width_mode: structureDefaults.content_width_mode,
                content_width: "",
                content_width_unit: "px",
                flex_direction: structureDefaults.flex_direction,
                flex_wrap: structureDefaults.flex_wrap,
                justify_content: structureDefaults.justify_content,
                align_items: structureDefaults.align_items,
                align_content: structureDefaults.align_content,
            },
            heading: { text: "New Heading", tag: "h2" },
            text: { text: "New paragraph text." },
            image: { src: "", attachment_id: 0, intrinsic_width: "", intrinsic_height: "", alt: "", title: "", caption: "", size: "full", align: "none", loading: "auto", lightbox: "0" },
            button: { label: "Click Here", url: "#", target: "same", rel: "" },
            shortcode: { shortcode: '[h4_products limit="6"]' },
            product_reviews: {
                product_id: "0",
                limit: "5",
                show_form: "1",
                show_summary: "1",
                title: "",
                empty_text: "",
            },
            commerce_indicator: {
                source: "cart",
                label: "Cart",
                url: "/cart/",
                icon_class: "fa-solid fa-cart-shopping",
                show_when_zero: "0",
                show_quantity: "1",
                show_label: "0",
                max_count: "99",
                preview_count: "0",
                storage_key: "h4bsCommerceCart",
                unit_singular: "item",
                unit_plural: "items",
            },
            google_business: {
                domain: "",
                view: "business",
                reviews: "5",
                location: "1",
                height: "360",
                show_map: "1",
                show_reviews: "1",
                show_header: "1",
                show_aggregate: "1",
                show_service_areas: "1",
                empty_text: "",
            },
            slider: {
                slider_id: 0,
                source: "manual",
                post_type: "post",
                limit: 8,
                taxonomy: "",
                terms: "",
                orderby: "date",
                order: "DESC",
                fit: "contain",
                snapshot_fit: "contain",
                bg: "#0b1118",
                height_mode: "fixed",
                height_px: 540,
                height_tablet: 480,
                height_mobile: 420,
                transition: "slide",
                transition_duration: 600,
                easing: "ease",
                motion: "none",
                motion_duration: 9000,
                motion_force: "0",
                autoplay: 4500,
                start_index: 0,
                loop: "1",
                shuffle: "0",
                arrows: "1",
                dots: "1",
                thumbnails: "0",
                progress: "1",
                pause_button: "1",
                pause_on_hover: "1",
                pause_out_of_view: "1",
                keyboard: "1",
                swipe: "1",
            },
            html: {
                html: "<div>Custom HTML</div>",
                design_background_color: "",
                design_padding_top: "",
                design_padding_right: "",
                design_padding_bottom: "",
                design_padding_left: "",
                design_padding_unit: "px",
            },
            spacer: { height: 28 },
            divider: { thickness: 1, color: "#dbe7f3", style: "solid" },
            video: {
                src: "",
                media_src: "",
                provider: "youtube",
                hls_src: "",
                fallback_src: "",
                fallback_media_src: "",
                poster_src: "",
                poster_media_src: "",
                fallback_image_src: "",
                fallback_image_media_src: "",
                title: "Video player",
                aspect_ratio: "16:9",
                preload: "metadata",
                autoplay: "0",
                controls: "1",
                muted: "0",
                loop: "0",
                height: 360,
            },
            icon: {
                icon_set: "dashicons",
                icon: "dashicons-star-filled",
                fa_class: "fa-solid fa-star",
                color: "#0f6cbf",
                size: 28,
                label: "",
            },
            list: {
                items: "Item one\nItem two\nItem three",
                ordered: "0",
            },
            quote: {
                text: "Add a customer quote here.",
                cite: "Customer Name",
            },
            cta: {
                title: "Ready to get started?",
                heading_tag: "h2",
                text: "Add a strong call-to-action message.",
                button_label: "Contact Us",
                button_url: "#",
                button_target: "same",
                button_rel: "",
            },
            gallery: {
                images: "",
                columns: 3,
            },
            map: {
                embed_url: "",
                height: 360,
            },
            faq: {
                items: "What do we offer?::Premium websites and support.\nHow fast can we launch?::Typical launches in days, not weeks.",
                open_first: "0",
            },
            collection: {
                fields: [
                    { key: "title", label: "Title" }, { key: "description", label: "Description" },
                    { key: "group", label: "Group" }, { key: "type", label: "Type" },
                    { key: "badge", label: "Badge" }, { key: "url", label: "Link URL" },
                ],
                items: [
                    { id: "item-1", title: "Monday Program", description: "Add program details.", group: "Monday", type: "Class", badge: "Open", url: "#" },
                    { id: "item-2", title: "Tuesday Program", description: "Add program details.", group: "Tuesday", type: "Workshop", badge: "New", url: "#" },
                ],
                filters: [{ key: "group", label: "Day" }, { key: "type", label: "Type" }],
                default_view: "grid",
                search_label: "Search programs",
                grid_label: "Grid by group",
                list_label: "Filterable list",
                empty_text: "No items match your filters.",
                columns: 3,
                columns_tablet: 2,
                columns_mobile: 1,
            },
            calendar: {
                source_ids: "",
                presentation: "calendar",
                show_search: "1",
                show_filters: "1",
                empty_text: "No events match your filters.",
                columns: 3,
                columns_tablet: 2,
                columns_mobile: 1,
            },
            staff_directory: {
                show_search: "1",
                show_tier_headings: "1",
                empty_text: "No staff profiles match this view.",
                columns: 3,
                columns_tablet: 2,
                columns_mobile: 1,
            },
            counter: {
                value: 100,
                prefix: "",
                suffix: "+",
                label: "Projects delivered",
            },
            progress: {
                label: "Campaign Progress",
                value: 65,
                max: 100,
            },
            menu: {
                menu_slug: "",
                orientation: "horizontal",
                dropdown_mode: "hover",
                depth: "0",
                mobile_hamburger: "1",
                menu_label: "Site Menu",
            },
            container: {
                columns: structureDefaults.columns,
                gap: structureDefaults.gap,
                min_height: structureDefaults.min_height,
                column_labels: "Column 1|Column 2",
                column_widths: "",
                layout_mode: structureDefaults.layout_mode,
                content_width_mode: structureDefaults.content_width_mode,
                content_width: "",
                content_width_unit: "px",
                flex_direction: structureDefaults.flex_direction,
                flex_wrap: structureDefaults.flex_wrap,
                justify_content: structureDefaults.justify_content,
                align_items: structureDefaults.align_items,
                align_content: structureDefaults.align_content,
                note: "Container wrapper section",
            },
            inner_section: {
                columns: structureDefaults.columns,
                gap: structureDefaults.gap,
                min_height: structureDefaults.min_height,
                column_labels: "Column 1|Column 2",
                column_widths: "",
                layout_mode: structureDefaults.layout_mode,
                content_width_mode: structureDefaults.content_width_mode,
                content_width: "",
                content_width_unit: "px",
                flex_direction: structureDefaults.flex_direction,
                flex_wrap: structureDefaults.flex_wrap,
                justify_content: structureDefaults.justify_content,
                align_items: structureDefaults.align_items,
                align_content: structureDefaults.align_content,
            },
        };
        const commonAdvancedSettings = {
            advanced_admin_label: "",
            advanced_css_classes: "",
            advanced_anchor_id: "",
            advanced_html_title: "",
            advanced_aria_label: "",
            advanced_role: "",
            advanced_tabindex: "",
            advanced_aria_hidden: "0",
            advanced_data_attributes: "",
        };
        return {
            schema_version: "1.0",
            id: makeId(type, state.layout.length + 1),
            type: type,
            settings: { ...commonAdvancedSettings, ...(map[type] || {}) },
            visibility: {
                scope: "all",
                include_ids: "",
                exclude_ids: "",
                user_roles: "",
                viewport: "all",
            },
            parent_id: "",
            slot: 0,
            extensions: {},
        };
    }

    function normalizeBlockForModal(block) {
        const source = block && typeof block === "object" ? block : {};
        const type = normalizeBlockType(source.type || "text", "text") || "text";
        const fallback = defaultBlock(type);
        const sourceSettings =
            source.settings && typeof source.settings === "object"
                ? source.settings
                : {};
        const sourceVisibility =
            source.visibility && typeof source.visibility === "object"
                ? source.visibility
                : {};
        const normalizedSettings = { ...fallback.settings, ...sourceSettings };
        if (type === "cta" && !Object.prototype.hasOwnProperty.call(sourceSettings, "heading_tag")) {
            normalizedSettings.heading_tag = "h3";
        }
        if (["list", "faq"].indexOf(type) >= 0 && typeof normalizedSettings.items === "string") {
            normalizedSettings.items = normalizeMultilineDelimiters(normalizedSettings.items);
        }
        if (
            type === "image" &&
            String(normalizedSettings.src || "").trim() === "" &&
            String(sourceSettings.url || "").trim() !== ""
        ) {
            normalizedSettings.src = String(sourceSettings.url);
        }

        return {
            schema_version: String(source.schema_version || fallback.schema_version || "1.0"),
            id: String(source.id || fallback.id || makeId(type, state.layout.length + 1)),
            type: type,
            settings: normalizedSettings,
            visibility: {
                scope: String(sourceVisibility.scope || "all"),
                include_ids: String(sourceVisibility.include_ids || ""),
                exclude_ids: String(sourceVisibility.exclude_ids || ""),
                user_roles: String(sourceVisibility.user_roles || ""),
                viewport: String(sourceVisibility.viewport || "all"),
            },
            parent_id: String(source.parent_id || ""),
            slot: Math.max(0, Number(source.slot || 0) || 0),
            extensions:
                source.extensions && typeof source.extensions === "object"
                    ? deepClone(source.extensions)
                    : deepClone(fallback.extensions || {}),
        };
    }

    function templateBySlug(slug) {
        const needle = String(slug || "");
        if (needle === "") {
            return null;
        }
        const templates = Array.isArray(data.templatePresets)
            ? data.templatePresets
            : [];
        return (
            templates.find(function (template) {
                return String(template.slug || "") === needle;
            }) || null
        );
    }

    function clampInsertIndex(index) {
        const raw = Number(index);
        if (!Number.isFinite(raw)) {
            return state.layout.length;
        }
        return Math.max(0, Math.min(state.layout.length, Math.round(raw)));
    }

    function normalizedSlot(value) {
        return Math.max(0, Math.min(MAX_SLOT, Number(value || 0) || 0));
    }

    function insertIndexForPlacement(parentId, slot, requestedIndex) {
        const parent = String(parentId || "");
        if (parent === "") {
            return clampInsertIndex(requestedIndex);
        }

        const targetSlot = normalizedSlot(slot);
        const siblingIndexes = [];
        state.layout.forEach(function (item, idx) {
            if (
                String(item && item.parent_id ? item.parent_id : "") === parent &&
                normalizedSlot(item && item.slot ? item.slot : 0) === targetSlot
            ) {
                siblingIndexes.push(idx);
            }
        });

        if (siblingIndexes.length > 0) {
            const desired = Number.isFinite(Number(requestedIndex))
                ? Math.max(
                      0,
                      Math.min(siblingIndexes.length, Math.round(Number(requestedIndex)))
                  )
                : siblingIndexes.length;
            if (desired >= siblingIndexes.length) {
                return siblingIndexes[siblingIndexes.length - 1] + 1;
            }
            return siblingIndexes[desired];
        }

        let insertAt = state.layout.length;
        const parentIndex = state.layout.findIndex(function (item) {
            return String(item && item.id ? item.id : "") === parent;
        });
        if (parentIndex >= 0) {
            insertAt = parentIndex + 1;
        }
        state.layout.forEach(function (item, idx) {
            if (idx < insertAt) {
                return;
            }
            if (String(item && item.parent_id ? item.parent_id : "") !== parent) {
                return;
            }
            if (normalizedSlot(item && item.slot ? item.slot : 0) <= targetSlot) {
                insertAt = idx + 1;
            }
        });
        return insertAt;
    }

    function insertSingleBlock(block, index, openSettings, placement) {
        if (!block || typeof block !== "object") {
            return null;
        }
        captureHistoryBeforeMutation();
        const parentId =
            placement && typeof placement === "object"
                ? String(placement.parent_id || "")
                : "";
        const slot =
            placement && typeof placement === "object"
                ? normalizedSlot(placement.slot || 0)
                : 0;
        block.parent_id = parentId;
        block.slot = slot;
        const insertAt = insertIndexForPlacement(parentId, slot, index);
        state.layout.splice(insertAt, 0, block);
        state.selectedId = String(block.id || "");
        setDirty(true);
        renderAll();
        if (openSettings !== false) {
            openBlockModal(String(block.id || ""));
        }
        return block;
    }

    function insertElementAt(type, index, openSettings, placement) {
        const blockType = normalizeBlockType(type || "", "");
        if (blockType === "") {
            return null;
        }
        if (
            placement &&
            typeof placement === "object" &&
            String(placement.parent_id || "") !== "" &&
            blockType === "section"
        ) {
            return null;
        }
        const block = defaultBlock(blockType);
        return insertSingleBlock(block, index, openSettings, placement);
    }

    function widgetStorageKey(widget) {
        if (!widget || typeof widget !== "object") {
            return "";
        }
        const shortcode = String(widget.shortcode || "").trim();
        if (shortcode !== "") {
            return shortcode;
        }
        const blockType = normalizeBlockType(
            widget.block_type || widget.blockType || "",
            ""
        );
        if (blockType === "") {
            return "";
        }
        const slug = String(widget.slug || "").trim();
        if (slug !== "") {
            return "block:" + blockType + ":" + slug;
        }
        return "block:" + blockType;
    }

    function insertWidgetAt(widget, index, openSettings, placement) {
        const item = widget && typeof widget === "object" ? widget : {};
        const blockType = normalizeBlockType(
            item.block_type || item.blockType || "",
            ""
        );
        if (blockType !== "") {
            const block = defaultBlock(blockType);
            const overrides =
                item.settings && typeof item.settings === "object"
                    ? deepClone(item.settings)
                    : {};
            block.settings = { ...block.settings, ...overrides };
            block.settings.widget_slug = String(item.slug || "").trim();
            block.settings.widget_label = String(item.label || "").trim();
            block.settings.widget_category = String(item.category || "").trim();
            recordWidgetRecent(widgetStorageKey(item));
            return insertSingleBlock(block, index, openSettings, placement);
        }
        const shortcode = String(item.shortcode || "");
        if (shortcode === "") {
            return null;
        }
        recordWidgetRecent(widgetStorageKey(item));
        const block = defaultBlock("shortcode");
        block.settings.shortcode = shortcode;
        block.settings.widget_slug = String(item.slug || "").trim();
        block.settings.widget_label = String(item.label || "").trim();
        block.settings.widget_category = String(item.category || "").trim();
        return insertSingleBlock(block, index, openSettings, placement);
    }

    function libraryInsertTarget() {
        const pending =
            state.pendingInsertTarget &&
            typeof state.pendingInsertTarget === "object"
                ? state.pendingInsertTarget
                : null;
        if (pending) {
            return {
                index: Number.isFinite(Number(pending.index))
                    ? Number(pending.index)
                    : state.layout.length,
                placement: {
                    parent_id: String(pending.parent_id || ""),
                    slot: normalizedSlot(pending.slot || 0),
                },
            };
        }
        return {
            index: state.layout.length,
            placement: { parent_id: "", slot: 0 },
        };
    }

    function insertElementFromLibrary(type) {
        const target = libraryInsertTarget();
        const inserted = insertElementAt(
            type,
            target.index,
            true,
            target.placement
        );
        if (!inserted || !inserted.id) {
            updateSelectionStatus(
                "That element cannot be placed there. Choose a content element or another location."
            );
            return null;
        }
        clearPendingInsertTarget();
        scheduleDropModalOpen(String(inserted.id), 0);
        updateSelectionStatus("Element added. Edit its content, then save the element.");
        return inserted;
    }

    function insertWidgetFromLibrary(widget) {
        const target = libraryInsertTarget();
        const inserted = insertWidgetAt(
            widget,
            target.index,
            true,
            target.placement
        );
        if (!inserted || !inserted.id) {
            updateSelectionStatus("That widget could not be added at this location.");
            return null;
        }
        clearPendingInsertTarget();
        scheduleDropModalOpen(String(inserted.id), 0);
        updateSelectionStatus("Widget added. Review its settings, then save the element.");
        return inserted;
    }

    function insertTemplateAt(template, index, placement) {
        if (!template || typeof template !== "object") {
            return [];
        }
        if (
            placement &&
            typeof placement === "object" &&
            String(placement.parent_id || "") !== ""
        ) {
            return [];
        }
        const blocks = cloneLayoutWithFreshIds(template.layout || [], index);
        if (!Array.isArray(blocks) || !blocks.length) {
            return [];
        }
        captureHistoryBeforeMutation();
        const insertAt = clampInsertIndex(index);
        state.layout.splice.apply(state.layout, [insertAt, 0].concat(blocks));
        state.selectedId = String(blocks[0].id || "");
        setDirty(true);
        renderAll();
        return blocks;
    }

    function replaceLayoutWithTemplate(template) {
        if (!template || typeof template !== "object") {
            return [];
        }
        const nextBlocks = cloneLayoutWithFreshIds(template.layout || [], 0);
        if (!Array.isArray(nextBlocks) || !nextBlocks.length) {
            return [];
        }
        const proceed = state.isFreshPage || window.confirm(
            "Replace this page layout with the selected template?"
        );
        if (!proceed) {
            return [];
        }
        captureHistoryBeforeMutation();
        state.layout = nextBlocks;
        if (String(template.page_layout || "").trim() !== "") {
            state.pageLayout = normalizePageLayout(template.page_layout);
        }
        state.selectedId = String(nextBlocks[0].id || "");
        setDirty(true);
        renderAll();
        return nextBlocks;
    }

    function cloneLayoutWithFreshIds(layoutSource, seedIndex) {
        const layout = normalizeLayout(layoutSource || []);
        if (!layout.length) {
            return [];
        }
        const idMap = {};
        const seed = Math.max(0, Number(seedIndex || 0) || 0);
        const clones = layout.map(function (block, offset) {
            const copy = deepClone(block || {});
            const originalId = String(copy.id || "");
            const newId = makeId(String(copy.type || "text"), seed + offset + 1);
            if (originalId !== "") {
                idMap[originalId] = newId;
            }
            copy.id = newId;
            copy.parent_id = String(copy.parent_id || "");
            copy.slot = normalizedSlot(copy.slot || 0);
            return copy;
        });

        clones.forEach(function (block) {
            const parent = String(block.parent_id || "");
            if (parent === "") {
                block.parent_id = "";
                return;
            }
            block.parent_id = Object.prototype.hasOwnProperty.call(idMap, parent)
                ? String(idMap[parent] || "")
                : "";
        });

        return clones;
    }

    function applyThemePack(pack, mode) {
        if (!pack || typeof pack !== "object") {
            return;
        }
        const applyMode = String(mode || "style").toLowerCase();
        const templateSlug = String(pack.template_slug || "").trim();
        if (
            applyMode !== "style" &&
            templateSlug !== "" &&
            !catalogIsLoaded("templates")
        ) {
            updateDirtyText("Loading the starter template...");
            ensureLibraryCatalog("templates", false)
                .done(function () {
                    applyThemePack(pack, mode);
                })
                .fail(function () {
                    updateDirtyText("The starter template could not be loaded.");
                });
            return;
        }
        const template = templateSlug !== "" ? templateBySlug(templateSlug) : null;
        const pageLayout = normalizePageLayout(String(pack.page_layout || state.pageLayout));
        const tokens = mergeGlobalDesignTokenPatch(
            state.globalDesignTokens || {},
            pack.tokens || {}
        );

        let replaceLayout = false;
        let insertStarter = false;
        if (applyMode === "replace") {
            replaceLayout = !!template;
            insertStarter = !!template;
        } else if (applyMode === "append") {
            insertStarter = !!template;
        }

        const label = String(pack.label || "Theme Pack");
        const shouldProceed =
            !insertStarter ||
            window.confirm(
                replaceLayout
                    ? "Apply " +
                          label +
                          " and replace this page layout with its starter structure?"
                    : "Apply " +
                          label +
                          " and append its starter structure to this page?"
            );
        if (!shouldProceed) {
            return;
        }

        captureHistoryBeforeMutation();
        state.globalDesignTokens = tokens;
        state.globalDesignDirty = true;
        if (insertStarter) {
            state.pageLayout = pageLayout;
        }
        state.activeThemePack = String(pack && pack.slug ? pack.slug : "").trim();

        let inserted = [];
        if (insertStarter && template) {
            const seed = replaceLayout ? 0 : state.layout.length;
            const cloned = cloneLayoutWithFreshIds(template.layout || [], seed);
            if (replaceLayout) {
                state.layout = cloned;
            } else if (cloned.length) {
                state.layout = state.layout.concat(cloned);
            }
            inserted = cloned;
        }

        if (inserted.length && inserted[0] && inserted[0].id) {
            state.selectedId = String(inserted[0].id || "");
        } else if (!findBlockById(state.selectedId)) {
            state.selectedId =
                state.layout.length > 0 ? String(state.layout[0].id || "") : null;
        }

        setDirty(true);
        renderAll();
        renderThemePackCards();

        if (inserted.length && inserted[0] && inserted[0].id) {
            scheduleDropModalOpen(String(inserted[0].id), 0);
        }

        if (insertStarter) {
            updateDirtyText(label + " applied with starter layout.");
            return;
        }
        updateDirtyText(label + " style tokens applied.");
    }

    function elementIcon(slug) {
        const map = {
            section: "dashicons-align-wide",
            heading: "dashicons-heading",
            text: "dashicons-editor-paragraph",
            image: "dashicons-format-image",
            button: "dashicons-button",
            shortcode: "dashicons-editor-code",
            product_reviews: "dashicons-star-filled",
            google_business: "dashicons-location-alt",
            slider: "dashicons-images-alt2",
            html: "dashicons-editor-code",
            spacer: "dashicons-minus",
            divider: "dashicons-editor-insertmore",
            video: "dashicons-format-video",
            icon: "dashicons-star-filled",
            list: "dashicons-editor-ul",
            quote: "dashicons-format-quote",
            cta: "dashicons-megaphone",
            gallery: "dashicons-format-gallery",
            map: "dashicons-location-alt",
            faq: "dashicons-editor-help",
            collection: "dashicons-filter",
            calendar: "dashicons-calendar-alt",
            staff_directory: "dashicons-groups",
            counter: "dashicons-chart-bar",
            progress: "dashicons-chart-line",
            menu: "dashicons-menu",
            container: "dashicons-screenoptions",
            inner_section: "dashicons-columns",
        };
        return map[String(slug || "")] || "dashicons-screenoptions";
    }

    function normalizeElementFilter(value) {
        const key = String(value || "")
            .trim()
            .toLowerCase();
        return ["all", "layout", "content", "media", "advanced"].indexOf(key) >= 0
            ? key
            : "all";
    }

    function elementFilterCatalog() {
        return [
            { key: "all", label: "All" },
            { key: "layout", label: "Layout" },
            { key: "content", label: "Content" },
            { key: "media", label: "Media" },
            { key: "advanced", label: "Advanced" },
        ];
    }

    function elementCategoryForSlug(slug) {
        const key = String(slug || "")
            .trim()
            .toLowerCase();
        if (
            ["section", "container", "inner_section", "spacer", "divider"].indexOf(
                key
            ) >= 0
        ) {
            return "layout";
        }
        if (
            [
                "heading",
                "text",
                "button",
                "product_reviews",
                "list",
                "quote",
                "cta",
                "faq",
                "collection",
                "calendar",
                "staff_directory",
                "counter",
                "progress",
                "menu",
            ].indexOf(key) >= 0
        ) {
            return "content";
        }
        if (
            ["image", "gallery", "video", "slider", "icon", "map", "google_business"].indexOf(key) >= 0
        ) {
            return "media";
        }
        return "advanced";
    }

    function elementCategoryLabel(key) {
        const labels = {
            all: "All",
            layout: "Layout",
            content: "Content",
            media: "Media",
            advanced: "Advanced",
        };
        return labels[String(key || "all")] || "All";
    }

    function widgetIcon(category) {
        const source = String(category || "").toLowerCase();
        if (
            source.indexOf("commerce") >= 0 ||
            source.indexOf("product") >= 0
        ) {
            return "dashicons-cart";
        }
        if (source.indexOf("payment") >= 0) {
            return "dashicons-money-alt";
        }
        if (source.indexOf("crm") >= 0 || source.indexOf("booking") >= 0) {
            return "dashicons-calendar-alt";
        }
        if (source.indexOf("seo") >= 0 || source.indexOf("marketing") >= 0) {
            return "dashicons-chart-line";
        }
        if (source.indexOf("security") >= 0) {
            return "dashicons-shield";
        }
        if (source.indexOf("template") >= 0) {
            return "dashicons-layout";
        }
        if (source.indexOf("lms") >= 0) {
            return "dashicons-welcome-learn-more";
        }
        return "dashicons-screenoptions";
    }

    function templateTone(slug) {
        const source = String(slug || "").toLowerCase();
        if (source.indexOf("realtor") >= 0 || source.indexOf("listing") >= 0) {
            return "is-realtor";
        }
        if (source.indexOf("store") >= 0 || source.indexOf("shop") >= 0) {
            return "is-commerce";
        }
        if (source.indexOf("contractor") >= 0 || source.indexOf("service") >= 0) {
            return "is-contractor";
        }
        return "is-general";
    }

    function themePackTone(pack) {
        const source = (
            String(pack && pack.slug ? pack.slug : "") +
            " " +
            String(pack && pack.industry ? pack.industry : "")
        )
            .toLowerCase()
            .trim();
        if (
            source.indexOf("realtor") >= 0 ||
            source.indexOf("idx") >= 0 ||
            source.indexOf("mls") >= 0
        ) {
            return "is-realtor";
        }
        if (
            source.indexOf("commerce") >= 0 ||
            source.indexOf("shop") >= 0 ||
            source.indexOf("store") >= 0
        ) {
            return "is-commerce";
        }
        if (
            source.indexOf("contractor") >= 0 ||
            source.indexOf("trade") >= 0 ||
            source.indexOf("service") >= 0
        ) {
            return "is-contractor";
        }
        return "is-general";
    }

    function createLibraryThumb(iconClass, pillLabel, toneClass) {
        const thumb = document.createElement("div");
        thumb.className = "h4bs-library-thumb";
        if (toneClass) {
            thumb.classList.add(toneClass);
        }

        const icon = document.createElement("span");
        icon.className = "dashicons " + String(iconClass || "dashicons-screenoptions");
        thumb.appendChild(icon);

        const lines = document.createElement("span");
        lines.className = "h4bs-library-thumb-lines";
        const lineA = document.createElement("i");
        const lineB = document.createElement("i");
        lines.appendChild(lineA);
        lines.appendChild(lineB);
        thumb.appendChild(lines);

        if (pillLabel) {
            const pill = document.createElement("span");
            pill.className = "h4bs-library-pill";
            pill.textContent = String(pillLabel);
            thumb.appendChild(pill);
        }

        return thumb;
    }

    function createLibraryBody(title, subtitle) {
        const body = document.createElement("div");
        body.className = "h4bs-library-body";

        const heading = document.createElement("strong");
        heading.textContent = String(title || "Item");
        body.appendChild(heading);

        const text = document.createElement("span");
        text.textContent = String(subtitle || "Drag to canvas");
        body.appendChild(text);

        return body;
    }

    function renderElementButtons() {
        if (!els.elementButtons) {
            return;
        }
        els.elementButtons.innerHTML = "";
        const activeFilter = normalizeElementFilter(state.elementFilter);
        state.elementFilter = activeFilter;

        const filterRow = document.createElement("div");
        filterRow.className = "h4bs-element-filters";
        elementFilterCatalog().forEach(function (filter) {
            const btn = document.createElement("button");
            btn.type = "button";
            btn.className = "button button-small h4bs-element-filter-btn";
            if (String(filter.key) === activeFilter) {
                btn.classList.add("is-active");
            }
            btn.textContent = String(filter.label || filter.key);
            btn.addEventListener("click", function () {
                state.elementFilter = normalizeElementFilter(filter.key);
                persistElementFilter();
                renderElementButtons();
            });
            filterRow.appendChild(btn);
        });
        els.elementButtons.appendChild(filterRow);

        const query = els.elementSearch
            ? String(els.elementSearch.value || "").toLowerCase().trim()
            : "";
        const blockTypes = (Array.isArray(data.blockTypes) ? data.blockTypes : []).filter(function (type) {
            const slug = String(type && type.slug ? type.slug : "").toLowerCase();
            const label = String(type && type.label ? type.label : "").toLowerCase();
            const category = elementCategoryForSlug(slug);
            if (activeFilter !== "all" && category !== activeFilter) {
                return false;
            }
            if (query === "") {
                return true;
            }
            return (
                slug +
                " " +
                label +
                " " +
                String(elementCategoryLabel(category)).toLowerCase()
            ).indexOf(query) >= 0;
        });
        if (!blockTypes.length) {
            const empty = document.createElement("p");
            empty.className = "h4bs-inspector-empty";
            empty.textContent = "No elements match this search.";
            els.elementButtons.appendChild(empty);
            return;
        }

        const grouped = {
            layout: [],
            content: [],
            media: [],
            advanced: [],
        };
        blockTypes.forEach(function (type) {
            const slug = String(type && type.slug ? type.slug : "");
            const category = elementCategoryForSlug(slug);
            if (!Array.isArray(grouped[category])) {
                grouped[category] = [];
            }
            grouped[category].push(type);
        });

        ["layout", "content", "media", "advanced"].forEach(function (category) {
            const items = Array.isArray(grouped[category]) ? grouped[category] : [];
            if (!items.length) {
                return;
            }
            items.sort(function (a, b) {
                return String(a && a.label ? a.label : "").localeCompare(
                    String(b && b.label ? b.label : "")
                );
            });

            const group = document.createElement("section");
            group.className = "h4bs-element-group";
            const heading = document.createElement("h4");
            heading.textContent =
                elementCategoryLabel(category) + " (" + items.length + ")";
            group.appendChild(heading);

            items.forEach(function (type) {
                const slug = String(type.slug || "");
                const label = String(type.label || slug);
                const tile = document.createElement("article");
                tile.className =
                    "h4bs-library-tile h4bs-library-tile-element is-draggable";
                tile.setAttribute("data-h4bs-drag-kind", "element");
                tile.setAttribute("data-h4bs-drag-type", slug);
                tile.setAttribute("data-h4bs-drag-label", label);
                tile.tabIndex = 0;
                tile.setAttribute("role", "button");
                tile.setAttribute("aria-label", "Add " + label);
                tile.appendChild(
                    createLibraryThumb(elementIcon(slug), "", "is-element")
                );
                tile.appendChild(
                    createLibraryBody(label, "Drag to canvas")
                );
                tile.addEventListener("click", function (event) {
                    if (ignoreLibraryClick(event)) {
                        return;
                    }
                    insertElementFromLibrary(slug);
                });
                tile.addEventListener("keydown", function (event) {
                    if (event.key !== "Enter" && event.key !== " ") return;
                    event.preventDefault();
                    insertElementFromLibrary(slug);
                });
                group.appendChild(tile);
            });
            els.elementButtons.appendChild(group);
        });
        wireLibraryDraggables();
    }

    function templateSearchTags(template) {
        const raw = template && template.tags ? template.tags : [];
        if (Array.isArray(raw)) {
            return raw.map(String).join(" ");
        }
        return String(raw || "");
    }

    function templateRecommendationScore(template) {
        const slug = String(template && template.slug ? template.slug : "").toLowerCase();
        const category = String(
            template && template.category ? template.category : ""
        ).toLowerCase();
        const tags = templateSearchTags(template).toLowerCase();
        const title = String(data.postTitle || "").toLowerCase();
        const role = String(
            data.templateConditions && data.templateConditions.role
                ? data.templateConditions.role
                : ""
        ).toLowerCase();
        const scope = String(
            data.templateConditions && data.templateConditions.scope
                ? data.templateConditions.scope
                : ""
        ).toLowerCase();
        const pageLayout = String(data.pageLayout || "").toLowerCase();
        let score = 0;

        if (data.isTemplate) {
            if (role === "header" && category === "headers") score += 120;
            if (role === "footer" && category === "footers") score += 120;
            if ((role === "404" || scope === "404") && category === "404 pages") score += 120;
            if (role === "archive" && (tags.includes("archive") || slug.includes("archive"))) score += 100;
            if (role === "search" && (tags.includes("search") || slug.includes("search"))) score += 100;
        }
        if (pageLayout === "canvas" && (slug.includes("canvas") || tags.includes("canvas") || tags.includes("landing"))) score += 80;
        if (/home|homepage|front page/.test(title) && (tags.includes("homepage") || category === "sales + services")) score += 90;
        if (/price|pricing|plan|package/.test(title) && (tags.includes("pricing") || tags.includes("plans"))) score += 90;
        if (/faq|question|support/.test(title) && (tags.includes("faq") || category === "faq + support")) score += 90;
        if (/contact|quote|consult|estimate/.test(title) && (tags.includes("contact") || tags.includes("intake"))) score += 90;
        if (/about|team|company/.test(title) && (tags.includes("team") || tags.includes("authority"))) score += 80;
        if (/case study|portfolio|work|result/.test(title) && (tags.includes("proof") || tags.includes("portfolio"))) score += 80;
        return score;
    }

    function templateUseCaseCatalog() {
        return [
            { key: "all", label: "All designs" },
            { key: "recommended", label: "Best for this page" },
            { key: "pages", label: "Complete pages", terms: ["page", "homepage", "front page", "landing", "canvas"] },
            { key: "hero", label: "Hero sections", terms: ["hero", "headline", "banner"] },
            { key: "services", label: "Services", terms: ["services", "service", "local business", "contact", "quote", "intake"] },
            { key: "selling", label: "Selling", terms: ["ecommerce", "store", "product", "catalog", "checkout", "pricing", "plans", "packages"] },
            { key: "proof", label: "Proof and people", terms: ["portfolio", "gallery", "work", "proof", "testimonial", "reviews", "stats", "team"] },
            { key: "events-learning", label: "Events and learning", terms: ["event", "calendar", "course", "class", "program", "learning", "education"] },
            { key: "site-parts", label: "Headers and site parts", terms: ["header", "footer", "404", "archive", "search", "navigation"] },
        ];
    }

    function templateMatchesUseCase(template, useCase) {
        const key = String(useCase || "all").trim();
        if (key === "all") {
            return true;
        }
        if (key === "recommended") {
            return templateRecommendationScore(template) > 0;
        }
        const definition = templateUseCaseCatalog().find(function (item) {
            return item.key === key;
        });
        if (!definition || !Array.isArray(definition.terms)) {
            return true;
        }
        if (key === "pages") {
            const category = String(template && template.category ? template.category : "").toLowerCase();
            const tags = templateSearchTags(template).toLowerCase();
            const slug = String(template && template.slug ? template.slug : "").toLowerCase();
            if (/header|footer|404|basic sections/.test(category)) {
                return false;
            }
            return (
                /pages|page shells|sales \+ services|managed wordpress|agency \+ portfolio/.test(category) ||
                String(template && template.page_layout ? template.page_layout : "").trim() !== "" ||
                (
                    /page|homepage|front page|landing|canvas/.test(tags)
                    && /home|homepage|landing|launch|portal|command|funnel|catalog|page/.test(slug)
                )
            );
        }
        const haystack = (
            String(template && template.slug ? template.slug : "") +
            " " +
            String(template && template.label ? template.label : "") +
            " " +
            String(template && template.category ? template.category : "") +
            " " +
            templateSearchTags(template)
        ).toLowerCase();
        return definition.terms.some(function (term) {
            return haystack.indexOf(String(term).toLowerCase()) >= 0;
        });
    }

    function renderTemplateUseCaseFilters() {
        if (!(els.templateUseCases instanceof HTMLElement)) {
            return;
        }
        els.templateUseCases.innerHTML = "";
        templateUseCaseCatalog().forEach(function (item) {
            const button = document.createElement("button");
            const active = state.templateUseCase === item.key;
            button.type = "button";
            button.className = "h4bs-template-use-case" + (active ? " is-active" : "");
            button.textContent = item.label;
            button.setAttribute("aria-pressed", active ? "true" : "false");
            button.addEventListener("click", function () {
                state.templateUseCase = item.key;
                renderTemplateUseCaseFilters();
                renderTemplateCards();
            });
            els.templateUseCases.appendChild(button);
        });
    }

    function templatePreviewBlockText(block) {
        const settings = block && block.settings && typeof block.settings === "object"
            ? block.settings
            : {};
        const candidates = [
            settings.text,
            settings.title,
            settings.label,
            settings.button_label,
            settings.alt,
            settings.items,
            settings.shortcode,
        ];
        for (let index = 0; index < candidates.length; index += 1) {
            const value = String(candidates[index] || "")
                .replace(/<[^>]*>/g, " ")
                .replace(/\s+/g, " ")
                .trim();
            if (value !== "") {
                return value;
            }
        }
        return String(block && block.type ? block.type : "Content");
    }

    function templatePreviewColumns(settings, device) {
        const source = settings && typeof settings === "object" ? settings : {};
        const key = device === "mobile"
            ? "columns_mobile"
            : device === "tablet"
                ? "columns_tablet"
                : "columns";
        return Math.max(1, Math.min(4, Number(source[key] || source.columns || 1) || 1));
    }

    function appendTemplatePreviewBlock(container, block) {
        const type = String(block && block.type ? block.type : "text").toLowerCase();
        const item = document.createElement("div");
        item.className = "h4bs-template-visual-block is-" + type.replace(/[^a-z0-9_-]/g, "-");
        const text = templatePreviewBlockText(block);

        if (type === "image" || type === "video" || type === "gallery" || type === "slider") {
            const icon = document.createElement("span");
            icon.className = "dashicons " + (type === "video" ? "dashicons-video-alt3" : type === "gallery" ? "dashicons-format-gallery" : type === "slider" ? "dashicons-images-alt2" : "dashicons-format-image");
            icon.setAttribute("aria-hidden", "true");
            item.appendChild(icon);
        }

        const label = document.createElement(type === "heading" || type === "cta" ? "strong" : "span");
        label.textContent = text;
        item.appendChild(label);

        if (type === "cta" || type === "button") {
            const action = document.createElement("i");
            action.textContent = type === "button" ? text : "Action";
            item.appendChild(action);
        } else if (type === "text" || type === "list" || type === "faq" || type === "quote") {
            const lines = document.createElement("b");
            lines.setAttribute("aria-hidden", "true");
            item.appendChild(lines);
        }
        container.appendChild(item);
    }

    function createTemplateVisual(template, device, cardMode) {
        const visual = document.createElement("div");
        visual.className = "h4bs-template-visual is-" + (cardMode ? "card" : "large") + " is-" + String(device || "desktop");
        if (cardMode) {
            visual.setAttribute("aria-hidden", "true");
        } else {
            visual.setAttribute("role", "img");
            visual.setAttribute("aria-label", String(template && template.label ? template.label : "Design") + " layout preview");
        }

        const layout = Array.isArray(template && template.layout) ? template.layout : [];
        const blocks = layout.filter(function (block) {
            return block && typeof block === "object";
        });
        const children = {};
        blocks.forEach(function (block) {
            const parentId = String(block.parent_id || "");
            if (parentId !== "") {
                if (!children[parentId]) {
                    children[parentId] = [];
                }
                children[parentId].push(block);
            }
        });
        const roots = blocks.filter(function (block) {
            return String(block.parent_id || "") === "";
        });

        roots.slice(0, cardMode ? 5 : 10).forEach(function (block) {
            const type = String(block.type || "text").toLowerCase();
            if (type !== "section" && type !== "container") {
                const band = document.createElement("section");
                band.className = "h4bs-template-visual-band is-single";
                appendTemplatePreviewBlock(band, block);
                visual.appendChild(band);
                return;
            }

            const settings = block.settings && typeof block.settings === "object" ? block.settings : {};
            const columns = templatePreviewColumns(settings, device);
            const band = document.createElement("section");
            band.className = "h4bs-template-visual-band is-grid tone-" + String(settings.design_background_color_global || "surface").replace(/[^a-z0-9_-]/gi, "-");
            band.style.setProperty("--h4bs-template-preview-columns", String(columns));
            const columnsBySlot = [];
            for (let columnIndex = 0; columnIndex < columns; columnIndex += 1) {
                const column = document.createElement("div");
                column.className = "h4bs-template-visual-column";
                columnsBySlot.push(column);
                band.appendChild(column);
            }
            (children[String(block.id || "")] || []).forEach(function (child) {
                const slot = Math.max(0, Math.min(columns - 1, Number(child.slot || 0) || 0));
                appendTemplatePreviewBlock(columnsBySlot[slot], child);
            });
            columnsBySlot.forEach(function (column) {
                if (!column.children.length) {
                    const placeholder = document.createElement("span");
                    placeholder.className = "h4bs-template-visual-placeholder";
                    placeholder.setAttribute("aria-hidden", "true");
                    column.appendChild(placeholder);
                }
            });
            visual.appendChild(band);
        });

        return visual;
    }

    function templateBySlug(slug) {
        return (Array.isArray(data.templatePresets) ? data.templatePresets : []).find(function (template) {
            return String(template && template.slug ? template.slug : "") === String(slug || "");
        }) || null;
    }

    function closeTemplatePreview(restoreFocus) {
        if (!(els.templatePreviewModal instanceof HTMLElement)) {
            return;
        }
        els.templatePreviewModal.hidden = true;
        root.classList.remove("has-template-preview");
        state.templatePreviewSlug = "";
        if (restoreFocus && state.templatePreviewReturnFocus instanceof HTMLElement) {
            state.templatePreviewReturnFocus.focus();
        }
        state.templatePreviewReturnFocus = null;
    }

    function renderTemplatePreview() {
        const template = templateBySlug(state.templatePreviewSlug);
        if (!template || !(els.templatePreviewModal instanceof HTMLElement)) {
            closeTemplatePreview(false);
            return;
        }
        if (els.templatePreviewTitle) {
            els.templatePreviewTitle.textContent = String(template.label || "Design Preview");
        }
        if (els.templatePreviewCategory) {
            els.templatePreviewCategory.textContent = String(template.category || "Page Design");
        }
        if (els.templatePreviewDescription) {
            els.templatePreviewDescription.textContent = String(template.description || "Preview this design before adding it to the page.");
        }
        const layout = Array.isArray(template.layout) ? template.layout : [];
        if (els.templatePreviewCount) {
            const sectionCount = layout.filter(function (block) {
                return block && (block.type === "section" || block.type === "container") && String(block.parent_id || "") === "";
            }).length;
            els.templatePreviewCount.textContent = String(sectionCount) + (sectionCount === 1 ? " section, " : " sections, ") + String(layout.length) + (layout.length === 1 ? " element" : " elements");
        }
        if (els.templatePreviewIncludes) {
            els.templatePreviewIncludes.innerHTML = "";
            const typeLabels = {
                heading: "Headings",
                text: "Text",
                image: "Images",
                button: "Buttons",
                cta: "Calls to action",
                form: "Forms",
                shortcode: "Dynamic modules",
                faq: "FAQ",
                gallery: "Gallery",
                slider: "Slider",
                menu: "Navigation",
                video: "Video",
                list: "Lists",
            };
            const unique = [];
            layout.forEach(function (block) {
                const type = String(block && block.type ? block.type : "");
                const label = typeLabels[type] || "";
                if (label !== "" && unique.indexOf(label) < 0) {
                    unique.push(label);
                }
            });
            unique.slice(0, 7).forEach(function (label) {
                const item = document.createElement("li");
                item.textContent = label;
                els.templatePreviewIncludes.appendChild(item);
            });
        }
        if (els.templatePreviewStage) {
            els.templatePreviewStage.innerHTML = "";
            els.templatePreviewStage.appendChild(createTemplateVisual(template, state.templatePreviewDevice, false));
            els.templatePreviewStage.className = "h4bs-template-preview-stage is-" + state.templatePreviewDevice;
        }
        els.templatePreviewDevices.forEach(function (button) {
            const active = String(button.getAttribute("data-h4bs-template-preview-device") || "") === state.templatePreviewDevice;
            button.classList.toggle("is-active", active);
            button.setAttribute("aria-pressed", active ? "true" : "false");
        });
        if (els.templatePreviewUse) {
            els.templatePreviewUse.textContent = state.isFreshPage ? "Use This Design" : "Add to End of Page";
        }
        if (els.templatePreviewSecondary) {
            els.templatePreviewSecondary.hidden = state.isFreshPage;
            els.templatePreviewSecondary.textContent = "Replace Current Page...";
        }
    }

    function openTemplatePreview(template, returnFocus) {
        if (!template || !(els.templatePreviewModal instanceof HTMLElement)) {
            return;
        }
        state.templatePreviewSlug = String(template.slug || "");
        state.templatePreviewDevice = "desktop";
        state.templatePreviewReturnFocus = returnFocus instanceof HTMLElement ? returnFocus : document.activeElement;
        els.templatePreviewModal.hidden = false;
        root.classList.add("has-template-preview");
        renderTemplatePreview();
        window.requestAnimationFrame(function () {
            if (els.templatePreviewClose instanceof HTMLElement) {
                els.templatePreviewClose.focus();
            }
        });
    }

    function applyTemplatePreview(replaceCurrent) {
        const template = templateBySlug(state.templatePreviewSlug);
        if (!template) {
            return;
        }
        const shouldReplace = state.isFreshPage || !!replaceCurrent;
        const blocks = shouldReplace
            ? replaceLayoutWithTemplate(template)
            : insertTemplateAt(template, state.layout.length, { parent_id: "", slot: 0 });
        if (!Array.isArray(blocks) || !blocks.length) {
            return;
        }
        closeTemplatePreview(false);
        updateDirtyText(
            shouldReplace
                ? "Design applied. Review the page, then choose Save Changes when ready."
                : "Design added to the end of the page. Review it, then save when ready."
        );
        if (els.previewStage instanceof HTMLElement) {
            els.previewStage.focus({ preventScroll: false });
        }
    }

    function initTemplatePreview() {
        if (!(els.templatePreviewModal instanceof HTMLElement)) {
            return;
        }
        [els.templatePreviewClose, els.templatePreviewCancel].forEach(function (button) {
            if (button) {
                button.addEventListener("click", function () {
                    closeTemplatePreview(true);
                });
            }
        });
        if (els.templatePreviewUse) {
            els.templatePreviewUse.addEventListener("click", function () {
                applyTemplatePreview(false);
            });
        }
        if (els.templatePreviewSecondary) {
            els.templatePreviewSecondary.addEventListener("click", function () {
                applyTemplatePreview(true);
            });
        }
        els.templatePreviewDevices.forEach(function (button) {
            button.addEventListener("click", function () {
                state.templatePreviewDevice = String(button.getAttribute("data-h4bs-template-preview-device") || "desktop");
                renderTemplatePreview();
            });
        });
        els.templatePreviewModal.addEventListener("click", function (event) {
            if (event.target === els.templatePreviewModal) {
                closeTemplatePreview(true);
            }
        });
        document.addEventListener("keydown", function (event) {
            if (els.templatePreviewModal.hidden) {
                return;
            }
            if (event.key === "Escape") {
                event.preventDefault();
                closeTemplatePreview(true);
                return;
            }
            if (event.key !== "Tab") {
                return;
            }
            const focusable = Array.from(els.templatePreviewModal.querySelectorAll('button:not([hidden]):not([disabled]), [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')).filter(function (node) {
                return node instanceof HTMLElement && node.offsetParent !== null;
            });
            if (!focusable.length) {
                return;
            }
            const first = focusable[0];
            const last = focusable[focusable.length - 1];
            if (event.shiftKey && document.activeElement === first) {
                event.preventDefault();
                last.focus();
            } else if (!event.shiftKey && document.activeElement === last) {
                event.preventDefault();
                first.focus();
            }
        });
    }

    function renderTemplateCards() {
        if (!els.templateList) {
            return;
        }
        els.templateList.innerHTML = "";
        const query = els.templateSearch
            ? String(els.templateSearch.value || "").toLowerCase().trim()
            : "";
        const categoryFilter = els.templateCategory
            ? String(els.templateCategory.value || "all").toLowerCase().trim()
            : "all";
        const templates = Array.isArray(data.templatePresets)
            ? data.templatePresets
            : [];
        const filteredTemplates = templates.filter(function (template) {
            if (!templateMatchesUseCase(template, state.templateUseCase)) {
                return false;
            }
            const templateCategory = String(
                template && template.category ? template.category : "General"
            )
                .toLowerCase()
                .trim();
            if (
                categoryFilter !== "all" &&
                categoryFilter !== "recommended" &&
                templateCategory !== categoryFilter
            ) {
                return false;
            }
            if (categoryFilter === "recommended" && templateRecommendationScore(template) <= 0) {
                return false;
            }
            if (query === "") {
                return true;
            }
            const haystack = (
                String(template && template.slug ? template.slug : "") +
                " " +
                String(template && template.label ? template.label : "") +
                " " +
                String(template && template.category ? template.category : "") +
                " " +
                String(
                    template && template.description ? template.description : ""
                ) +
                " " +
                templateSearchTags(template)
            )
                .toLowerCase()
                .trim();
            return haystack.indexOf(query) >= 0;
        });
        if (!filteredTemplates.length) {
            const empty = document.createElement("p");
            empty.className = "h4bs-inspector-empty";
            empty.textContent = "No templates match this search.";
            els.templateList.appendChild(empty);
            if (els.templateResults) {
                els.templateResults.textContent = "No designs match these filters.";
            }
            return;
        }
        filteredTemplates.sort(function (a, b) {
            const scoreDifference =
                templateRecommendationScore(b) - templateRecommendationScore(a);
            if (scoreDifference !== 0) {
                return scoreDifference;
            }
            return String(a && a.label ? a.label : "").localeCompare(
                String(b && b.label ? b.label : "")
            );
        });
        if (els.templateResults) {
            els.templateResults.textContent = String(filteredTemplates.length) + (filteredTemplates.length === 1 ? " design" : " designs");
        }
        filteredTemplates.forEach(function (template) {
            const card = document.createElement("article");
            card.className = "h4bs-library-tile h4bs-template-card is-draggable";
            card.setAttribute("data-h4bs-drag-kind", "template");
            card.setAttribute(
                "data-h4bs-template-slug",
                String(template.slug || "")
            );
            card.setAttribute(
                "data-h4bs-drag-label",
                String(template.label || "Template")
            );

            card.appendChild(createTemplateVisual(template, "desktop", true));
            const body = createLibraryBody(
                String(template.label || "Template"),
                String(template.description || "Preview this editable design")
            );
            const categoryBadge = document.createElement("span");
            categoryBadge.className = "h4bs-library-meta";
            categoryBadge.textContent =
                "Category: " +
                String(
                    template && template.category ? template.category : "General"
                );
            body.appendChild(categoryBadge);
            const recommendationScore = templateRecommendationScore(template);
            if (recommendationScore > 0) {
                const recommended = document.createElement("span");
                recommended.className = "h4bs-library-meta is-recommended";
                recommended.textContent = "Recommended for this page";
                body.appendChild(recommended);
            }
            const blockCount = document.createElement("span");
            blockCount.className = "h4bs-library-meta";
            blockCount.textContent =
                String(Array.isArray(template.layout) ? template.layout.length : 0) +
                " native blocks";
            body.appendChild(blockCount);
            if (String(template && template.page_layout ? template.page_layout : "").trim() !== "") {
                const pageMode = document.createElement("span");
                pageMode.className = "h4bs-library-meta";
                pageMode.textContent =
                    "Replace Page mode: " +
                    (String(template.page_layout) === "canvas"
                        ? "Help4 Canvas"
                        : String(template.page_layout) === "full_width"
                            ? "Help4 Full Width"
                            : "Theme Default");
                body.appendChild(pageMode);
            }
            const actions = document.createElement("div");
            actions.className = "h4bs-library-actions";

            const previewButton = document.createElement("button");
            previewButton.type = "button";
            previewButton.className = "button button-primary";
            previewButton.textContent = "Preview Design";
            previewButton.addEventListener("click", function (event) {
                event.preventDefault();
                event.stopPropagation();
                openTemplatePreview(template, previewButton);
            });
            actions.appendChild(previewButton);
            const dragHint = document.createElement("span");
            dragHint.className = "h4bs-template-drag-hint";
            dragHint.textContent = "Or drag to the canvas";
            actions.appendChild(dragHint);
            body.appendChild(actions);

            card.appendChild(body);
            card.addEventListener("click", function (event) {
                if (ignoreLibraryClick(event)) {
                    return;
                }
                openTemplatePreview(template, card);
            });
            els.templateList.appendChild(card);
        });
        wireLibraryDraggables();
    }

    function renderSiteKitCards() {
        if (!els.siteKitList) {
            return;
        }
        els.siteKitList.innerHTML = "";
        const query = els.siteKitSearch
            ? String(els.siteKitSearch.value || "").toLowerCase().trim()
            : "";
        const kits = Array.isArray(data.siteKits) ? data.siteKits : [];
        const filtered = kits.filter(function (kit) {
            if (query === "") {
                return true;
            }
            const features = Array.isArray(kit && kit.features)
                ? kit.features.join(" ")
                : "";
            const pageNames = Array.isArray(kit && kit.pages)
                ? kit.pages
                      .map(function (page) {
                          return String(page && page.title ? page.title : "");
                      })
                      .join(" ")
                : "";
            const haystack = [
                kit && kit.slug,
                kit && kit.label,
                kit && kit.industry,
                kit && kit.description,
                kit && kit.theme_pack,
                features,
                pageNames,
            ]
                .map(function (value) {
                    return String(value || "");
                })
                .join(" ")
                .toLowerCase();
            return haystack.indexOf(query) >= 0;
        });
        if (!filtered.length) {
            const empty = document.createElement("p");
            empty.className = "h4bs-inspector-empty";
            empty.textContent = "No site kits match this search.";
            els.siteKitList.appendChild(empty);
            return;
        }

        filtered.forEach(function (kit) {
            const pages = Array.isArray(kit.pages) ? kit.pages : [];
            const templates = Array.isArray(kit.templates) ? kit.templates : [];
            const card = document.createElement("article");
            card.className = "h4bs-library-tile h4bs-site-kit-card";
            card.appendChild(
                createLibraryThumb(
                    "dashicons-admin-multisite",
                    "Site Kit",
                    themePackTone(kit)
                )
            );

            const body = createLibraryBody(
                String(kit.label || "Site Kit"),
                String(kit.description || "Editable draft site foundation")
            );
            const industry = document.createElement("span");
            industry.className = "h4bs-library-meta";
            industry.textContent =
                String(kit.industry || "General") +
                " | " +
                String(pages.length) +
                " pages + " +
                String(templates.length) +
                " templates";
            body.appendChild(industry);

            const style = document.createElement("span");
            style.className = "h4bs-library-meta";
            style.textContent =
                "Optional style: " +
                String(kit.theme_pack || "keep current global styles");
            body.appendChild(style);

            const details = document.createElement("details");
            details.className = "h4bs-site-kit-plan";
            const summary = document.createElement("summary");
            summary.textContent = "Review included drafts";
            details.appendChild(summary);
            const list = document.createElement("ul");
            pages.concat(templates).forEach(function (item) {
                const row = document.createElement("li");
                row.textContent =
                    String(item.title || item.key || "Draft") +
                    (item.role ? " (" + String(item.role) + ")" : "");
                list.appendChild(row);
            });
            details.appendChild(list);
            body.appendChild(details);

            const actions = document.createElement("div");
            actions.className = "h4bs-library-actions";
            const install = document.createElement("button");
            install.type = "button";
            install.className = "button button-primary";
            install.textContent = "Install Draft Kit";
            install.addEventListener("click", function (event) {
                event.preventDefault();
                event.stopPropagation();
                installSiteKit(kit, install);
            });
            actions.appendChild(install);
            body.appendChild(actions);
            card.appendChild(body);
            els.siteKitList.appendChild(card);
        });
    }

    function installSiteKit(kit, button) {
        const kitSlug = String(kit && kit.slug ? kit.slug : "").trim();
        if (kitSlug === "" || !(button instanceof HTMLButtonElement)) {
            return;
        }
        const applyStyles = !!(
            els.siteKitApplyStyles && els.siteKitApplyStyles.checked
        );
        const prompt =
            "Install " +
            String(kit.label || "this site kit") +
            " as drafts?\n\n" +
            "Builder will create or reuse only kit-owned drafts and a kit-owned navigation menu. It will not publish, replace existing content, assign templates, or change the front page." +
            (applyStyles
                ? "\n\nThe selected kit style tokens will also be applied sitewide."
                : "");
        if (!window.confirm(prompt)) {
            return;
        }

        button.disabled = true;
        button.textContent = "Installing...";
        setSiteKitStatus("Running site-kit preflight...");
        $.post(data.ajaxUrl, {
            action: "h4bs_builder_import_site_kit",
            nonce: data.nonce,
            site_kit: kitSlug,
            apply_styles: applyStyles ? "1" : "0",
            global_revision: String(state.globalDesignRevision || 1),
        })
            .done(function (response) {
                if (!response || !response.success) {
                    const message =
                        response &&
                        response.data &&
                        typeof response.data.message === "string"
                            ? response.data.message
                            : "The site kit could not be installed.";
                    setSiteKitStatus(message, [], true);
                    return;
                }
                const result = response.data || {};
                const items = []
                    .concat(Array.isArray(result.pages) ? result.pages : [])
                    .concat(
                        Array.isArray(result.templates)
                            ? result.templates
                            : []
                    );
                const links = items
                    .filter(function (item) {
                        return item && item.builder_url;
                    })
                    .map(function (item) {
                        return {
                            label:
                                String(item.title || "Open draft") +
                                (item.created ? " - new" : " - existing"),
                            url: String(item.builder_url),
                        };
                    });
                const created = Number(result.created_count || 0);
                const reused = Number(result.reused_count || 0);
                const styles =
                    result.styles && result.styles.changed
                        ? " Global styles were updated; reload Studio before editing global tokens."
                        : "";
                if (
                    result.styles &&
                    Number(result.styles.global_revision || 0) > 0
                ) {
                    state.globalDesignRevision = Number(
                        result.styles.global_revision
                    );
                }
                setSiteKitStatus(
                    "Draft kit ready: " +
                        String(created) +
                        " created, " +
                        String(reused) +
                        " reused." +
                        styles,
                    links,
                    false
                );
            })
            .fail(function (xhr) {
                const response =
                    xhr && xhr.responseJSON && xhr.responseJSON.data
                        ? xhr.responseJSON.data
                        : {};
                setSiteKitStatus(
                    String(
                        response.message ||
                            "The site kit request failed before completion."
                    ),
                    [],
                    true
                );
            })
            .always(function () {
                button.disabled = false;
                button.textContent = "Install Draft Kit";
            });
    }

    function setSiteKitStatus(message, links, isError) {
        if (!els.siteKitStatus) {
            return;
        }
        els.siteKitStatus.innerHTML = "";
        els.siteKitStatus.classList.toggle("is-error", !!isError);
        const summary = document.createElement("p");
        summary.textContent = String(message || "");
        els.siteKitStatus.appendChild(summary);
        (Array.isArray(links) ? links : []).forEach(function (link) {
            const anchor = document.createElement("a");
            anchor.href = String(link.url || "#");
            anchor.textContent = String(link.label || "Open draft");
            anchor.target = "_blank";
            anchor.rel = "noopener";
            els.siteKitStatus.appendChild(anchor);
        });
    }

    function renderTemplateCategoryOptions() {
        if (!els.templateCategory) {
            return;
        }
        const current = String(els.templateCategory.value || "all")
            .toLowerCase()
            .trim();
        const templates = Array.isArray(data.templatePresets)
            ? data.templatePresets
            : [];
        const categories = new Set(["all", "recommended"]);
        templates.forEach(function (template) {
            const label = String(
                template && template.category ? template.category : "General"
            ).trim();
            if (label !== "") {
                categories.add(label);
            }
        });
        const options = Array.from(categories);
        els.templateCategory.innerHTML = "";
        options.forEach(function (category) {
            const option = document.createElement("option");
            if (category.toLowerCase() === "all") {
                option.value = "all";
                option.textContent = "All Categories";
            } else if (category.toLowerCase() === "recommended") {
                option.value = "recommended";
                option.textContent = "Recommended for This Page";
            } else {
                option.value = category.toLowerCase();
                option.textContent = category;
            }
            els.templateCategory.appendChild(option);
        });
        const hasCurrent = options.some(function (category) {
            return category.toLowerCase() === current;
        });
        els.templateCategory.value = hasCurrent ? current : "all";
    }

    function themePackCatalog() {
        const merged = [];
        const index = {};
        (Array.isArray(data.themePacks) ? data.themePacks : [])
            .concat(Array.isArray(state.customThemePacks) ? state.customThemePacks : [])
            .forEach(function (pack) {
                const slug = String(pack && pack.slug ? pack.slug : "").trim();
                if (slug === "" || Object.prototype.hasOwnProperty.call(index, slug)) {
                    return;
                }
                index[slug] = true;
                merged.push(pack);
            });
        return merged;
    }

    function normalizeCustomThemePacks(raw) {
        if (!Array.isArray(raw)) {
            return [];
        }
        const seen = {};
        return raw
            .map(function (pack, index) {
                if (!pack || typeof pack !== "object") {
                    return null;
                }
                const label = String(pack.label || "Custom Style " + String(index + 1)).trim();
                let slug = String(pack.slug || label)
                    .toLowerCase()
                    .replace(/[^a-z0-9]+/g, "-")
                    .replace(/^-+|-+$/g, "");
                if (slug === "") {
                    slug = "custom-style-" + String(index + 1);
                }
                if (seen[slug]) {
                    return null;
                }
                seen[slug] = true;
                return {
                    slug: slug,
                    label: label || slug,
                    description: String(pack.description || "Custom Builder design tokens.").trim(),
                    industry: String(pack.industry || "Custom").trim(),
                    page_layout: normalizePageLayout(pack.page_layout || "default"),
                    template_slug: "",
                    replace_layout: false,
                    thumbnail: String(pack.thumbnail || "").trim(),
                    tokens: normalizeThemeTokenPatch(pack.tokens || {}),
                    custom: true,
                };
            })
            .filter(function (pack) {
                return !!pack;
            })
            .slice(0, 100);
    }

    function normalizeThemeTokenPatch(raw) {
        const source = raw && typeof raw === "object" ? raw : {};
        const normalized = normalizeGlobalDesignTokens(source);
        const patch = {};
        ["colors", "fonts", "typography", "spacing", "shape", "components", "layout"].forEach(
            function (group) {
                const sourceGroup = source[group] && typeof source[group] === "object"
                    ? source[group]
                    : null;
                if (!sourceGroup) {
                    return;
                }
                const values = {};
                Object.keys(sourceGroup).forEach(function (key) {
                    if (
                        normalized[group] &&
                        Object.prototype.hasOwnProperty.call(normalized[group], key)
                    ) {
                        values[key] = normalized[group][key];
                    }
                });
                if (Object.keys(values).length > 0) {
                    patch[group] = values;
                }
            }
        );
        return patch;
    }

    function mergeGlobalDesignTokenPatch(base, patch) {
        const merged = deepClone(normalizeGlobalDesignTokens(base || {}));
        const source = normalizeThemeTokenPatch(patch || {});
        Object.keys(source).forEach(function (group) {
            if (!merged[group] || typeof merged[group] !== "object") {
                merged[group] = {};
            }
            Object.keys(source[group] || {}).forEach(function (key) {
                merged[group][key] = source[group][key];
            });
        });
        return normalizeGlobalDesignTokens(merged);
    }

    function customThemePackSpec(label) {
        return normalizeCustomThemePacks([
            {
                slug: "custom-" +
                    String(label || "style")
                        .toLowerCase()
                        .replace(/[^a-z0-9]+/g, "-")
                        .replace(/^-+|-+$/g, ""),
                label: String(label || "Custom Style").trim(),
                description: "Custom Builder design tokens.",
                industry: "Custom",
                page_layout: state.pageLayout,
                tokens: deepClone(state.globalDesignTokens || {}),
                custom: true,
            },
        ])[0] || null;
    }

    function upsertCustomThemePack(pack) {
        const normalized = normalizeCustomThemePacks([pack])[0] || null;
        if (!normalized) {
            return false;
        }
        const next = (Array.isArray(state.customThemePacks) ? state.customThemePacks : []).filter(
            function (item) {
                return String(item && item.slug ? item.slug : "") !== normalized.slug;
            }
        );
        next.push(normalized);
        state.customThemePacks = normalizeCustomThemePacks(next);
        state.globalDesignDirty = true;
        state.activeThemePack = normalized.slug;
        setDirty(true);
        renderThemePackCards();
        return true;
    }

    function saveCurrentThemePack() {
        const label = window.prompt("Name this reusable style pack:", "My Site Style");
        if (label === null || String(label).trim() === "") {
            return;
        }
        const pack = customThemePackSpec(label);
        if (pack && upsertCustomThemePack(pack)) {
            updateDirtyText("Custom style pack saved. Publish to keep it on this site.");
        }
    }

    function importThemePack() {
        const raw = window.prompt("Paste a Help4 theme pack JSON object:", "");
        if (raw === null || String(raw).trim() === "") {
            return;
        }
        try {
            const parsed = JSON.parse(String(raw));
            const pack = normalizeCustomThemePacks([parsed])[0] || null;
            if (!pack || !upsertCustomThemePack(pack)) {
                throw new Error("Invalid pack");
            }
            applyThemePack(pack, "style");
            updateDirtyText("Theme pack imported as style-only. Publish to keep it.");
        } catch (error) {
            window.alert("That JSON is not a valid Help4 theme pack.");
        }
    }

    function exportThemePack() {
        const active = themePackCatalog().find(function (pack) {
            return String(pack && pack.slug ? pack.slug : "") === String(state.activeThemePack || "");
        });
        const pack = active || customThemePackSpec("Current Site Style");
        const json = JSON.stringify(pack, null, 2);
        copyTextToClipboard(json).then(function () {
            updateDirtyText("Theme pack JSON copied.");
        });
    }

    function renderThemePackCards() {
        if (!els.themeList) {
            return;
        }
        els.themeList.innerHTML = "";
        const query = els.themeSearch
            ? String(els.themeSearch.value || "").toLowerCase().trim()
            : "";
        const packs = themePackCatalog().filter(function (pack) {
            if (query === "") {
                return true;
            }
            const haystack = (
                String(pack && pack.slug ? pack.slug : "") +
                " " +
                String(pack && pack.label ? pack.label : "") +
                " " +
                String(pack && pack.description ? pack.description : "") +
                " " +
                String(pack && pack.industry ? pack.industry : "")
            )
                .toLowerCase()
                .trim();
            return haystack.indexOf(query) >= 0;
        });

        if (!packs.length) {
            const empty = document.createElement("p");
            empty.className = "h4bs-inspector-empty";
            empty.textContent = "No theme packs match this search.";
            els.themeList.appendChild(empty);
            return;
        }

        packs.forEach(function (pack) {
            const card = document.createElement("article");
            card.className = "h4bs-library-tile h4bs-theme-pack-card";
            const packSlug = String(pack && pack.slug ? pack.slug : "").trim();
            if (packSlug !== "" && packSlug === state.activeThemePack) {
                card.classList.add("is-active");
            }

            const preview = String(pack && pack.thumbnail ? pack.thumbnail : "").trim();
            if (preview !== "") {
                const media = document.createElement("div");
                media.className = "h4bs-theme-pack-thumb " + themePackTone(pack);
                const image = document.createElement("img");
                image.src = preview;
                image.loading = "lazy";
                image.alt = String(pack && pack.label ? pack.label : "Theme Pack");
                media.appendChild(image);
                card.appendChild(media);
            } else {
                card.appendChild(
                    createLibraryThumb(
                        "dashicons-art",
                        "Theme",
                        themePackTone(pack)
                    )
                );
            }

            const body = createLibraryBody(
                String(pack && pack.label ? pack.label : "Theme Pack"),
                String(
                    pack && pack.description
                        ? pack.description
                        : "Apply curated global design tokens."
                )
            );
            const meta = document.createElement("span");
            meta.className = "h4bs-library-meta";
            const industry = String(pack && pack.industry ? pack.industry : "General");
            const starter = String(
                pack && pack.template_slug ? pack.template_slug : ""
            ).trim();
            meta.textContent =
                "Industry: " +
                industry +
                (starter !== "" ? " | Starter: " + starter : " | Style-only");
            body.appendChild(meta);
            if (packSlug !== "" && packSlug === state.activeThemePack) {
                const activeBadge = document.createElement("span");
                activeBadge.className = "h4bs-theme-pack-active-badge";
                activeBadge.textContent = "Active";
                body.appendChild(activeBadge);
            }
            card.appendChild(body);

            const actions = document.createElement("div");
            actions.className = "h4bs-theme-pack-actions";

            const styleButton = document.createElement("button");
            styleButton.type = "button";
            styleButton.className = "button button-small";
            styleButton.textContent = "Apply Style";
            styleButton.addEventListener("click", function (event) {
                event.preventDefault();
                event.stopPropagation();
                applyThemePack(pack, "style");
            });
            actions.appendChild(styleButton);

            if (starter !== "") {
                const starterButton = document.createElement("button");
                starterButton.type = "button";
                starterButton.className = "button button-small";
                starterButton.textContent = "Style + Starter";
                starterButton.addEventListener("click", function (event) {
                    event.preventDefault();
                    event.stopPropagation();
                    applyThemePack(
                        pack,
                        pack && pack.replace_layout ? "replace" : "append"
                    );
                });
                actions.appendChild(starterButton);
            }

            card.appendChild(actions);
            els.themeList.appendChild(card);
        });
    }

    function widgetCatalog() {
        return Array.isArray(data.widgetCatalog) ? data.widgetCatalog : [];
    }

    function renderWidgetLibrary() {
        if (!els.widgetList) {
            return;
        }

        els.widgetList.innerHTML = "";
        const allItems = widgetCatalog();
        const recentRank = {};
        state.widgetRecent.forEach(function (entry, index) {
            recentRank[String(entry || "")] = index;
        });

        const filterRow = document.createElement("div");
        filterRow.className = "h4bs-widget-filters";
        [
            { key: "all", label: "All" },
            { key: "favorites", label: "Favorites" },
            { key: "recent", label: "Recent" },
        ].forEach(function (tab) {
            const btn = document.createElement("button");
            btn.type = "button";
            btn.className = "button button-small h4bs-widget-filter-btn";
            if (String(state.widgetFilter || "all") === String(tab.key)) {
                btn.classList.add("is-active");
            }
            btn.textContent = String(tab.label || tab.key);
            btn.addEventListener("click", function () {
                state.widgetFilter = String(tab.key || "all");
                persistWidgetFilter();
                renderWidgetLibrary();
            });
            filterRow.appendChild(btn);
        });
        els.widgetList.appendChild(filterRow);

        const query = els.widgetSearch
            ? String(els.widgetSearch.value || "").toLowerCase().trim()
            : "";
        const items = allItems.filter(function (item) {
            const shortcode = String(item && item.shortcode ? item.shortcode : "").trim();
            const blockType = normalizeBlockType(
                item && (item.block_type || item.blockType)
                    ? item.block_type || item.blockType
                    : "",
                ""
            );
            const widgetKey = widgetStorageKey(item);
            const status = String(item && item.status ? item.status : "ready")
                .trim()
                .toLowerCase();

            if (shortcode === "" && blockType === "") {
                return false;
            }
            if (state.widgetFilter === "favorites" && !isWidgetFavorite(widgetKey)) {
                return false;
            }
            if (
                state.widgetFilter === "recent" &&
                !Object.prototype.hasOwnProperty.call(recentRank, widgetKey)
            ) {
                return false;
            }
            if (query === "") {
                return true;
            }
            const haystack = (
                String(item.label || "") +
                " " +
                String(item.category || "") +
                " " +
                shortcode +
                " " +
                blockType
            ).toLowerCase();
            return haystack.indexOf(query) >= 0;
        });

        if (String(state.widgetFilter || "all") === "recent") {
            items.sort(function (a, b) {
                const aKey = widgetStorageKey(a);
                const bKey = widgetStorageKey(b);
                const aRank = Object.prototype.hasOwnProperty.call(recentRank, aKey)
                    ? Number(recentRank[aKey])
                    : Number.MAX_SAFE_INTEGER;
                const bRank = Object.prototype.hasOwnProperty.call(recentRank, bKey)
                    ? Number(recentRank[bKey])
                    : Number.MAX_SAFE_INTEGER;
                if (aRank !== bRank) {
                    return aRank - bRank;
                }
                return String(a && a.label ? a.label : "").localeCompare(
                    String(b && b.label ? b.label : "")
                );
            });
        } else {
            items.sort(function (a, b) {
                const aCategory = String(a && a.category ? a.category : "Widgets");
                const bCategory = String(b && b.category ? b.category : "Widgets");
                if (aCategory !== bCategory) {
                    return aCategory.localeCompare(bCategory);
                }
                return String(a && a.label ? a.label : "").localeCompare(
                    String(b && b.label ? b.label : "")
                );
            });
        }

        const grouped = {};
        items.forEach(function (item) {
            const category = String(item.category || "Widgets");
            if (!grouped[category]) {
                grouped[category] = [];
            }
            grouped[category].push(item);
        });

        const categories = Object.keys(grouped);
        if (!categories.length) {
            const empty = document.createElement("p");
            empty.className = "h4bs-inspector-empty h4bs-widget-empty";
            empty.textContent =
                query === ""
                    ? String(state.widgetFilter || "all") === "favorites"
                        ? "No favorite widgets yet. Click a star to save favorites."
                        : String(state.widgetFilter || "all") === "recent"
                        ? "No recent widgets yet. Insert a widget to populate this list."
                        : "No widgets are available in this build."
                    : "No widgets match this search.";
            els.widgetList.appendChild(empty);
            return;
        }
        categories.sort().forEach(function (category) {
            const section = document.createElement("section");
            section.className = "h4bs-widget-group";
            let itemCount = 0;

            const heading = document.createElement("h4");
            heading.textContent = category;
            section.appendChild(heading);

            grouped[category].forEach(function (item) {
                const shortcode = String(item.shortcode || "").trim();
                const blockType = normalizeBlockType(
                    item.block_type || item.blockType || "",
                    ""
                );
                const widgetKey = widgetStorageKey(item);
                const canUse = shortcode !== "" || blockType !== "";
                if (!canUse) {
                    return;
                }
                const row = document.createElement("article");
                row.className = "h4bs-library-tile h4bs-widget-item";
                row.classList.add("is-draggable");
                row.setAttribute("data-h4bs-drag-kind", "widget");
                if (shortcode !== "") {
                    row.setAttribute("data-h4bs-widget-shortcode", shortcode);
                }
                if (blockType !== "") {
                    row.setAttribute("data-h4bs-widget-block-type", blockType);
                }
                if (String(item.slug || "").trim() !== "") {
                    row.setAttribute(
                        "data-h4bs-widget-slug",
                        String(item.slug || "").trim()
                    );
                }
                row.setAttribute(
                    "data-h4bs-widget-category",
                    String(item.category || "Widgets")
                );
                if (item.settings && typeof item.settings === "object") {
                    try {
                        row.setAttribute(
                            "data-h4bs-widget-settings",
                            encodeURIComponent(JSON.stringify(item.settings))
                        );
                    } catch (_error) {
                        // ignore invalid JSON payloads for drag metadata
                    }
                }
                row.setAttribute(
                    "data-h4bs-drag-label",
                    String(item.label || "Widget")
                );

                row.appendChild(
                    createLibraryThumb(
                        widgetIcon(category),
                        "LIVE",
                        "is-ready"
                    )
                );

                const meta = createLibraryBody(
                    String(item.label || "Widget"),
                    "Content element"
                );
                row.appendChild(meta);

                const controls = document.createElement("div");
                controls.className = "h4bs-widget-item-controls";
                if (widgetKey !== "") {
                    const favoriteBtn = document.createElement("button");
                    favoriteBtn.type = "button";
                    favoriteBtn.className = "button button-small h4bs-widget-favorite";
                    if (isWidgetFavorite(widgetKey)) {
                        favoriteBtn.classList.add("is-active");
                    }
                    favoriteBtn.setAttribute("aria-label", "Toggle favorite");
                    favoriteBtn.title = isWidgetFavorite(widgetKey)
                        ? "Remove favorite"
                        : "Add favorite";
                    favoriteBtn.innerHTML = isWidgetFavorite(widgetKey)
                        ? "<span class='dashicons dashicons-star-filled' aria-hidden='true'></span>"
                        : "<span class='dashicons dashicons-star-empty' aria-hidden='true'></span>";
                    favoriteBtn.addEventListener("click", function (event) {
                        event.preventDefault();
                        event.stopPropagation();
                        toggleWidgetFavorite(widgetKey);
                    });
                    controls.appendChild(favoriteBtn);
                }
                const insertBtn = document.createElement("button");
                insertBtn.type = "button";
                insertBtn.className = "button button-small h4bs-widget-insert";
                insertBtn.textContent = "Insert";
                insertBtn.addEventListener("click", function (event) {
                    event.preventDefault();
                    event.stopPropagation();
                    const widgetPayload = {
                        shortcode: shortcode,
                        block_type: blockType,
                        slug: String(item.slug || ""),
                        label: String(item.label || ""),
                        category: String(item.category || ""),
                        settings:
                            item.settings && typeof item.settings === "object"
                                ? deepClone(item.settings)
                                : {},
                    };
                    insertWidgetFromLibrary(widgetPayload);
                });
                controls.appendChild(insertBtn);
                if (controls.childNodes.length > 0) {
                    row.appendChild(controls);
                }

                row.addEventListener("click", function (event) {
                    if (ignoreLibraryClick(event)) {
                        return;
                    }
                    const widgetPayload = {
                        shortcode: shortcode,
                        block_type: blockType,
                        slug: String(item.slug || ""),
                        settings:
                            item.settings && typeof item.settings === "object"
                                ? deepClone(item.settings)
                                : {},
                    };
                    insertWidgetFromLibrary(widgetPayload);
                });

                section.appendChild(row);
                itemCount += 1;
            });

            if (itemCount > 0) {
                els.widgetList.appendChild(section);
            }
        });
        wireLibraryDraggables();
    }

    function buildDragPayloadFromNode(node) {
        if (!(node instanceof HTMLElement)) {
            return null;
        }
        const kind = String(node.getAttribute("data-h4bs-drag-kind") || "");
        const label = String(node.getAttribute("data-h4bs-drag-label") || "Item");
        if (kind === "element") {
            const type = normalizeBlockType(
                node.getAttribute("data-h4bs-drag-type") || "",
                ""
            );
            if (type === "") {
                return null;
            }
            return { kind: kind, type: type, label: label };
        }
        if (kind === "widget") {
            const shortcode = String(
                node.getAttribute("data-h4bs-widget-shortcode") || ""
            );
            const blockType = normalizeBlockType(
                node.getAttribute("data-h4bs-widget-block-type") || "",
                ""
            );
            if (shortcode === "" && blockType === "") {
                return null;
            }
            let settings = {};
            const rawSettings = String(
                node.getAttribute("data-h4bs-widget-settings") || ""
            );
            if (rawSettings !== "") {
                try {
                    const parsed = JSON.parse(decodeURIComponent(rawSettings));
                    if (parsed && typeof parsed === "object") {
                        settings = parsed;
                    }
                } catch (_error) {
                    settings = {};
                }
            }
            return {
                kind: kind,
                shortcode: shortcode,
                block_type: blockType,
                slug: String(node.getAttribute("data-h4bs-widget-slug") || ""),
                category: String(
                    node.getAttribute("data-h4bs-widget-category") || ""
                ),
                settings: settings,
                label: label,
            };
        }
        if (kind === "template") {
            const slug = String(node.getAttribute("data-h4bs-template-slug") || "");
            if (slug === "") {
                return null;
            }
            return { kind: kind, slug: slug, label: label };
        }
        return null;
    }

    function wireLibraryDraggables() {
        if (!els.previewCanvas || !$.fn || typeof $.fn.draggable !== "function") {
            return;
        }

        root.querySelectorAll("[data-h4bs-drag-kind]").forEach(function (node) {
            if (!(node instanceof HTMLElement)) {
                return;
            }
            const payload = buildDragPayloadFromNode(node);
            if (!payload) {
                return;
            }
            node.setAttribute("data-h4bs-drop-payload", JSON.stringify(payload));

            const $node = $(node);
            if ($node.hasClass("ui-draggable")) {
                $node.draggable("destroy");
            }

            $node.draggable({
                connectToSortable:
                    "[data-h4bs-preview-canvas], [data-h4bs-section-dropzone]",
                appendTo: "body",
                helper: function () {
                    const helper = document.createElement("section");
                    helper.className = "h4bs-drag-helper";
                    helper.textContent = String(payload.label || "Element");
                    helper.setAttribute(
                        "data-h4bs-drop-payload",
                        JSON.stringify(payload)
                    );
                    return helper;
                },
                revert: "invalid",
                zIndex: 100001,
                cursorAt: { left: 16, top: 12 },
                distance: 6,
                cancel: ".button,a,input,textarea,select,label",
                start: function () {
                    state.libraryDragStartedAt = Date.now();
                    state.activeDragPayload = payload;
                    root.setAttribute(
                        "data-h4bs-active-payload",
                        JSON.stringify(payload)
                    );
                    root.classList.add("is-dragging-library");
                    setDropTargetsActive(true);
                },
                stop: function () {
                    window.setTimeout(function () {
                        state.activeDragPayload = null;
                        root.removeAttribute("data-h4bs-active-payload");
                        root.classList.remove("is-dragging-library");
                        setDropTargetsActive(false);
                    }, 80);
                },
            });
        });
    }

    function setDropTargetsActive(active) {
        if (!(els.previewCanvas instanceof HTMLElement)) {
            return;
        }
        const isActive = !!active;
        els.previewCanvas.classList.toggle("is-drop-target-active", isActive);
        els.previewCanvas
            .querySelectorAll("[data-h4bs-section-dropzone]")
            .forEach(function (zone) {
                if (zone instanceof HTMLElement) {
                    zone.classList.toggle("is-drop-target-active", isActive);
                }
            });
    }

    function ignoreLibraryClick(event) {
        const target = event && event.target ? event.target : null;
        if (!(target instanceof HTMLElement)) {
            return false;
        }
        if (target.closest("a,button,input,textarea,select,label")) {
            return true;
        }
        return false;
    }

    function parseDropPayload(raw) {
        if (typeof raw !== "string" || raw.trim() === "") {
            return null;
        }
        try {
            const parsed = JSON.parse(raw);
            return normalizeDropPayload(parsed);
        } catch (_error) {
            return null;
        }
    }

    function normalizeDropPayload(payload) {
        if (!payload || typeof payload !== "object") {
            return null;
        }
        const kind = String(payload.kind || "");
        if (kind === "element") {
            const type = normalizeBlockType(payload.type || "", "");
            if (type === "") {
                return null;
            }
            return {
                kind: "element",
                type: type,
                label: String(payload.label || type),
            };
        }
        if (kind === "widget") {
            const shortcode = String(payload.shortcode || "");
            if (shortcode === "") {
                return null;
            }
            return {
                kind: "widget",
                shortcode: shortcode,
                label: String(payload.label || "Widget"),
            };
        }
        if (kind === "template") {
            const slug = String(payload.slug || "");
            if (slug === "") {
                return null;
            }
            return {
                kind: "template",
                slug: slug,
                label: String(payload.label || "Template"),
            };
        }
        return null;
    }

    function payloadFromSortableItem(uiItem) {
        if (!uiItem || typeof uiItem.attr !== "function") {
            const fromRoot =
                root && typeof root.getAttribute === "function"
                    ? parseDropPayload(
                          String(root.getAttribute("data-h4bs-active-payload") || "")
                      )
                    : null;
            return (
                fromRoot ||
                normalizeDropPayload(state.activeDragPayload)
            );
        }
        const raw = String(uiItem.attr("data-h4bs-drop-payload") || "");
        const parsed = parseDropPayload(raw);
        if (parsed) {
            return parsed;
        }
        const node = uiItem.get && typeof uiItem.get === "function" ? uiItem.get(0) : null;
        if (node instanceof HTMLElement) {
            const fromNode = normalizeDropPayload(buildDragPayloadFromNode(node));
            if (fromNode) {
                return fromNode;
            }
            const nodeRaw = String(node.getAttribute("data-h4bs-drop-payload") || "");
            const nodeParsed = parseDropPayload(nodeRaw);
            if (nodeParsed) {
                return nodeParsed;
            }
        }
        const fromRoot =
            root && typeof root.getAttribute === "function"
                ? parseDropPayload(
                      String(root.getAttribute("data-h4bs-active-payload") || "")
                  )
                : null;
        return fromRoot || normalizeDropPayload(state.activeDragPayload);
    }

    function cleanupDroppedHelpers() {
        if (!els.previewCanvas) {
            return;
        }
        els.previewCanvas
            .querySelectorAll(".h4bs-drag-helper, .h4bs-library-tile")
            .forEach(function (node) {
                if (node instanceof HTMLElement) {
                    node.remove();
                }
            });
    }

    function scheduleDropModalOpen(blockId, attempt) {
        const id = String(blockId || "");
        if (id === "") {
            return;
        }
        const tries = Number.isFinite(Number(attempt)) ? Number(attempt) : 0;
        const maxTries = 10;

        window.setTimeout(function () {
            const modalVisible = !!(els.modal && !els.modal.hidden);
            const currentModalId = String(state.modalBlockId || "");
            if (
                modalVisible &&
                state.modalMode === "block" &&
                currentModalId === id
            ) {
                return;
            }

            // Respect unsaved modal changes if the user chose not to discard.
            if (
                state.modalMode &&
                state.modalDirty &&
                currentModalId !== id
            ) {
                return;
            }

            const target = findBlockById(id);
            if (!target) {
                if (tries < maxTries) {
                    scheduleDropModalOpen(id, tries + 1);
                }
                return;
            }

            state.selectedId = id;
            renderBlockList();
            openBlockModal(id);

            const opened = !!(
                els.modal &&
                !els.modal.hidden &&
                state.modalMode === "block" &&
                String(state.modalBlockId || "") === id
            );
            if (!opened && tries < maxTries) {
                scheduleDropModalOpen(id, tries + 1);
            }
        }, 90 + tries * 80);
    }

    function handleExternalDrop(payload, index, parentId, slot) {
        if (!payload || typeof payload !== "object") {
            return;
        }

        const kind = String(payload.kind || "");
        const insertAt = clampInsertIndex(index);
        const placement = {
            parent_id: String(parentId || ""),
            slot: normalizedSlot(slot || 0),
        };
        if (kind === "element") {
            const inserted = insertElementAt(
                String(payload.type || ""),
                insertAt,
                true,
                placement
            );
            if (inserted && inserted.id) {
                scheduleDropModalOpen(String(inserted.id), 0);
            }
            return;
        }
        if (kind === "widget") {
            const inserted = insertWidgetAt(
                {
                    shortcode: String(payload.shortcode || ""),
                    block_type: String(payload.block_type || ""),
                    slug: String(payload.slug || ""),
                    label: String(payload.label || ""),
                    category: String(payload.category || ""),
                    settings:
                        payload.settings && typeof payload.settings === "object"
                            ? deepClone(payload.settings)
                            : {},
                },
                insertAt,
                true,
                placement
            );
            if (inserted && inserted.id) {
                scheduleDropModalOpen(String(inserted.id), 0);
            }
            return;
        }
        if (kind === "template") {
            if (placement.parent_id !== "") {
                return;
            }
            const template = templateBySlug(String(payload.slug || ""));
            if (!template) {
                return;
            }
            const blocks = insertTemplateAt(template, insertAt, placement);
            if (blocks.length > 0) {
                scheduleDropModalOpen(String(blocks[0].id || ""), 0);
            }
        }
    }

    function normalizeFrameMode(value) {
        return String(value || "").toLowerCase() === "clean"
            ? "clean"
            : "framed";
    }

    function normalizePreviewSizingMode(value) {
        return String(value || "").toLowerCase() === "exact"
            ? "exact"
            : "workspace";
    }

    function readStoredStringList(storageKey, maxLength) {
        try {
            const raw = window.localStorage.getItem(String(storageKey || ""));
            if (!raw) {
                return [];
            }
            const parsed = JSON.parse(raw);
            if (!Array.isArray(parsed)) {
                return [];
            }
            const max = Math.max(1, Number(maxLength || 100));
            const list = [];
            parsed.forEach(function (entry) {
                const value = String(entry || "").trim();
                if (value === "" || list.indexOf(value) >= 0) {
                    return;
                }
                list.push(value);
            });
            return list.slice(0, max);
        } catch (_error) {
            return [];
        }
    }

    function persistStoredStringList(storageKey, values, maxLength) {
        try {
            const key = String(storageKey || "");
            if (key === "") {
                return;
            }
            const max = Math.max(1, Number(maxLength || 100));
            const list = [];
            if (Array.isArray(values)) {
                values.forEach(function (entry) {
                    const value = String(entry || "").trim();
                    if (value === "" || list.indexOf(value) >= 0) {
                        return;
                    }
                    list.push(value);
                });
            }
            if (list.length < 1) {
                window.localStorage.removeItem(key);
                return;
            }
            window.localStorage.setItem(key, JSON.stringify(list.slice(0, max)));
        } catch (_error) {
            return;
        }
    }

    function readStoredWidgetFavorites() {
        return readStoredStringList(WIDGET_FAVORITES_KEY, 400);
    }

    function persistWidgetFavorites() {
        persistStoredStringList(WIDGET_FAVORITES_KEY, state.widgetFavorites, 400);
    }

    function readStoredWidgetRecent() {
        return readStoredStringList(WIDGET_RECENT_KEY, 40);
    }

    function persistWidgetRecent() {
        persistStoredStringList(WIDGET_RECENT_KEY, state.widgetRecent, 40);
    }

    function readStoredWidgetFilter() {
        try {
            const raw = String(window.localStorage.getItem(WIDGET_FILTER_KEY) || "")
                .trim()
                .toLowerCase();
            return ["all", "favorites", "recent"].indexOf(raw) >= 0 ? raw : "all";
        } catch (_error) {
            return "all";
        }
    }

    function persistWidgetFilter() {
        try {
            window.localStorage.setItem(
                WIDGET_FILTER_KEY,
                String(state.widgetFilter || "all")
            );
        } catch (_error) {
            return;
        }
    }

    function readStoredElementFilter() {
        try {
            return normalizeElementFilter(
                String(window.localStorage.getItem(ELEMENT_FILTER_KEY) || "")
            );
        } catch (_error) {
            return "all";
        }
    }

    function persistElementFilter() {
        try {
            window.localStorage.setItem(
                ELEMENT_FILTER_KEY,
                normalizeElementFilter(state.elementFilter)
            );
        } catch (_error) {
            return;
        }
    }

    function isWidgetFavorite(shortcode) {
        const key = String(shortcode || "").trim();
        if (key === "") {
            return false;
        }
        return state.widgetFavorites.indexOf(key) >= 0;
    }

    function toggleWidgetFavorite(shortcode) {
        const key = String(shortcode || "").trim();
        if (key === "") {
            return;
        }
        const idx = state.widgetFavorites.indexOf(key);
        if (idx >= 0) {
            state.widgetFavorites.splice(idx, 1);
        } else {
            state.widgetFavorites.unshift(key);
            if (state.widgetFavorites.length > 400) {
                state.widgetFavorites = state.widgetFavorites.slice(0, 400);
            }
        }
        persistWidgetFavorites();
        renderWidgetLibrary();
    }

    function recordWidgetRecent(shortcode) {
        const key = String(shortcode || "").trim();
        if (key === "") {
            return;
        }
        state.widgetRecent = state.widgetRecent.filter(function (entry) {
            return String(entry || "") !== key;
        });
        state.widgetRecent.unshift(key);
        if (state.widgetRecent.length > 40) {
            state.widgetRecent = state.widgetRecent.slice(0, 40);
        }
        persistWidgetRecent();
    }

    function readStoredStyleClipboard() {
        try {
            const raw = window.localStorage.getItem(STYLE_CLIPBOARD_KEY);
            if (!raw) {
                return null;
            }
            const parsed = JSON.parse(raw);
            if (
                !parsed ||
                typeof parsed !== "object" ||
                !parsed.settings ||
                typeof parsed.settings !== "object"
            ) {
                return null;
            }
            return {
                settings: parsed.settings,
            };
        } catch (_error) {
            return null;
        }
    }

    function persistStyleClipboard() {
        try {
            if (
                !state.styleClipboard ||
                !state.styleClipboard.settings ||
                typeof state.styleClipboard.settings !== "object"
            ) {
                window.localStorage.removeItem(STYLE_CLIPBOARD_KEY);
                return;
            }
            window.localStorage.setItem(
                STYLE_CLIPBOARD_KEY,
                JSON.stringify(state.styleClipboard)
            );
        } catch (_error) {
            return;
        }
    }

    function readStoredFrameMode() {
        try {
            return normalizeFrameMode(window.localStorage.getItem(FRAME_STORAGE_KEY));
        } catch (error) {
            return "framed";
        }
    }

    function readStoredPreviewSizingMode() {
        try {
            return normalizePreviewSizingMode(
                window.localStorage.getItem(PREVIEW_SIZING_STORAGE_KEY)
            );
        } catch (_error) {
            return "workspace";
        }
    }

    function readStoredBoolean(storageKey, fallback) {
        try {
            const stored = window.localStorage.getItem(String(storageKey || ""));
            if (stored === null) {
                return !!fallback;
            }
            return stored === "1";
        } catch (_error) {
            return !!fallback;
        }
    }

    function persistStoredBoolean(storageKey, value) {
        try {
            window.localStorage.setItem(String(storageKey || ""), value ? "1" : "0");
        } catch (_error) {
            return;
        }
    }

    function readStoredNumber(storageKey, fallback, minimum, maximum) {
        const safeFallback = Math.min(maximum, Math.max(minimum, Number(fallback) || minimum));
        try {
            const raw = window.localStorage.getItem(String(storageKey || ""));
            if (raw === null || String(raw).trim() === "") {
                return safeFallback;
            }
            const stored = Number(raw);
            if (!Number.isFinite(stored)) {
                return safeFallback;
            }
            return Math.min(maximum, Math.max(minimum, Math.round(stored)));
        } catch (_error) {
            return safeFallback;
        }
    }

    function persistStoredNumber(storageKey, value) {
        try {
            window.localStorage.setItem(String(storageKey || ""), String(Math.round(Number(value) || 0)));
        } catch (_error) {
            return;
        }
    }

    function persistFrameMode() {
        try {
            window.localStorage.setItem(FRAME_STORAGE_KEY, state.frameMode);
        } catch (error) {
            return;
        }
    }

    function persistPreviewSizingMode() {
        try {
            window.localStorage.setItem(
                PREVIEW_SIZING_STORAGE_KEY,
                state.previewSizingMode
            );
        } catch (_error) {
            return;
        }
    }

    function readStoredParityMode() {
        try {
            return String(window.localStorage.getItem(PARITY_STORAGE_KEY) || "") === "1";
        } catch (_error) {
            return false;
        }
    }

    function persistParityMode() {
        try {
            window.localStorage.setItem(
                PARITY_STORAGE_KEY,
                state.parityMode ? "1" : "0"
            );
        } catch (_error) {
            return;
        }
    }

    function normalizeLibraryTab(value) {
        const key = String(value || "")
            .trim()
            .toLowerCase();
        return ["elements", "templates", "site-kits", "themes", "widgets"].indexOf(key) >= 0
            ? key
            : "elements";
    }

    function readStoredLibraryTab() {
        try {
            return normalizeLibraryTab(
                window.localStorage.getItem(LIBRARY_TAB_KEY)
            );
        } catch (_error) {
            return "elements";
        }
    }

    function persistLibraryTab() {
        try {
            window.localStorage.setItem(
                LIBRARY_TAB_KEY,
                normalizeLibraryTab(state.activeLibraryTab)
            );
        } catch (_error) {
            return;
        }
    }

    function viewportCatalog() {
        if (!Array.isArray(data.viewportPresets)) {
            return [];
        }
        return data.viewportPresets.map(function (viewport) {
            const group = String(viewport.group || "");
            return {
                slug: String(viewport.slug || ""),
                label: String(viewport.label || viewport.slug || "Viewport"),
                width: Math.max(240, Number(viewport.width || 1920)),
                height: Math.max(240, Number(viewport.height || 1080)),
                group: group !== "" ? group : "monitor",
                tier: String(viewport.tier || "Presets"),
            };
        });
    }

    function viewportGroupMeta() {
        return {
            monitor: { label: "Monitors", icon: "dashicons-desktop" },
            tablet: { label: "Tablets", icon: "dashicons-tablet" },
            mobile: { label: "Mobiles", icon: "dashicons-smartphone" },
            tv: { label: "TV", icon: "dashicons-video-alt3" },
        };
    }

    function viewportBySlug(slug) {
        const list = viewportCatalog();
        return (
            list.find(function (viewport) {
                return viewport.slug === String(slug || "");
            }) || null
        );
    }

    function inferViewportGroup(viewport) {
        if (viewport && typeof viewport === "object" && viewport.group) {
            return String(viewport.group);
        }
        return "monitor";
    }

    function selectedViewport() {
        const found = viewportBySlug(state.viewportSlug);
        if (found) {
            return found;
        }

        const byGroup = viewportCatalog().find(function (viewport) {
            return viewport.group === state.viewportGroup;
        });
        if (byGroup) {
            state.viewportSlug = byGroup.slug;
            return byGroup;
        }

        const fallback = viewportCatalog()[0] || {
            slug: "fallback",
            label: "Desktop",
            width: 1920,
            height: 1080,
            group: "monitor",
            tier: "Presets",
        };
        state.viewportSlug = fallback.slug;
        state.viewportGroup = fallback.group;
        return fallback;
    }

    function buildViewportControls() {
        renderViewportIcons();
        renderViewportSelect();
        renderFrameModeButtons();
        renderPreviewSizingButtons();
    }

    function renderViewportIcons() {
        if (!els.viewportIcons) {
            return;
        }

        els.viewportIcons.innerHTML = "";
        const meta = viewportGroupMeta();
        Object.keys(meta).forEach(function (group) {
            const button = document.createElement("button");
            button.type = "button";
            button.className = "h4bs-viewport-icon-btn";
            if (group === state.viewportGroup) {
                button.classList.add("is-active");
            }
            button.setAttribute("data-h4bs-viewport-group", group);
            button.innerHTML =
                "<span class=\"dashicons " +
                escAttr(meta[group].icon) +
                "\"></span><span>" +
                escHtml(meta[group].label) +
                "</span>";
            button.addEventListener("click", function () {
                state.viewportGroup = group;
                const preferredSlugs = {
                    monitor: "fhd_1080p",
                    tablet: "ipad_pro_13",
                    mobile: "iphone_17_pro_max",
                    tv: "tv_4k",
                };
                const preferredViewport = viewportBySlug(preferredSlugs[group] || "");
                const groupViewport =
                    preferredViewport && preferredViewport.group === group
                        ? preferredViewport
                        : viewportCatalog().find(function (viewport) {
                              return viewport.group === group;
                          });
                if (groupViewport) {
                    state.viewportSlug = groupViewport.slug;
                }
                renderViewportIcons();
                renderViewportSelect();
                applyViewport();
                renderPreview();
            });
            els.viewportIcons.appendChild(button);
        });
    }

    function renderViewportSelect() {
        if (!els.viewportSelect) {
            return;
        }

        const list = viewportCatalog().filter(function (viewport) {
            return viewport.group === state.viewportGroup;
        });

        els.viewportSelect.innerHTML = "";
        if (list.length === 0) {
            return;
        }

        const tierGroups = {};
        list.forEach(function (viewport) {
            const tier = viewport.tier || "Presets";
            if (!tierGroups[tier]) {
                tierGroups[tier] = [];
            }
            tierGroups[tier].push(viewport);
        });

        Object.keys(tierGroups).forEach(function (tier) {
            const optGroup = document.createElement("optgroup");
            optGroup.label = tier;
            tierGroups[tier].forEach(function (viewport) {
                const option = document.createElement("option");
                option.value = viewport.slug;
                option.textContent =
                    viewport.label +
                    " (" +
                    viewport.width +
                    "x" +
                    viewport.height +
                    ")";
                if (viewport.slug === state.viewportSlug) {
                    option.selected = true;
                }
                optGroup.appendChild(option);
            });
            els.viewportSelect.appendChild(optGroup);
        });

        const hasSelected = list.some(function (viewport) {
            return viewport.slug === state.viewportSlug;
        });
        if (!hasSelected) {
            state.viewportSlug = list[0].slug;
            els.viewportSelect.value = state.viewportSlug;
        }
    }

    function renderFrameModeButtons() {
        if (!els.frameButtons || els.frameButtons.length === 0) {
            return;
        }
        els.frameButtons.forEach(function (button) {
            const mode = normalizeFrameMode(
                button.getAttribute("data-h4bs-frame-mode")
            );
            button.classList.toggle("is-active", mode === state.frameMode);
            button.setAttribute(
                "aria-pressed",
                mode === state.frameMode ? "true" : "false"
            );
        });
    }

    function renderPreviewSizingButtons() {
        if (!els.previewSizingButtons || els.previewSizingButtons.length === 0) {
            return;
        }
        els.previewSizingButtons.forEach(function (button) {
            const mode = normalizePreviewSizingMode(
                button.getAttribute("data-h4bs-preview-sizing")
            );
            const active = mode === state.previewSizingMode;
            button.classList.toggle("is-active", active);
            button.setAttribute("aria-pressed", active ? "true" : "false");
        });
    }

    function renderParityToggle() {
        if (!(els.parityToggle instanceof HTMLElement)) {
            return;
        }
        els.parityToggle.classList.toggle("is-active", !!state.parityMode);
        els.parityToggle.setAttribute(
            "aria-pressed",
            state.parityMode ? "true" : "false"
        );
        els.parityToggle.setAttribute(
            "title",
            state.parityMode
                ? "Return to editable canvas"
                : "View the current draft with its real theme and frontend assets"
        );
        if (els.parityLabel) {
            els.parityLabel.textContent = state.parityMode
                ? "Return to editing"
                : "View actual draft";
        }
    }

    function applyParityMode() {
        if (state.parityMode) {
            if (state.parityPreviousSizingMode === null) {
                state.parityPreviousSizingMode = state.previewSizingMode;
            }
            state.previewSizingMode = "exact";
        } else if (state.parityPreviousSizingMode !== null) {
            state.previewSizingMode = normalizePreviewSizingMode(state.parityPreviousSizingMode);
            state.parityPreviousSizingMode = null;
        }
        root.classList.toggle("is-parity-mode", !!state.parityMode);
        document.body.classList.toggle("h4bs-parity-mode", !!state.parityMode);
        renderParityToggle();
        renderPreviewSizingButtons();
        applyViewport();
        if (els.parityStatus) {
            els.parityStatus.textContent = state.parityMode
                ? "Preparing current draft..."
                : "Editable canvas: visible";
        }
        updateParitySelectionHelp(
            state.parityMode ? "preparing" : "hidden"
        );
        if (state.parityMode) {
            closeContextMenu();
            if (state.modalMode) {
                commitModalDraftToWorkspace();
                closeBuilderModal(true);
            }
            hideBoxModelOverlay();
        }
        ensureParityPreviewFrame(!!state.parityMode);
        ensureDraftPreviewFrame("", false);
        scheduleMiniPreviewSync(true);
    }

    function parityPreviewUrl() {
        return String(state.draftPreviewUrl || "").trim();
    }

    function toggleCurrentDraftReview() {
        const requestedDraftKey = stableSerialize(previewRequestPayload());
        const currentDraftReady =
            String(state.draftPreviewUrl || "") !== "" &&
            String(state.draftPreviewFingerprint || "") !== "" &&
            !state.previewRenderInFlight &&
            requestedDraftKey === String(state.previewLastSubmittedKey || "");
        if (!state.parityMode && !currentDraftReady) {
            state.parityPendingOpen = true;
            if (els.previewAssetStatus) {
                els.previewAssetStatus.hidden = false;
                els.previewAssetStatus.textContent = "Preparing current draft preview...";
            }
            requestServerPreviewRender(0);
            return;
        }
        state.parityMode = !state.parityMode;
        persistParityMode();
        applyParityMode();
        renderPreview();
    }

    function updateParitySelectionHelp(status, message) {
        const normalized = String(status || "hidden");
        root.setAttribute("data-h4bs-parity-selection", normalized);
        if (!(els.paritySelectionHelp instanceof HTMLElement)) {
            return;
        }
        els.paritySelectionHelp.hidden = normalized === "hidden";
        els.paritySelectionHelp.classList.toggle(
            "is-warning",
            normalized === "warning" || normalized === "error"
        );
        const text = els.paritySelectionHelp.querySelector("span:last-child");
        if (!(text instanceof HTMLElement)) {
            return;
        }
        const defaults = {
            preparing: "Preparing the current draft...",
            ready: "Select any page item to edit it.",
            warning: "That item belongs to a site-wide template. Open Site Parts to edit it.",
            error: "Direct selection is unavailable. Return to editing and retry.",
        };
        text.textContent = String(message || defaults[normalized] || "");
    }

    function ensureParityPreviewFrame(forceReload) {
        if (!els.previewShell) {
            return;
        }
        let frame = els.previewShell.querySelector("[data-h4bs-parity-frame]");
        if (!(frame instanceof HTMLIFrameElement)) {
            frame = document.createElement("iframe");
            frame.className = "h4bs-preview-parity-frame";
            frame.setAttribute("data-h4bs-parity-frame", "1");
            frame.setAttribute("title", "Pixel parity preview");
            frame.setAttribute("loading", "eager");
            frame.setAttribute("referrerpolicy", "strict-origin-when-cross-origin");
            frame.addEventListener("load", function () {
                verifyParityPreviewFrame(frame);
            });
            frame.hidden = true;
            els.previewShell.appendChild(frame);
        }

        const active = !!state.parityMode;
        frame.hidden = !active;
        frame.setAttribute("aria-hidden", active ? "false" : "true");
        if (!active) {
            return;
        }

        const targetUrl = parityPreviewUrl();
        if (targetUrl === "") {
            return;
        }

        const previousUrl = String(frame.getAttribute("data-h4bs-src") || "");
        if (forceReload || previousUrl !== targetUrl) {
            frame.setAttribute("data-h4bs-src", targetUrl);
            frame.setAttribute("data-h4bs-payload-key", String(state.previewLastSubmittedKey || ""));
            frame.removeAttribute("data-h4bs-direct-select-ready");
            updateParitySelectionHelp("preparing");
            if (els.parityStatus) {
                els.parityStatus.textContent = "Preparing current draft...";
            }
            frame.src = targetUrl;
        }
    }

    function verifyParityPreviewFrame(frame) {
        if (!(frame instanceof HTMLIFrameElement) || !state.parityMode) {
            return;
        }
        const acceptedFingerprint = String(state.draftPreviewFingerprint || "").trim();
        const acceptedPayloadKey = String(state.previewLastSubmittedKey || "");
        let loadedFingerprint = "";
        try {
            loadedFingerprint = String(
                new URL(frame.contentWindow.location.href).searchParams.get("h4bs_draft_fingerprint") || ""
            ).trim();
        } catch (error) {
            failCurrentDraftPreview();
            return;
        }
        if (
            acceptedFingerprint === "" ||
            loadedFingerprint !== acceptedFingerprint ||
            String(frame.getAttribute("data-h4bs-payload-key") || "") !== acceptedPayloadKey ||
            stableSerialize(previewRequestPayload()) !== acceptedPayloadKey
        ) {
            failCurrentDraftPreview();
            return;
        }
        auditPreviewFrameAssets(frame, function (assetState) {
            if (!assetState || !assetState.ok || !state.parityMode) {
                failCurrentDraftPreview();
                return;
            }
            if (els.parityStatus) {
                els.parityStatus.textContent = "Actual current draft: select an item to edit";
            }
            if (bindParityPreviewSelection(frame)) {
                updateParitySelectionHelp("ready");
            } else {
                updateParitySelectionHelp("error");
            }
        });
    }

    function selectBlockFromParityFrame(frame, target, clicked) {
        if (!(frame instanceof HTMLIFrameElement) || !state.parityMode) {
            return false;
        }
        const blockId = String(target && target.getAttribute("id") || "").trim();
        const block = findBlockById(blockId);
        if (!block) {
            updateParitySelectionHelp("warning");
            return false;
        }
        try {
            state.draftFrameScrollX = Number(frame.contentWindow.scrollX || 0);
            state.draftFrameScrollY = Number(frame.contentWindow.scrollY || 0);
        } catch (error) {
            state.draftFrameScrollX = 0;
            state.draftFrameScrollY = 0;
        }
        state.selectedId = blockId;
        state.htmlQuickEditTarget = describeHtmlQuickEditTarget(target, clicked);
        root.setAttribute("data-h4bs-parity-selected-block", blockId);
        state.parityMode = false;
        persistParityMode();
        applyParityMode();
        renderBlockList();
        openBlockModal(blockId, {
            htmlQuickEditTarget: state.htmlQuickEditTarget,
        });
        syncDraftFrameSelection(
            els.previewShell
                ? els.previewShell.querySelector("[data-h4bs-draft-frame]")
                : null
        );
        return true;
    }

    function bindParityPreviewSelection(frame) {
        if (!(frame instanceof HTMLIFrameElement) || !state.parityMode) {
            return false;
        }
        try {
            const doc = frame.contentDocument;
            if (!doc || !doc.body) {
                return false;
            }
            doc.documentElement.setAttribute("data-h4bs-studio-draft", "1");
            const selectable = Array.from(doc.querySelectorAll(".h4bs-block[id]"))
                .filter(function (node) {
                    return Boolean(findBlockById(String(node.getAttribute("id") || "")));
                });
            if (selectable.length === 0) {
                return false;
            }
            selectable.forEach(function (node) {
                const block = findBlockById(String(node.getAttribute("id") || ""));
                if (!block) {
                    return;
                }
                node.setAttribute("data-h4bs-parity-selectable", "1");
                if (!node.hasAttribute("tabindex")) {
                    node.setAttribute("tabindex", "0");
                }
                if (!node.hasAttribute("aria-label")) {
                    node.setAttribute(
                        "aria-label",
                        "Edit " + blockLabel(block, Math.max(0, state.layout.indexOf(block)))
                    );
                }
                if (String(block.type || "") === "html") {
                    node.querySelectorAll(
                        "img,a,button,h1,h2,h3,h4,h5,h6,p,li,label,figcaption"
                    ).forEach(function (target) {
                        target.setAttribute("data-h4bs-parity-edit-target", "1");
                        if (!target.hasAttribute("tabindex")) {
                            target.setAttribute("tabindex", "0");
                        }
                        if (!target.hasAttribute("aria-label")) {
                            const tag = String(target.tagName || "item").toLowerCase();
                            const label = tag === "img"
                                ? String(target.getAttribute("alt") || "image").trim()
                                : shortText(String(target.textContent || tag).trim(), 56);
                            target.setAttribute(
                                "aria-label",
                                "Edit " + (label || tag)
                            );
                        }
                    });
                }
            });
            if (doc.body.getAttribute("data-h4bs-parity-bound") !== "1") {
                doc.body.setAttribute("data-h4bs-parity-bound", "1");
                doc.addEventListener("click", function (event) {
                    const clicked = event.target && event.target.nodeType === 1
                        ? event.target
                        : null;
                    const target = clicked ? clicked.closest(".h4bs-block[id]") : null;
                    if (!target || target.nodeType !== 1) {
                        return;
                    }
                    event.preventDefault();
                    event.stopPropagation();
                    if (typeof event.stopImmediatePropagation === "function") {
                        event.stopImmediatePropagation();
                    }
                    selectBlockFromParityFrame(frame, target, clicked);
                }, true);
                doc.addEventListener("keydown", function (event) {
                    if (event.key !== "Enter" && event.key !== " ") {
                        return;
                    }
                    const clicked = event.target && event.target.nodeType === 1
                        ? event.target
                        : null;
                    const target = clicked ? clicked.closest(".h4bs-block[id]") : null;
                    if (!target || target.nodeType !== 1) {
                        return;
                    }
                    event.preventDefault();
                    event.stopPropagation();
                    selectBlockFromParityFrame(frame, target, clicked);
                }, true);
            }
            frame.setAttribute("data-h4bs-direct-select-ready", "1");
            root.setAttribute("data-h4bs-parity-selectable-count", String(selectable.length));
            return true;
        } catch (error) {
            frame.removeAttribute("data-h4bs-direct-select-ready");
            return false;
        }
    }

    function ensureDraftPreviewFrame(url, forceReload) {
        if (!els.previewShell) {
            return null;
        }
        let frame = els.previewShell.querySelector("[data-h4bs-draft-frame]");
        if (!(frame instanceof HTMLIFrameElement)) {
            frame = document.createElement("iframe");
            frame.className = "h4bs-preview-draft-frame";
            frame.setAttribute("data-h4bs-draft-frame", "1");
            frame.setAttribute("title", "Editable frontend draft preview");
            frame.setAttribute("loading", "eager");
            frame.setAttribute("referrerpolicy", "same-origin");
            frame.addEventListener("load", function () {
                bindDraftPreviewFrame(frame);
            });
            els.previewShell.appendChild(frame);
        }
        frame.hidden = !!state.parityMode;
        frame.setAttribute("aria-hidden", state.parityMode ? "true" : "false");
        const target = String(url || "").trim();
        if (!state.parityMode && target !== "") {
            const previous = String(frame.getAttribute("data-h4bs-src") || "");
            if (forceReload || previous !== target) {
                try {
                    state.draftFrameScrollX = Number(frame.contentWindow.scrollX || 0);
                    state.draftFrameScrollY = Number(frame.contentWindow.scrollY || 0);
                } catch (error) {
                    state.draftFrameScrollX = 0;
                    state.draftFrameScrollY = 0;
                }
                frame.setAttribute("data-h4bs-src", target);
                state.previewLoadStartedAt = window.performance.now();
                frame.src = target;
            }
        }
        return frame;
    }

    function bindDraftPreviewFrame(frame) {
        if (!(frame instanceof HTMLIFrameElement) || state.parityMode) {
            return;
        }
        try {
            const doc = frame.contentDocument;
            if (!doc || !doc.body) {
                throw new Error("Draft document unavailable");
            }
            root.setAttribute("data-h4bs-draft-preview", "ready");
            syncInspectorPreviewStatus("ready");
            doc.documentElement.setAttribute("data-h4bs-studio-draft", "1");
            if (doc.body.getAttribute("data-h4bs-studio-bound") !== "1") {
                doc.body.setAttribute("data-h4bs-studio-bound", "1");
                doc.addEventListener("click", function (event) {
                    if (els.toolsMenu && els.toolsMenu.open) {
                        els.toolsMenu.open = false;
                    }
                    const clicked = event.target && event.target.nodeType === 1
                        ? event.target
                        : null;
                    const target = clicked
                        ? clicked.closest(".h4bs-block[id]")
                        : null;
                    if (!target || target.nodeType !== 1) {
                        return;
                    }
                    const blockId = String(target.getAttribute("id") || "");
                    if (blockId === "" || !findBlockById(blockId)) {
                        return;
                    }
                    event.preventDefault();
                    event.stopPropagation();
                    if (typeof event.stopImmediatePropagation === "function") {
                        event.stopImmediatePropagation();
                    }
                    state.selectedId = blockId;
                    state.htmlQuickEditTarget = describeHtmlQuickEditTarget(
                        target,
                        clicked
                    );
                    renderBlockList();
                    openBlockModal(blockId, {
                        htmlQuickEditTarget: state.htmlQuickEditTarget,
                    });
                    syncDraftFrameSelection(frame);
                }, true);
                doc.addEventListener("dblclick", function (event) {
                    const clicked = event.target && event.target.nodeType === 1
                        ? event.target
                        : null;
                    const target = clicked
                        ? clicked.closest(".h4bs-block[id]")
                        : null;
                    const blockId = target && target.nodeType === 1
                        ? String(target.getAttribute("id") || "")
                        : "";
                    if (blockId !== "" && findBlockById(blockId)) {
                        event.preventDefault();
                        event.stopPropagation();
                        if (typeof event.stopImmediatePropagation === "function") {
                            event.stopImmediatePropagation();
                        }
                        openBlockModal(blockId, {
                            htmlQuickEditTarget: describeHtmlQuickEditTarget(
                                target,
                                clicked
                            ),
                        });
                    }
                }, true);
            }
            syncDraftFrameSelection(frame);
            applyImmediateDraftPreview(frame);
            captureDraftPreviewPerformance(frame);
            auditPreviewFrameAssets(frame);
            window.requestAnimationFrame(function () {
                try {
                    frame.contentWindow.scrollTo(
                        Number(state.draftFrameScrollX || 0),
                        Number(state.draftFrameScrollY || 0)
                    );
                } catch (error) {
                    // Same-origin previews restore position; rewritten hosts fall back naturally.
                }
            });
        } catch (error) {
            root.setAttribute("data-h4bs-draft-preview", "fallback");
            syncInspectorPreviewStatus("fallback");
        }
    }

    function captureDraftPreviewPerformance(frame) {
        if (!(frame instanceof HTMLIFrameElement)) {
            return;
        }
        window.setTimeout(function () {
            try {
                const framePerformance = frame.contentWindow && frame.contentWindow.performance;
                const navigation = framePerformance
                    ? framePerformance.getEntriesByType("navigation")[0]
                    : null;
                const elapsed = Math.max(
                    0,
                    window.performance.now() - Number(state.previewLoadStartedAt || 0)
                );
                const measured = navigation && Number(navigation.duration || 0) > 0
                    ? Number(navigation.duration || 0)
                    : elapsed;
                const responseStart = navigation ? Number(navigation.responseStart || 0) : 0;
                const requestStart = navigation ? Number(navigation.requestStart || 0) : 0;
                const responseEnd = navigation ? Number(navigation.responseEnd || 0) : 0;
                const domComplete = navigation
                    ? Number(navigation.domComplete || navigation.loadEventEnd || measured)
                    : measured;
                state.previewMeasuredMs = Math.max(1, Math.round(measured));
                state.previewMeasuredTtfbMs = Math.max(
                    0,
                    Math.round(responseStart - requestStart)
                );
                state.previewMeasuredRenderMs = Math.max(
                    0,
                    Math.round(domComplete - responseEnd)
                );
                root.setAttribute(
                    "data-h4bs-preview-measured-ms",
                    String(state.previewMeasuredMs)
                );
                root.setAttribute(
                    "data-h4bs-preview-ttfb-ms",
                    String(state.previewMeasuredTtfbMs)
                );
                root.setAttribute(
                    "data-h4bs-preview-render-ms",
                    String(state.previewMeasuredRenderMs)
                );
                updateEstimate();
            } catch (error) {
                // Cross-origin rewrites keep the previous estimate without breaking Studio.
            }
        }, 0);
    }

    function auditPreviewFrameAssets(frame, onComplete) {
        if (!(frame instanceof HTMLIFrameElement)) {
            return;
        }
        window.setTimeout(function () {
            try {
                const doc = frame.contentDocument;
                const perf = frame.contentWindow && frame.contentWindow.performance;
                if (!doc || !perf) {
                    return;
                }
                const failed = [];
                perf.getEntriesByType("resource").forEach(function (entry) {
                    const status = Number(entry && entry.responseStatus ? entry.responseStatus : 0);
                    if (status >= 400) {
                        failed.push(String(entry.name || "page asset"));
                    }
                });
                doc.querySelectorAll("img[src]").forEach(function (img) {
                    if (img.complete && Number(img.naturalWidth || 0) === 0) {
                        failed.push(String(img.currentSrc || img.src || "image"));
                    }
                });
                doc.querySelectorAll("link[rel~='stylesheet']").forEach(function (link) {
                    if (!link.sheet) {
                        failed.push(String(link.href || "stylesheet"));
                    }
                });
                const unique = Array.from(new Set(failed));
                root.setAttribute("data-h4bs-preview-asset-failures", String(unique.length));
                if (unique.length > 0) {
                    root.setAttribute("data-h4bs-preview-assets", "incomplete");
                    if (els.previewAssetStatus) {
                        els.previewAssetStatus.hidden = false;
                        els.previewAssetStatus.textContent =
                            "Preview incomplete: " + unique.length + " page asset(s) failed. Reload before reviewing layout.";
                    }
                    syncInspectorPreviewStatus("incomplete", unique.length);
                    if (typeof onComplete === "function") {
                        onComplete({ ok: false, failures: unique });
                    }
                } else {
                    root.setAttribute("data-h4bs-preview-assets", "ready");
                    if (els.previewAssetStatus) {
                        els.previewAssetStatus.hidden = true;
                        els.previewAssetStatus.textContent = "";
                    }
                    syncInspectorPreviewStatus("ready");
                    if (typeof onComplete === "function") {
                        onComplete({ ok: true, failures: [] });
                    }
                }
            } catch (error) {
                root.setAttribute("data-h4bs-preview-assets", "unavailable");
                if (els.previewAssetStatus) {
                    els.previewAssetStatus.hidden = false;
                    els.previewAssetStatus.textContent =
                        "Preview assets could not be verified. Reload before reviewing layout.";
                }
                if (typeof onComplete === "function") {
                    onComplete({ ok: false, failures: ["unavailable"] });
                }
            }
        }, 80);
    }

    function syncDraftFrameSelection(frame) {
        if (!(frame instanceof HTMLIFrameElement)) {
            return;
        }
        try {
            const doc = frame.contentDocument;
            if (!doc) {
                return;
            }
            doc.querySelectorAll(".h4bs-block[data-h4bs-studio-selected]").forEach(function (node) {
                node.removeAttribute("data-h4bs-studio-selected");
            });
            doc.querySelectorAll("[data-h4bs-studio-selected-inner]").forEach(function (node) {
                node.removeAttribute("data-h4bs-studio-selected-inner");
            });
            const selectedId = String(state.selectedId || "");
            if (selectedId !== "") {
                const selected = doc.getElementById(selectedId);
                if (selected) {
                    selected.setAttribute("data-h4bs-studio-selected", "1");
                    const descriptor = state.htmlQuickEditTarget;
                    const tag = String(
                        descriptor && descriptor.tag ? descriptor.tag : ""
                    ).toLowerCase();
                    const index = Math.max(
                        0,
                        Number(descriptor && descriptor.index ? descriptor.index : 0)
                    );
                    if (
                        /^(?:img|a|button|h[1-6]|p|li|label|figcaption|span)$/.test(tag)
                    ) {
                        const innerTargets = selected.querySelectorAll(tag);
                        if (innerTargets[index] && innerTargets[index].nodeType === 1) {
                            innerTargets[index].setAttribute(
                                "data-h4bs-studio-selected-inner",
                                "1"
                            );
                        }
                    }
                }
            }
        } catch (error) {
            // The signed preview is same-origin; fall back cleanly if a host rewrites it.
        }
    }

    function globalDesignLiveDeclarations(rawTokens) {
        const tokens = normalizeGlobalDesignTokens(rawTokens || {});
        const declarations = {};
        const colors = tokens.colors && typeof tokens.colors === "object" ? tokens.colors : {};
        const fonts = tokens.fonts && typeof tokens.fonts === "object" ? tokens.fonts : {};
        const typography =
            tokens.typography && typeof tokens.typography === "object" ? tokens.typography : {};
        const spacing = tokens.spacing && typeof tokens.spacing === "object" ? tokens.spacing : {};
        const shape = tokens.shape && typeof tokens.shape === "object" ? tokens.shape : {};
        const components =
            tokens.components && typeof tokens.components === "object" ? tokens.components : {};
        const layout = tokens.layout && typeof tokens.layout === "object" ? tokens.layout : {};

        Object.keys(colors).forEach(function (key) {
            const value = String(colors[key] || "").trim();
            if (/^#[0-9a-f]{6}$/i.test(value)) {
                declarations["--h4bs-color-" + String(key).replace(/_/g, "-")] = value;
            }
        });
        ["display", "heading", "body", "ui"].forEach(function (key) {
            const family = cssSafeToken(fonts[key] || "").replace(/'/g, "");
            if (family !== "") {
                declarations["--h4bs-font-" + key] = "'" + family + "',sans-serif";
            }
        });

        const dimensions = {
            "base-size": [fonts.base_size || "16", "px"],
            "h1-size": [typography.h1_size || "56", "px"],
            "h2-size": [typography.h2_size || "42", "px"],
            "h3-size": [typography.h3_size || "32", "px"],
            "h4-size": [typography.h4_size || "25", "px"],
            "h5-size": [typography.h5_size || "20", "px"],
            "h6-size": [typography.h6_size || "17", "px"],
            "page-gap": [spacing.page_gap || "16", "px"],
            "section-x": [spacing.section_x || "24", "px"],
            "section-y": [spacing.section_y || "64", "px"],
            "card-gap": [spacing.card_gap || "20", "px"],
            "radius-sm": [shape.radius_sm || "4", "px"],
            "radius-md": [shape.radius_md || "8", "px"],
            "radius-lg": [shape.radius_lg || "16", "px"],
            "button-padding-x": [components.button_padding_x || "20", "px"],
            "button-padding-y": [components.button_padding_y || "12", "px"],
            "button-radius": [components.button_radius || "8", "px"],
            "card-padding": [components.card_padding || "28", "px"],
            "field-height": [components.field_height || "46", "px"],
            "field-padding-x": [components.field_padding_x || "14", "px"],
            "field-radius": [components.field_radius || "6", "px"],
        };
        Object.keys(dimensions).forEach(function (key) {
            const parts = dimensions[key];
            const value = cssDimension(parts[0], parts[1], "");
            if (value !== "") {
                declarations["--h4bs-" + key] = value;
            }
        });

        {
            const rawValues = {
                "heading-weight": typography.heading_weight || "700",
                "body-weight": typography.body_weight || "400",
                "heading-line-height": typography.heading_line_height || "1.12",
                "body-line-height": typography.body_line_height || "1.65",
                "button-weight": components.button_weight || "700",
                "shadow-sm": shape.shadow_sm || "",
                "shadow-md": shape.shadow_md || "",
            };
            Object.keys(rawValues).forEach(function (key) {
                const value = cssSafeToken(rawValues[key]);
                if (value !== "") {
                    declarations["--h4bs-" + key] = value;
                }
            });
        }

        const containerWidth = cssDimension(
            layout.container_max_width || "1200",
            layout.container_max_width_unit || "px",
            "1200px"
        );
        if (containerWidth !== "") {
            declarations["--h4bs-container-max-width"] = containerWidth;
        }
        return declarations;
    }

    function isElementNode(node) {
        return !!node && node.nodeType === 1 && !!node.style;
    }

    function applyLiveDeclarations(element, declarations, attributeName) {
        if (!isElementNode(element)) {
            return;
        }
        const marker = String(attributeName || "data-h4bs-studio-live-properties");
        String(element.getAttribute(marker) || "")
            .split("|")
            .filter(Boolean)
            .forEach(function (property) {
                element.style.removeProperty(property);
            });
        const keys = Object.keys(declarations || {});
        keys.forEach(function (property) {
            element.style.setProperty(property, String(declarations[property] || ""));
        });
        element.setAttribute(marker, keys.join("|"));
    }

    function applyLiveCssText(element, cssText, baselineAttribute) {
        if (!isElementNode(element)) {
            return;
        }
        const baselineKey = String(
            baselineAttribute || "data-h4bs-studio-live-baseline-style"
        );
        if (!element.hasAttribute(baselineKey)) {
            element.setAttribute(baselineKey, String(element.getAttribute("style") || ""));
        }
        element.setAttribute("style", String(element.getAttribute(baselineKey) || ""));
        const probe = element.ownerDocument.createElement("div");
        probe.style.cssText = String(cssText || "");
        for (let index = 0; index < probe.style.length; index += 1) {
            const property = probe.style.item(index);
            element.style.setProperty(
                property,
                probe.style.getPropertyValue(property),
                probe.style.getPropertyPriority(property)
            );
        }
    }

    function syncDraftFrameBlockClasses(target, block) {
        if (!isElementNode(target) || !block) {
            return;
        }
        const settings = block.settings && typeof block.settings === "object" ? block.settings : {};
        Array.from(target.classList).forEach(function (className) {
            if (
                className.indexOf("h4bs-style-preset-") === 0 ||
                className.indexOf("h4bs-motion-entrance-") === 0 ||
                className.indexOf("h4bs-motion-hover-") === 0 ||
                className.indexOf("h4bs-motion-background-") === 0 ||
                className.indexOf("h4bs-motion-trigger-") === 0 ||
                className.indexOf("h4bs-motion-reduced-") === 0 ||
                className.indexOf("h4bs-heading-h") === 0 ||
                className === "h4bs-has-motion"
            ) {
                target.classList.remove(className);
            }
        });
        const preset = safeSelectToken(
            settings.design_style_preset || "",
            ["button_primary", "button_secondary", "button_outline", "button_ghost", "card", "card_elevated", "card_soft", "callout"],
            ""
        );
        if (preset !== "") {
            target.classList.add("h4bs-style-preset-" + preset.replace(/_/g, "-"));
        }
        [
            ["design_motion_entrance", "h4bs-motion-entrance-"],
            ["design_motion_hover", "h4bs-motion-hover-"],
            ["design_motion_background", "h4bs-motion-background-"],
        ].forEach(function (entry) {
            const allowed = entry[0] === "design_motion_entrance"
                ? ["fade_up", "fade_down", "fade_left", "fade_right", "zoom_in"]
                : entry[0] === "design_motion_hover"
                    ? ["lift", "grow", "tilt", "glow"]
                    : ["drift_x", "drift_y", "pulse"];
            const value = safeSelectToken(settings[entry[0]] || "", allowed, "");
            if (value !== "") {
                target.classList.add(entry[1] + value.replace(/_/g, "-"));
            }
        });
        if (
            String(settings.design_motion_entrance || "").trim() !== "" ||
            String(settings.design_motion_background || "").trim() !== ""
        ) {
            target.classList.add("h4bs-has-motion");
            target.classList.add(
                "h4bs-motion-trigger-" +
                    safeSelectToken(
                        settings.design_motion_trigger || "page_load",
                        ["page_load", "in_view", "interaction"],
                        "page_load"
                    ).replace(/_/g, "-")
            );
        }
        target.classList.add(
            "h4bs-motion-reduced-" +
                safeSelectToken(
                    settings.design_motion_reduced || "respect",
                    ["respect", "disable", "allow"],
                    "respect"
                )
        );
        if (String(block.type || "") === "heading") {
            target.classList.add(
                "h4bs-heading-" + sanitizeHeadingTag(String(settings.tag || "h2"))
            );
        }
    }

    function replaceElementTag(element, tagName) {
        if (!isElementNode(element)) {
            return null;
        }
        const tag = String(tagName || "div").toLowerCase();
        if (String(element.tagName || "").toLowerCase() === tag) {
            return element;
        }
        const replacement = element.ownerDocument.createElement(tag);
        Array.from(element.attributes).forEach(function (attribute) {
            replacement.setAttribute(attribute.name, attribute.value);
        });
        while (element.firstChild) {
            replacement.appendChild(element.firstChild);
        }
        element.replaceWith(replacement);
        return replacement;
    }

    function syncDraftFrameBlockContent(target, block) {
        if (!isElementNode(target) || !block) {
            return;
        }
        const settings = block.settings && typeof block.settings === "object" ? block.settings : {};
        const type = String(block.type || "text");
        if (type === "html") {
            syncDraftFrameHtmlQuickEdit(target, block, settings);
            return;
        }
        if (type === "heading") {
            let heading = target.querySelector("h1,h2,h3,h4,h5,h6");
            heading = replaceElementTag(heading, sanitizeHeadingTag(String(settings.tag || "h2")));
            if (heading) {
                heading.textContent = String(settings.text || "Heading");
            }
            return;
        }
        if (type === "text") {
            const paragraph = target.querySelector("p");
            if (paragraph) {
                paragraph.textContent = String(settings.text || "");
            }
            return;
        }
        if (type === "button") {
            const button = target.querySelector("a.h4bs-builder-button, a.h4bs-preview-button");
            if (isElementNode(button)) {
                button.textContent = String(settings.label || "Button");
                button.setAttribute("href", String(settings.url || "#"));
                const designSettings = previewDesignSettingsForBlock(block, settings);
                applyLiveCssText(
                    button,
                    previewDesignStyle(buttonElementDesignSettings(designSettings)),
                    "data-h4bs-studio-live-button-style"
                );
            }
            return;
        }
        if (type === "image") {
            const image = target.querySelector("img");
            if (isElementNode(image)) {
                const src = String(settings.src || settings.url || "").trim();
                if (src !== "") {
                    image.src = src;
                }
                image.alt = String(settings.alt || "");
                image.title = String(settings.title || "");
            }
            const caption = target.querySelector("figcaption");
            if (caption) {
                caption.textContent = String(settings.caption || "");
            }
            return;
        }
        if (type === "list") {
            const list = target.querySelector("ul,ol");
            if (!list) {
                return;
            }
            const ordered = toBool(settings.ordered || "0", false);
            const resolvedList = replaceElementTag(list, ordered ? "ol" : "ul");
            if (!resolvedList) {
                return;
            }
            const raw = normalizeMultilineDelimiters(settings.items || "");
            const values = raw.split(/\r\n|\r|\n|\|/).map(function (item) {
                return item.trim();
            }).filter(Boolean);
            resolvedList.replaceChildren();
            values.forEach(function (value) {
                const item = resolvedList.ownerDocument.createElement("li");
                item.textContent = value;
                resolvedList.appendChild(item);
            });
            return;
        }
        if (type === "quote") {
            const quote = target.querySelector("blockquote p");
            const cite = target.querySelector("blockquote cite");
            if (quote) {
                quote.textContent = String(settings.text || "");
            }
            if (cite) {
                cite.textContent = String(settings.cite || "");
            }
            return;
        }
        if (type === "cta") {
            let title = target.querySelector(".h4bs-builder-cta h2, .h4bs-builder-cta h3, .h4bs-builder-cta h4, .h4bs-builder-cta h5, .h4bs-builder-cta h6");
            const text = target.querySelector(".h4bs-builder-cta p");
            const button = target.querySelector(".h4bs-builder-cta a");
            if (title) {
                title = replaceElementTag(title, sanitizeCtaHeadingTag(String(settings.heading_tag || "h3")));
                title.textContent = String(settings.title || "");
            }
            if (text) {
                text.textContent = String(settings.text || "");
            }
            if (button) {
                button.textContent = String(settings.button_label || "Learn More");
                button.setAttribute("href", String(settings.button_url || "#"));
            }
            return;
        }
        if (type === "counter") {
            const value = target.querySelector(".h4bs-builder-counter strong");
            const label = target.querySelector(".h4bs-builder-counter span");
            if (value) {
                value.textContent =
                    String(settings.prefix || "") +
                    String(Number(settings.value || 0) || 0) +
                    String(settings.suffix || "");
            }
            if (label) {
                label.textContent = String(settings.label || "");
            }
            return;
        }
        if (type === "progress") {
            const max = Math.max(1, Number(settings.max || 100) || 100);
            const value = Math.max(0, Math.min(max, Number(settings.value || 0) || 0));
            const percent = Math.round((value / max) * 100);
            const labels = target.querySelectorAll(".h4bs-builder-progress-head span");
            if (labels[0]) {
                labels[0].textContent = String(settings.label || "Progress");
            }
            if (labels[1]) {
                labels[1].textContent = String(percent) + "%";
            }
            const bar = target.querySelector(".h4bs-builder-progress-track i");
            if (isElementNode(bar)) {
                bar.style.width = String(percent) + "%";
            }
        }
    }

    function syncDraftFrameHtmlQuickEdit(target, block, settings) {
        if (
            !isElementNode(target) ||
            !block ||
            String(block.id || "") !== String(state.modalBlockId || "") ||
            !state.htmlQuickEditTarget
        ) {
            return false;
        }
        const snapshot = htmlQuickEditSnapshot(
            String(settings && settings.html ? settings.html : ""),
            state.htmlQuickEditTarget
        );
        if (!snapshot) {
            return false;
        }

        const selectedNodes = Array.from(target.querySelectorAll(snapshot.tag));
        const selected = selectedNodes[snapshot.index] || null;
        if (!isElementNode(selected)) {
            return false;
        }
        if (snapshot.tag === "img") {
            const safeSource = safeHtmlQuickEditUrl(snapshot.src, false);
            if (safeSource !== null) {
                selected.setAttribute("src", safeSource);
            }
            selected.setAttribute("alt", snapshot.alt);
        } else if (snapshot.simpleText) {
            selected.innerHTML = String(snapshot.simpleHtml || "");
        }

        if (snapshot.anchorIndex >= 0) {
            const anchors = Array.from(target.querySelectorAll("a"));
            const anchor = anchors[snapshot.anchorIndex] || null;
            const safeHref = safeHtmlQuickEditUrl(snapshot.href, true);
            if (isElementNode(anchor) && safeHref !== null) {
                anchor.setAttribute("href", safeHref);
            }
        }
        return true;
    }

    function syncDraftFrameBlock(target, block) {
        if (!isElementNode(target) || !block) {
            return;
        }
        const settings = block.settings && typeof block.settings === "object" ? block.settings : {};
        const designSettings = previewDesignSettingsForBlock(block, settings);
        const wrapperSettings = String(block.type || "") === "button"
            ? buttonWrapperDesignSettings(designSettings)
            : designSettings;
        applyLiveCssText(target, previewDesignStyle(wrapperSettings));
        syncDraftFrameBlockClasses(target, block);
        syncDraftFrameBlockContent(target, block);

        if (String(block.type || "") === "section") {
            const grid = target.querySelector(".h4bs-builder-section-grid");
            if (isElementNode(grid)) {
                const defaults = structureLayoutDefaults();
                const context = sectionLayoutContext(settings, {
                    columns: defaults.columns,
                    gap: defaults.gap,
                    minHeight: defaults.min_height,
                    minHeightMin: 80,
                    minHeightMax: 1800,
                    layoutMode: defaults.layout_mode,
                    contentWidthMode: defaults.content_width_mode,
                    flexDirection: defaults.flex_direction,
                    flexWrap: defaults.flex_wrap,
                    justifyContent: defaults.justify_content,
                    alignItems: defaults.align_items,
                    alignContent: defaults.align_content,
                });
                grid.classList.remove("is-grid", "is-flex");
                grid.classList.add("is-" + context.modeClass);
                applyLiveCssText(
                    grid,
                    context.style,
                    "data-h4bs-studio-live-section-style"
                );
            }
        }
        target.setAttribute("data-h4bs-studio-live", "1");
    }

    function applyImmediateDraftPreview(explicitFrame) {
        if (state.parityMode || !els.previewShell) {
            return false;
        }
        const frame = explicitFrame instanceof HTMLIFrameElement
            ? explicitFrame
            : els.previewShell.querySelector("[data-h4bs-draft-frame]");
        if (!(frame instanceof HTMLIFrameElement)) {
            return false;
        }
        try {
            const doc = frame.contentDocument;
            if (!doc || !doc.body) {
                return false;
            }
            const payload = previewRequestPayload();
            const declarations = globalDesignLiveDeclarations(payload.globalDesignTokens);
            const pageLayout = normalizePageLayout(payload.pageLayout);
            doc.querySelectorAll(".h4bs-builder-page").forEach(function (pageRoot) {
                if (!isElementNode(pageRoot)) {
                    return;
                }
                ["default", "full_width", "canvas"].forEach(function (layoutName) {
                    pageRoot.classList.toggle(
                        "h4bs-builder-page-layout-" + layoutName,
                        layoutName === pageLayout
                    );
                });
                applyLiveDeclarations(pageRoot, declarations);
            });
            payload.layout.forEach(function (block) {
                const blockId = String(block && block.id ? block.id : "");
                if (blockId === "") {
                    return;
                }
                const target = doc.getElementById(blockId);
                if (isElementNode(target)) {
                    syncDraftFrameBlock(target, block);
                }
            });
            doc.documentElement.setAttribute(
                "data-h4bs-studio-live-revision",
                String(state.previewRenderRevision || 0)
            );
            root.setAttribute("data-h4bs-live-preview", "applied");
            syncDraftFrameSelection(frame);
            return true;
        } catch (error) {
            root.setAttribute("data-h4bs-live-preview", "fallback");
            return false;
        }
    }

    function styleSourceForProperty(doc, element, property) {
        if (!doc || !element || element.nodeType !== 1) {
            return "unknown";
        }
        let source = "browser/theme inheritance";
        Array.from(doc.styleSheets || []).forEach(function (sheet) {
            let rules = [];
            try {
                rules = Array.from(sheet.cssRules || []);
            } catch (error) {
                return;
            }
            rules.forEach(function (rule) {
                if (!rule || !rule.selectorText || !rule.style) {
                    return;
                }
                if (String(rule.style.getPropertyValue(property) || "").trim() === "") {
                    return;
                }
                try {
                    if (element.matches(String(rule.selectorText))) {
                        source = String(sheet.href || "inline style") + " :: " + String(rule.selectorText);
                    }
                } catch (error) {
                    // Ignore selectors that cannot be evaluated by Element.matches().
                }
            });
        });
        if (element.style && String(element.style.getPropertyValue(property) || "").trim() !== "") {
            source = "element inline style";
        }
        return source;
    }

    function loadPublicComparisonFrame() {
        return new Promise(function (resolve, reject) {
            if (!els.previewShell) {
                reject(new Error("Preview shell unavailable"));
                return;
            }
            let frame = els.previewShell.querySelector("[data-h4bs-compare-frame]");
            if (!(frame instanceof HTMLIFrameElement)) {
                frame = document.createElement("iframe");
                frame.setAttribute("data-h4bs-compare-frame", "1");
                frame.setAttribute("title", "Public style comparison document");
                frame.style.position = "fixed";
                frame.style.left = "-100000px";
                frame.style.top = "0";
                frame.style.opacity = "0";
                frame.style.pointerEvents = "none";
                els.previewShell.appendChild(frame);
            }
            const draftFrame = els.previewShell.querySelector("[data-h4bs-draft-frame]");
            const draftWidth = draftFrame instanceof HTMLIFrameElement
                ? Math.max(320, Number(draftFrame.clientWidth || 0))
                : 1440;
            const draftHeight = draftFrame instanceof HTMLIFrameElement
                ? Math.max(480, Number(draftFrame.clientHeight || 0))
                : 900;
            frame.style.width = String(draftWidth) + "px";
            frame.style.height = String(draftHeight) + "px";
            const url = parityPreviewUrl();
            if (url === "") {
                reject(new Error("Public preview URL unavailable"));
                return;
            }
            const finish = function () {
                frame.removeEventListener("load", finish);
                resolve(frame);
            };
            frame.addEventListener("load", finish);
            frame.src = url + (url.indexOf("?") >= 0 ? "&" : "?") + "h4bs_compare=" + String(Date.now());
            window.setTimeout(function () {
                frame.removeEventListener("load", finish);
                if (frame.contentDocument && frame.contentDocument.readyState === "complete") {
                    resolve(frame);
                } else {
                    reject(new Error("Public comparison timed out"));
                }
            }, 12000);
        });
    }

    function comparePreviewParity() {
        const draftFrame = els.previewShell
            ? els.previewShell.querySelector("[data-h4bs-draft-frame]")
            : null;
        if (!(draftFrame instanceof HTMLIFrameElement) || !draftFrame.contentDocument) {
            window.alert("The draft preview is not ready yet.");
            return;
        }
        loadPublicComparisonFrame()
            .then(function (publicFrame) {
                const draftDoc = draftFrame.contentDocument;
                const publicDoc = publicFrame.contentDocument;
                if (!draftDoc || !publicDoc) {
                    throw new Error("Comparison documents unavailable");
                }
                const selectedId = String(state.selectedId || "");
                const surfaceSelectors = [
                    selectedId !== "" ? "#" + window.CSS.escape(selectedId) : "",
                    ".h4bs-block-heading h1, .h4bs-block-heading h2",
                    ".h4bs-builder-button, [data-h4bs-role='button']",
                    "[data-h4bs-skin~='card'], .h4bs-skin-card",
                    "[data-h4bs-role='form'], .h4bs-form, form",
                    "[data-h4bs-module]",
                ].filter(function (selector) {
                    return selector !== "";
                });
                const properties = [
                    "display", "width", "max-width", "font-family", "font-size",
                    "font-weight", "line-height", "color", "background-color",
                    "padding-top", "padding-right", "padding-bottom", "padding-left",
                    "gap", "border-radius", "align-items", "justify-content",
                ];
                const surfaces = [];
                surfaceSelectors.forEach(function (selector) {
                    const draftElement = draftDoc.querySelector(selector);
                    const publicElement = publicDoc.querySelector(selector);
                    if (!draftElement || draftElement.nodeType !== 1 || !publicElement || publicElement.nodeType !== 1) {
                        return;
                    }
                    const draftStyle = draftDoc.defaultView.getComputedStyle(draftElement);
                    const publicStyle = publicDoc.defaultView.getComputedStyle(publicElement);
                    const differences = [];
                    properties.forEach(function (property) {
                        const draftValue = String(draftStyle.getPropertyValue(property) || "").trim();
                        const publicValue = String(publicStyle.getPropertyValue(property) || "").trim();
                        if (draftValue !== publicValue) {
                            differences.push({
                                property: property,
                                draft: draftValue,
                                public: publicValue,
                                draft_source: styleSourceForProperty(draftDoc, draftElement, property),
                                public_source: styleSourceForProperty(publicDoc, publicElement, property),
                            });
                        }
                    });
                    surfaces.push({ selector: selector, differences: differences });
                });
                const report = {
                    generated_at: new Date().toISOString(),
                    post_id: Number(data.postId || 0),
                    viewport: String(state.viewportSlug || ""),
                    surfaces: surfaces,
                    pass: surfaces.length > 0 && surfaces.every(function (surface) {
                        return surface.differences.length === 0;
                    }),
                };
                const differenceCount = surfaces.reduce(function (total, surface) {
                    return total + surface.differences.length;
                }, 0);
                let reportNode = root.querySelector("[data-h4bs-parity-report]");
                if (!(reportNode instanceof HTMLElement)) {
                    reportNode = document.createElement("pre");
                    reportNode.hidden = true;
                    reportNode.setAttribute("data-h4bs-parity-report", "1");
                    root.appendChild(reportNode);
                }
                reportNode.textContent = JSON.stringify(report, null, 2);
                root.setAttribute("data-h4bs-parity-result", report.pass ? "pass" : "fail");
                root.setAttribute("data-h4bs-parity-surfaces", String(surfaces.length));
                root.setAttribute("data-h4bs-parity-differences", String(differenceCount));
                window.h4bsLastParityReport = report;
                return copyTextToClipboard(JSON.stringify(report, null, 2)).catch(function () {
                    return false;
                }).then(function () {
                    window.alert(
                        report.pass
                            ? "Draft and public computed styles match. Report copied."
                            : String(differenceCount) + " computed-style differences found. Report copied with source attribution."
                    );
                });
            })
            .catch(function () {
                root.setAttribute("data-h4bs-parity-result", "error");
                window.alert("The public comparison document could not be loaded.");
            });
    }

    function initQuickHelp() {
        if (!els.quickHelp || String(els.quickHelp.tagName || "").toLowerCase() !== "details") {
            return;
        }

        const helpLinks = Array.prototype.slice.call(els.quickHelpLinks || []);
        const normalizeQuery = function (value) {
            return String(value || "")
                .toLowerCase()
                .trim()
                .replace(/\s+/g, " ");
        };
        const statusTemplate = function (name, fallback) {
            if (!els.quickHelpStatus) {
                return fallback;
            }
            return String(els.quickHelpStatus.getAttribute(name) || fallback);
        };
        const formatStatus = function (template, count) {
            return String(template || "").replace("%d", String(count));
        };
        const filterQuickHelp = function () {
            const query = normalizeQuery(els.quickHelpSearch ? els.quickHelpSearch.value : "");
            const terms = query === "" ? [] : query.split(" ");
            let visibleCount = 0;

            helpLinks.forEach(function (link) {
                if (!(link instanceof HTMLElement)) {
                    return;
                }
                const searchable = normalizeQuery(
                    link.getAttribute("data-h4bs-quick-help-text") || link.textContent
                );
                const matches = terms.every(function (term) {
                    return searchable.includes(term);
                });
                link.hidden = !matches;
                if (matches) {
                    visibleCount += 1;
                }
            });

            if (els.quickHelpClear instanceof HTMLElement) {
                els.quickHelpClear.hidden = query === "";
            }
            if (els.quickHelpEmpty instanceof HTMLElement) {
                els.quickHelpEmpty.hidden = visibleCount !== 0;
            }
            if (els.quickHelpStatus instanceof HTMLElement) {
                const template = query === ""
                    ? statusTemplate("data-status-all", "%d task guides available.")
                    : visibleCount === 1
                        ? statusTemplate("data-status-one", "%d task guide found.")
                        : statusTemplate("data-status-many", "%d task guides found.");
                els.quickHelpStatus.textContent = formatStatus(template, visibleCount);
            }
        };
        const closeQuickHelp = function (restoreFocus) {
            if (!els.quickHelp.open) {
                return;
            }
            els.quickHelp.open = false;
            if (restoreFocus && els.quickHelpToggle) {
                els.quickHelpToggle.focus();
            }
        };

        els.quickHelp.addEventListener("toggle", function () {
            if (els.quickHelpToggle) {
                els.quickHelpToggle.setAttribute(
                    "aria-expanded",
                    els.quickHelp.open ? "true" : "false"
                );
            }
            if (els.quickHelp.open && els.quickHelpSearch instanceof HTMLElement) {
                window.requestAnimationFrame(function () {
                    els.quickHelpSearch.focus();
                });
            }
        });

        if (els.quickHelpSearch instanceof HTMLElement) {
            els.quickHelpSearch.addEventListener("input", filterQuickHelp);
        }
        if (els.quickHelpClear instanceof HTMLElement) {
            els.quickHelpClear.addEventListener("click", function () {
                if (!(els.quickHelpSearch instanceof HTMLElement)) {
                    return;
                }
                els.quickHelpSearch.value = "";
                filterQuickHelp();
                els.quickHelpSearch.focus();
            });
        }

        els.quickHelp.addEventListener("click", function (event) {
            if (event.target instanceof Element && event.target.closest("a")) {
                closeQuickHelp(false);
            }
        });

        document.addEventListener("click", function (event) {
            if (
                els.quickHelp.open &&
                event.target instanceof Node &&
                !els.quickHelp.contains(event.target)
            ) {
                closeQuickHelp(false);
            }
        });

        document.addEventListener("keydown", function (event) {
            if (event.key !== "Escape" || !els.quickHelp.open) {
                return;
            }
            event.preventDefault();
            closeQuickHelp(true);
        });

        filterQuickHelp();
    }

    function initSidePanel() {
        if (!els.sidePanel || !els.sideToggle) {
            return;
        }
        applySidePanelState();
        els.sideToggle.addEventListener("click", function () {
            state.inspectorAutoCollapsedSide = false;
            state.sideCollapsed = !state.sideCollapsed;
            persistStoredBoolean(SIDE_COLLAPSED_KEY, state.sideCollapsed);
            applySidePanelState();
        });
    }

    function inspectorWidthLimits() {
        const viewportWidth = Math.max(320, Number(window.innerWidth || 0));
        if (viewportWidth <= 800) {
            return {
                minimum: Math.min(320, viewportWidth),
                maximum: viewportWidth,
            };
        }
        if (viewportWidth <= 1180) {
            return {
                minimum: 360,
                maximum: Math.max(360, Math.min(520, Math.floor(viewportWidth * 0.56))),
            };
        }
        return {
            minimum: 380,
            maximum: Math.max(380, Math.min(560, Math.floor(viewportWidth * 0.48))),
        };
    }

    function applyInspectorWidth(width, persist) {
        const limits = inspectorWidthLimits();
        state.inspectorWidth = Math.min(
            limits.maximum,
            Math.max(limits.minimum, Math.round(Number(width) || 420))
        );
        const target = els.studioWrap || document.documentElement;
        target.style.setProperty("--h4bs-inspector-width", state.inspectorWidth + "px");
        if (els.modalResizeHandle) {
            els.modalResizeHandle.setAttribute("aria-valuemin", String(limits.minimum));
            els.modalResizeHandle.setAttribute("aria-valuemax", String(limits.maximum));
            els.modalResizeHandle.setAttribute("aria-valuenow", String(state.inspectorWidth));
            els.modalResizeHandle.setAttribute(
                "aria-valuetext",
                "Inspector width " + state.inspectorWidth + " pixels"
            );
        }
        if (persist) {
            persistStoredNumber(INSPECTOR_WIDTH_KEY, state.inspectorWidth);
        }
        window.requestAnimationFrame(function () {
            applyViewport();
            syncMiniPreview();
        });
    }

    function initInspectorResize() {
        applyInspectorWidth(state.inspectorWidth, false);
        if (!els.modalResizeHandle) {
            return;
        }

        let pointerId = null;
        let startX = 0;
        let startWidth = state.inspectorWidth;

        els.modalResizeHandle.addEventListener("pointerdown", function (event) {
            if (window.innerWidth <= 800) {
                return;
            }
            pointerId = event.pointerId;
            startX = event.clientX;
            startWidth = state.inspectorWidth;
            els.modalResizeHandle.setPointerCapture(pointerId);
            document.body.classList.add("h4bs-is-resizing-inspector");
            event.preventDefault();
        });
        els.modalResizeHandle.addEventListener("pointermove", function (event) {
            if (pointerId === null || event.pointerId !== pointerId) {
                return;
            }
            applyInspectorWidth(startWidth + startX - event.clientX, false);
        });
        const finishPointerResize = function (event) {
            if (pointerId === null || event.pointerId !== pointerId) {
                return;
            }
            if (els.modalResizeHandle.hasPointerCapture(pointerId)) {
                els.modalResizeHandle.releasePointerCapture(pointerId);
            }
            pointerId = null;
            document.body.classList.remove("h4bs-is-resizing-inspector");
            persistStoredNumber(INSPECTOR_WIDTH_KEY, state.inspectorWidth);
        };
        els.modalResizeHandle.addEventListener("pointerup", finishPointerResize);
        els.modalResizeHandle.addEventListener("pointercancel", finishPointerResize);
        els.modalResizeHandle.addEventListener("keydown", function (event) {
            const limits = inspectorWidthLimits();
            let nextWidth = state.inspectorWidth;
            if (event.key === "ArrowLeft") {
                nextWidth += event.shiftKey ? 32 : 16;
            } else if (event.key === "ArrowRight") {
                nextWidth -= event.shiftKey ? 32 : 16;
            } else if (event.key === "Home") {
                nextWidth = limits.minimum;
            } else if (event.key === "End") {
                nextWidth = limits.maximum;
            } else {
                return;
            }
            event.preventDefault();
            applyInspectorWidth(nextWidth, true);
        });
        els.modalResizeHandle.addEventListener("dblclick", function () {
            applyInspectorWidth(420, true);
        });
        window.addEventListener("resize", function () {
            const compactWorkspace = window.innerWidth <= 1180;
            if (compactWorkspace !== state.compactWorkspace) {
                state.compactWorkspace = compactWorkspace;
                if (compactWorkspace) {
                    state.sideCollapsed = true;
                    state.inspectorAutoCollapsedSide = false;
                    applySidePanelState();
                } else if (!root.classList.contains("has-inspector")) {
                    state.sideCollapsed = readStoredBoolean(SIDE_COLLAPSED_KEY, false);
                    applySidePanelState();
                }
            }
            applyInspectorWidth(state.inspectorWidth, false);
        });
    }

    function initWorkspaceControls() {
        applyCanvasFocusState();
        if (els.canvasFocusToggle) {
            els.canvasFocusToggle.addEventListener("click", function () {
                state.canvasFocus = !state.canvasFocus;
                persistStoredBoolean(CANVAS_FOCUS_KEY, state.canvasFocus);
                applyCanvasFocusState();
            });
        }

        if (els.toolsMenu) {
            els.toolsMenu.addEventListener("click", function (event) {
                if (!(event.target instanceof Element)) {
                    return;
                }
                const action = event.target.closest("button, a");
                if (!action || !els.toolsMenu.contains(action)) {
                    return;
                }
                window.setTimeout(function () {
                    els.toolsMenu.open = false;
                }, 0);
            });
            document.addEventListener("click", function (event) {
                if (
                    els.toolsMenu.open &&
                    event.target instanceof Node &&
                    !els.toolsMenu.contains(event.target)
                ) {
                    els.toolsMenu.open = false;
                }
            }, true);
            document.addEventListener("keydown", function (event) {
                if (event.key !== "Escape" || !els.toolsMenu.open) {
                    return;
                }
                event.preventDefault();
                event.stopImmediatePropagation();
                els.toolsMenu.open = false;
                const summary = els.toolsMenu.querySelector("summary");
                if (summary) {
                    summary.focus();
                }
            });
        }

        if (els.commandMenu) {
            const compactCommandMenu = window.matchMedia("(max-width: 800px)");
            let commandMenuWasDesktop = false;
            const syncCommandMenuMode = function () {
                if (compactCommandMenu.matches) {
                    if (commandMenuWasDesktop) {
                        els.commandMenu.open = false;
                    }
                    commandMenuWasDesktop = false;
                    return;
                }
                els.commandMenu.open = true;
                commandMenuWasDesktop = true;
            };
            syncCommandMenuMode();
            if (typeof compactCommandMenu.addEventListener === "function") {
                compactCommandMenu.addEventListener("change", syncCommandMenuMode);
            } else if (typeof compactCommandMenu.addListener === "function") {
                compactCommandMenu.addListener(syncCommandMenuMode);
            }
            els.commandMenu.addEventListener("click", function (event) {
                if (!(event.target instanceof Element)) {
                    return;
                }
                const action = event.target.closest("button, a");
                if (!action || !els.commandMenu.contains(action)) {
                    return;
                }
                window.setTimeout(function () {
                    els.commandMenu.open = !compactCommandMenu.matches;
                }, 0);
            });
            document.addEventListener("click", function (event) {
                if (
                    compactCommandMenu.matches &&
                    els.commandMenu.open &&
                    event.target instanceof Node &&
                    !els.commandMenu.contains(event.target)
                ) {
                    els.commandMenu.open = false;
                }
            }, true);
            document.addEventListener("keydown", function (event) {
                if (event.key !== "Escape" || !compactCommandMenu.matches || !els.commandMenu.open) {
                    return;
                }
                event.preventDefault();
                event.stopImmediatePropagation();
                els.commandMenu.open = false;
                const summary = els.commandMenu.querySelector("summary");
                if (summary) {
                    summary.focus();
                }
            });
        }
    }

    function applyCanvasFocusState() {
        root.classList.toggle("is-canvas-focus", state.canvasFocus);
        document.body.classList.toggle("h4bs-canvas-focus", state.canvasFocus);
        if (els.canvasFocusToggle) {
            const label = state.canvasFocus ? "Restore Workspace" : "Focus Canvas";
            els.canvasFocusToggle.setAttribute("aria-pressed", state.canvasFocus ? "true" : "false");
            els.canvasFocusToggle.setAttribute("title", label);
            els.canvasFocusToggle.classList.toggle("is-active", state.canvasFocus);
            const icon = els.canvasFocusToggle.querySelector(".dashicons");
            if (icon) {
                icon.classList.remove("dashicons-editor-expand", "dashicons-editor-contract");
                icon.classList.add(state.canvasFocus ? "dashicons-editor-contract" : "dashicons-editor-expand");
            }
            if (els.canvasFocusLabel) {
                els.canvasFocusLabel.textContent = label;
            }
        }
        window.requestAnimationFrame(function () {
            applyViewport();
            syncMiniPreview();
        });
    }

    function applySidePanelState() {
        if (!els.sidePanel || !els.sideToggle) {
            return;
        }

        const expanded = !state.sideCollapsed;
        root.classList.toggle("is-side-collapsed", !expanded);
        els.sidePanel.classList.toggle("is-collapsed", !expanded);
        els.sideToggle.setAttribute("aria-expanded", expanded ? "true" : "false");

        const icon = els.sideToggle.querySelector(".dashicons");
        if (icon) {
            icon.classList.remove("dashicons-arrow-right-alt2", "dashicons-arrow-left-alt2");
            icon.classList.add(expanded ? "dashicons-arrow-left-alt2" : "dashicons-arrow-right-alt2");
        }

        if (els.sideToggleLabel) {
            els.sideToggleLabel.textContent = expanded ? "Collapse" : "Expand";
        }
    }

    function libraryTabLabel(tabKey) {
        const key = normalizeLibraryTab(tabKey);
        const labels = {
            elements: "Elements",
            templates: "Templates",
            "site-kits": "Site Kits",
            themes: "Themes",
            widgets: "Widgets",
        };
        return labels[key] || "Elements";
    }

    function libraryTabDescription(tabKey) {
        const key = normalizeLibraryTab(tabKey);
        const descriptions = {
            elements: "Drag into canvas or click to insert.",
            templates: "Preview a design, then add it without saving automatically.",
            "site-kits": "Create reviewable draft pages and site parts.",
            themes: "Preview and apply reusable design tokens.",
            widgets: "Add a connected feature to the current page.",
        };
        return descriptions[key] || descriptions.elements;
    }

    function normalizeHelpEntry(rawEntry) {
        const entry = rawEntry && typeof rawEntry === "object" ? rawEntry : {};
        const url = String(entry.url || "").trim();
        if (!/^https?:\/\//i.test(url)) {
            return null;
        }
        return {
            label: String(entry.label || "Open Help4 guide").trim(),
            url: url,
        };
    }

    function helpCatalogEntry(section, key) {
        const catalog =
            data.helpCatalog && typeof data.helpCatalog === "object"
                ? data.helpCatalog
                : {};
        const sectionEntries =
            catalog[section] && typeof catalog[section] === "object"
                ? catalog[section]
                : {};
        return (
            normalizeHelpEntry(sectionEntries[String(key || "")]) ||
            normalizeHelpEntry(catalog.hub) || {
                label: "Open Help4 Builder tutorials",
                url: "https://help4wordpress.com/help4-builder-tutorials/",
            }
        );
    }

    function setHelpLink(anchor, labelNode, entry) {
        if (!(anchor instanceof HTMLAnchorElement) || !entry) {
            return;
        }
        anchor.href = String(entry.url || "");
        anchor.title = String(entry.label || "Open Help4 guide");
        anchor.setAttribute("aria-label", String(entry.label || "Open Help4 guide"));
        if (labelNode instanceof HTMLElement) {
            labelNode.textContent = String(entry.label || "Open Help4 guide");
        }
    }

    function syncSideHelp() {
        setHelpLink(
            els.sideHelp,
            els.sideHelpLabel,
            helpCatalogEntry("contexts", state.activeLibraryTab)
        );
    }

    function syncModalHelp(block, pageTab) {
        let entry = null;
        if (state.modalMode === "page") {
            const contextMap = {
                layout: "page-layout",
                globals: "page-globals",
                history: "page-history",
                template: "page-template",
                code: "page-code",
            };
            entry = helpCatalogEntry(
                "contexts",
                contextMap[String(pageTab || "layout")] || "page-layout"
            );
        } else if (block && typeof block === "object") {
            entry = helpCatalogEntry("block_types", String(block.type || "text"));
        } else {
            entry = helpCatalogEntry("contexts", "elements");
        }
        setHelpLink(els.contextHelp, els.contextHelpLabel, entry);
    }

    function renderStartJourney() {
        if (!(els.startJourney instanceof HTMLElement)) {
            return;
        }
        const visible = state.isFreshPage && !state.startJourneyDismissed;
        els.startJourney.hidden = !visible;
        root.classList.toggle("has-start-journey", visible);
        if (!visible && els.copySourcePanel instanceof HTMLElement) {
            els.copySourcePanel.hidden = true;
        }
    }

    function setStartJourneyStatus(message, isError) {
        if (!(els.startStatus instanceof HTMLElement)) {
            return;
        }
        els.startStatus.textContent = String(message || "");
        els.startStatus.classList.toggle("is-error", !!isError);
    }

    function openStartLibrary(tabKey) {
        state.canvasFocus = false;
        persistStoredBoolean(CANVAS_FOCUS_KEY, false);
        applyCanvasFocusState();
        state.inspectorAutoCollapsedSide = false;
        state.sideCollapsed = false;
        persistStoredBoolean(SIDE_COLLAPSED_KEY, false);
        applySidePanelState();
        activateLibraryTab(tabKey, true);
    }

    function populateCopySources() {
        if (!(els.copySourceSelect instanceof HTMLSelectElement)) {
            return;
        }
        const currentValue = String(els.copySourceSelect.value || "");
        while (els.copySourceSelect.options.length > 1) {
            els.copySourceSelect.remove(1);
        }
        const sources = Array.isArray(data.copySources) ? data.copySources : [];
        sources.forEach(function (source) {
            const sourceId = Math.max(0, Number(source && source.id ? source.id : 0));
            if (sourceId < 1) {
                return;
            }
            const title = String(source.title || "Untitled Builder page").trim();
            const status = String(source.status || "").trim();
            const blockCount = Math.max(0, Number(source.block_count || 0));
            const option = document.createElement("option");
            option.value = String(sourceId);
            option.textContent =
                title +
                " - " +
                String(blockCount) +
                (blockCount === 1 ? " element" : " elements") +
                (status && status !== "publish" ? " - " + status : "");
            els.copySourceSelect.appendChild(option);
        });
        if (
            currentValue !== "" &&
            Array.from(els.copySourceSelect.options).some(function (option) {
                return option.value === currentValue;
            })
        ) {
            els.copySourceSelect.value = currentValue;
        }
        if (els.copySourceConfirm instanceof HTMLButtonElement) {
            els.copySourceConfirm.disabled = String(els.copySourceSelect.value || "") === "";
        }
    }

    function useCopySource() {
        if (
            !(els.copySourceSelect instanceof HTMLSelectElement) ||
            !(els.copySourceConfirm instanceof HTMLButtonElement)
        ) {
            return;
        }
        const sourceId = Math.max(0, Number(els.copySourceSelect.value || 0));
        if (sourceId < 1 || els.copySourceConfirm.disabled) {
            setStartJourneyStatus("Choose a Builder page first.", true);
            return;
        }

        els.copySourceConfirm.disabled = true;
        setStartJourneyStatus("Loading the page design...", false);
        $.post(data.ajaxUrl, {
            action: "h4bs_builder_copy_source",
            nonce: data.nonce,
            post_id: data.postId,
            source_id: sourceId,
        })
            .done(function (response) {
                if (!response || !response.success || !response.data) {
                    const message =
                        response && response.data && response.data.message
                            ? response.data.message
                            : "The page design could not be copied.";
                    setStartJourneyStatus(message, true);
                    return;
                }
                const sourceLayout = Array.isArray(response.data.layout)
                    ? response.data.layout
                    : [];
                const copiedLayout = cloneLayoutWithFreshIds(sourceLayout, 0);
                if (copiedLayout.length < 1) {
                    setStartJourneyStatus("That Builder page has no design to copy.", true);
                    return;
                }

                captureHistoryBeforeMutation();
                state.layout = copiedLayout;
                state.pageLayout = normalizePageLayout(response.data.page_layout || "default");
                state.pageCss = String(response.data.page_css || "");
                state.pageCssHash = "";
                state.selectedId = String(copiedLayout[0].id || "");
                state.startJourneyDismissed = true;
                setDirty(true);
                renderStartJourney();
                renderAll();
                updateDirtyText("Copied page design. Save Changes when it looks right.");
            })
            .fail(function (xhr) {
                const payload = xhr && xhr.responseJSON && xhr.responseJSON.data
                    ? xhr.responseJSON.data
                    : null;
                setStartJourneyStatus(
                    payload && payload.message
                        ? payload.message
                        : "The page design could not be copied.",
                    true
                );
            })
            .always(function () {
                els.copySourceConfirm.disabled =
                    String(els.copySourceSelect.value || "") === "";
            });
    }

    function initStartJourney() {
        populateCopySources();
        renderStartJourney();
        if (els.copySourceSelect instanceof HTMLSelectElement) {
            els.copySourceSelect.addEventListener("change", function () {
                if (els.copySourceConfirm instanceof HTMLButtonElement) {
                    els.copySourceConfirm.disabled = String(els.copySourceSelect.value || "") === "";
                }
                setStartJourneyStatus("", false);
            });
        }
        if (els.copySourceConfirm instanceof HTMLButtonElement) {
            els.copySourceConfirm.addEventListener("click", useCopySource);
        }
        if (!els.startActions || els.startActions.length < 1) {
            return;
        }
        els.startActions.forEach(function (button) {
            button.addEventListener("click", function () {
                const action = String(button.getAttribute("data-h4bs-start-action") || "");
                if (action === "copy") {
                    if (!(els.copySourcePanel instanceof HTMLElement)) {
                        return;
                    }
                    const willOpen = els.copySourcePanel.hidden;
                    els.copySourcePanel.hidden = !willOpen;
                    button.setAttribute("aria-expanded", willOpen ? "true" : "false");
                    setStartJourneyStatus(
                        willOpen && (!data.copySources || data.copySources.length < 1)
                            ? "No other saved Builder pages are available yet."
                            : "",
                        false
                    );
                    if (willOpen && els.copySourceSelect instanceof HTMLElement) {
                        els.copySourceSelect.focus();
                    }
                    return;
                }

                state.startJourneyDismissed = true;
                if (action === "blank") {
                    captureHistoryBeforeMutation();
                    state.layout = [];
                    state.selectedId = null;
                    setDirty(true);
                    renderStartJourney();
                    renderAll();
                    openStartLibrary("elements");
                    updateDirtyText("Blank page ready. Add an element, then save when ready.");
                    return;
                }
                renderStartJourney();
                if (action === "template") {
                    state.templateUseCase = "pages";
                    openStartLibrary("templates");
                    return;
                }
                if (action === "site-kit") {
                    openStartLibrary("site-kits");
                }
            });
        });
    }

    function initLibraryTabs() {
        renderLibraryTabs();
        if (!els.libraryTabButtons || els.libraryTabButtons.length < 1) {
            return;
        }
        els.libraryTabButtons.forEach(function (button) {
            if (!(button instanceof HTMLElement)) {
                return;
            }
            button.addEventListener("click", function () {
                const nextTab = button.getAttribute("data-h4bs-library-tab");
                activateLibraryTab(nextTab, true);
            });
        });
    }

    function activateLibraryTab(tabKey, persist) {
        state.activeLibraryTab = normalizeLibraryTab(tabKey);
        renderLibraryTabs();
        ensureLibraryCatalog(state.activeLibraryTab, true);
        if (persist) {
            persistLibraryTab();
        }
    }

    function catalogDefinition(tabKey) {
        const key = normalizeLibraryTab(tabKey);
        const definitions = {
            templates: {
                property: "templatePresets",
                target: els.templateList,
                render: function () {
                    renderTemplateUseCaseFilters();
                    renderTemplateCategoryOptions();
                    renderTemplateCards();
                },
            },
            "site-kits": {
                property: "siteKits",
                target: els.siteKitList,
                render: renderSiteKitCards,
            },
            themes: {
                property: "themePacks",
                target: els.themeList,
                render: renderThemePackCards,
            },
            widgets: {
                property: "widgetCatalog",
                target: els.widgetList,
                render: renderWidgetLibrary,
            },
            elements: {
                property: "blockTypes",
                target: els.elementButtons,
                render: renderElementButtons,
            },
        };
        return definitions[key] || definitions.elements;
    }

    function catalogIsLoaded(tabKey) {
        const key = normalizeLibraryTab(tabKey);
        return !catalogLoads[key] || catalogLoads[key].loaded;
    }

    function renderCatalogMessage(tabKey, message, isError) {
        const definition = catalogDefinition(tabKey);
        if (!definition.target) {
            return;
        }
        definition.target.innerHTML = "";
        const status = document.createElement("p");
        status.className = "h4bs-inspector-empty";
        if (isError) {
            status.classList.add("is-error");
        }
        status.textContent = String(message || "");
        definition.target.appendChild(status);
    }

    function ensureLibraryCatalog(tabKey, renderAfterLoad) {
        const key = normalizeLibraryTab(tabKey);
        const shouldRender = renderAfterLoad !== false;
        const definition = catalogDefinition(key);
        const loadState = catalogLoads[key] || null;

        if (!loadState || loadState.loaded) {
            if (shouldRender && typeof definition.render === "function") {
                definition.render();
            }
            return $.Deferred().resolve().promise();
        }

        if (loadState.request) {
            if (shouldRender) {
                loadState.request.done(function () {
                    if (loadState.loaded && typeof definition.render === "function") {
                        definition.render();
                    }
                });
            }
            return loadState.request;
        }

        if (shouldRender) {
            renderCatalogMessage(key, "Loading " + libraryTabLabel(key) + "...", false);
        }
        loadState.request = $.post(data.ajaxUrl, {
            action: "h4bs_builder_load_catalog",
            nonce: data.nonce,
            post_id: data.postId,
            catalog: key,
        })
            .done(function (response) {
                if (
                    !response ||
                    !response.success ||
                    !response.data ||
                    !Array.isArray(response.data.items)
                ) {
                    if (shouldRender) {
                        renderCatalogMessage(
                            key,
                            "This library could not be loaded. Select the tab to retry.",
                            true
                        );
                    }
                    return;
                }
                data[definition.property] = response.data.items;
                loadState.loaded = true;
                if (shouldRender && typeof definition.render === "function") {
                    definition.render();
                }
            })
            .fail(function () {
                if (shouldRender) {
                    renderCatalogMessage(
                        key,
                        "This library could not be loaded. Select the tab to retry.",
                        true
                    );
                }
            })
            .always(function () {
                loadState.request = null;
            });

        return loadState.request;
    }

    function renderLibraryTabs() {
        const activeTab = normalizeLibraryTab(state.activeLibraryTab);
        state.activeLibraryTab = activeTab;

        if (els.sideHeading) {
            els.sideHeading.textContent = libraryTabLabel(activeTab);
        }
        if (els.sideDescription) {
            els.sideDescription.textContent = libraryTabDescription(activeTab);
        }

        if (els.libraryTabButtons && els.libraryTabButtons.length > 0) {
            els.libraryTabButtons.forEach(function (button) {
                if (!(button instanceof HTMLElement)) {
                    return;
                }
                const key = normalizeLibraryTab(
                    button.getAttribute("data-h4bs-library-tab")
                );
                const isActive = key === activeTab;
                button.classList.toggle("is-active", isActive);
                button.setAttribute("aria-selected", isActive ? "true" : "false");
                button.setAttribute("tabindex", isActive ? "0" : "-1");
            });
        }

        if (els.libraryPanels && els.libraryPanels.length > 0) {
            els.libraryPanels.forEach(function (panel) {
                if (!(panel instanceof HTMLElement)) {
                    return;
                }
                const key = normalizeLibraryTab(
                    panel.getAttribute("data-h4bs-library-panel")
                );
                const isActive = key === activeTab;
                panel.classList.toggle("is-active", isActive);
                panel.hidden = !isActive;
            });
        }
        syncSideHelp();
    }

    function initNavigatorModal() {
        if (els.openNavigator) {
            els.openNavigator.addEventListener("click", function () {
                openNavigatorModal();
            });
        }
        if (els.closeNavigator) {
            els.closeNavigator.addEventListener("click", function (event) {
                event.preventDefault();
                event.stopPropagation();
                closeNavigatorModal(true);
            });
        }
        makeFloatingModalDraggable(
            els.navigatorModal,
            els.navigatorDragHandle,
            "[data-h4bs-close-navigator]"
        );
    }

    function openNavigatorModal() {
        if (!els.navigatorModal) {
            return;
        }
        state.navigatorReturnFocus = document.activeElement;
        state.navigatorOpen = true;
        renderBlockList();
        els.navigatorModal.classList.add("is-open");
        els.navigatorModal.hidden = false;
        els.navigatorModal.removeAttribute("inert");
        els.navigatorModal.setAttribute("aria-hidden", "false");
        if (els.openNavigator) {
            els.openNavigator.setAttribute("aria-expanded", "true");
        }
        window.requestAnimationFrame(function () {
            if (els.closeNavigator && state.navigatorOpen) {
                els.closeNavigator.focus();
            }
        });
    }

    function closeNavigatorModal(restoreFocus) {
        if (!els.navigatorModal) {
            return;
        }
        state.navigatorOpen = false;
        els.navigatorModal.classList.remove("is-open");
        els.navigatorModal.hidden = true;
        els.navigatorModal.setAttribute("inert", "");
        els.navigatorModal.setAttribute("aria-hidden", "true");
        if (els.openNavigator) {
            els.openNavigator.setAttribute("aria-expanded", "false");
        }
        const returnFocus = state.navigatorReturnFocus;
        state.navigatorReturnFocus = null;
        if (restoreFocus && returnFocus && typeof returnFocus.focus === "function") {
            window.requestAnimationFrame(function () {
                returnFocus.focus();
            });
        }
    }

    function initMiniPreviewModal() {
        if (els.openMiniPreview) {
            els.openMiniPreview.addEventListener("click", function () {
                openMiniPreviewModal();
            });
        }
        if (els.closeMiniPreview) {
            els.closeMiniPreview.addEventListener("click", function () {
                closeMiniPreviewModal();
            });
        }
        if (els.miniPreviewFrame) {
            const startSeek = function (clientY) {
                if (!els.previewStage || !els.miniPreviewFrame) {
                    return;
                }
                const rect = els.miniPreviewFrame.getBoundingClientRect();
                if (!rect.height) {
                    return;
                }
                const relativeY = Math.max(
                    0,
                    Math.min(rect.height, Number(clientY || 0) - rect.top)
                );
                const stageMax = Math.max(
                    0,
                    els.previewStage.scrollHeight - els.previewStage.clientHeight
                );
                if (!stageMax) {
                    return;
                }
                const visibleRatio = Math.max(
                    0.08,
                    Math.min(1, els.previewStage.clientHeight / els.previewStage.scrollHeight)
                );
                let ratio = relativeY / rect.height;
                if (visibleRatio < 1) {
                    ratio = ratio - visibleRatio * 0.5;
                }
                ratio = Math.max(0, Math.min(1, ratio));
                els.previewStage.scrollTop = stageMax * ratio;
                updateMiniPreviewViewportWindow();
            };

            let seeking = false;
            const onMove = function (event) {
                if (!seeking) {
                    return;
                }
                if (event && typeof event.preventDefault === "function") {
                    event.preventDefault();
                }
                const touch =
                    event && event.touches && event.touches[0]
                        ? event.touches[0]
                        : null;
                const clientY = touch ? touch.clientY : event.clientY;
                startSeek(clientY);
            };
            const onStop = function () {
                seeking = false;
                document.removeEventListener("mousemove", onMove);
                document.removeEventListener("mouseup", onStop);
                document.removeEventListener("touchmove", onMove);
                document.removeEventListener("touchend", onStop);
            };

            const onStart = function (event) {
                if (event && typeof event.preventDefault === "function") {
                    event.preventDefault();
                }
                const touch =
                    event && event.touches && event.touches[0]
                        ? event.touches[0]
                        : null;
                const clientY = touch ? touch.clientY : event.clientY;
                seeking = true;
                startSeek(clientY);
                document.addEventListener("mousemove", onMove);
                document.addEventListener("mouseup", onStop);
                document.addEventListener("touchmove", onMove, { passive: false });
                document.addEventListener("touchend", onStop);
            };

            els.miniPreviewFrame.addEventListener("mousedown", onStart);
            els.miniPreviewFrame.addEventListener("touchstart", onStart, { passive: false });
        }
        makeFloatingModalDraggable(
            els.miniPreviewModal,
            els.miniPreviewDragHandle,
            "[data-h4bs-close-mini-preview]"
        );
    }

    function openMiniPreviewModal() {
        if (!els.miniPreviewModal) {
            return;
        }
        state.miniPreviewOpen = true;
        els.miniPreviewModal.hidden = false;
        syncMiniPreview(true);
    }

    function closeMiniPreviewModal() {
        if (!els.miniPreviewModal) {
            return;
        }
        state.miniPreviewOpen = false;
        els.miniPreviewModal.hidden = true;
    }

    function scheduleMiniPreviewSync(force) {
        if (!state.miniPreviewOpen && !force) {
            return;
        }
        if (state.miniPreviewSyncTimer) {
            window.clearTimeout(state.miniPreviewSyncTimer);
        }
        state.miniPreviewSyncTimer = window.setTimeout(function () {
            state.miniPreviewSyncTimer = null;
            syncMiniPreview(!!force);
        }, force ? 0 : 90);
    }

    function hashMiniPreviewMarkup(raw) {
        const text = String(raw || "");
        let hash = 0;
        for (let i = 0; i < text.length; i += 1) {
            hash = (hash << 5) - hash + text.charCodeAt(i);
            hash |= 0;
        }
        return String(hash);
    }

    function sanitizeMiniPreviewClone(rootNode) {
        if (!(rootNode instanceof HTMLElement)) {
            return;
        }
        rootNode
            .querySelectorAll(
                ".h4bs-preview-block-tools, .h4bs-section-empty, .h4bs-boxmodel-overlay, .ui-sortable-placeholder"
            )
            .forEach(function (node) {
                if (node instanceof HTMLElement) {
                    node.remove();
                }
            });
        rootNode.querySelectorAll("[contenteditable='true']").forEach(function (node) {
            if (node instanceof HTMLElement) {
                node.removeAttribute("contenteditable");
            }
        });
    }

    function syncMiniPreview(force) {
        if (
            !state.miniPreviewOpen ||
            !els.previewCanvas ||
            !els.miniPreviewScale ||
            !els.miniPreviewShell ||
            !els.miniPreviewFrame
        ) {
            return;
        }
        const viewport = selectedViewport();
        const width = Math.max(320, Number(viewport.width || 1920));
        const height = Math.max(480, Number(viewport.height || 1080));
        const viewportHeight = Math.max(480, Math.min(height, 4320));
        const group = String(viewport.group || state.viewportGroup || "monitor");
        const renderedMarkup = String(els.previewCanvas.innerHTML || "");
        const signature =
            String(viewport.slug || "") +
            "|" +
            String(state.frameMode || "") +
            "|" +
            hashMiniPreviewMarkup(renderedMarkup);

        if (!force && signature === String(state.miniPreviewMarkupHash || "")) {
            updateMiniPreviewViewportWindow();
            return;
        }
        state.miniPreviewMarkupHash = signature;

        const shell = document.createElement("div");
        shell.className = "h4bs-preview-shell h4bs-mini-shell is-device-" + group;
        if (state.frameMode === "clean") {
            shell.classList.add("is-frame-clean");
        }
        shell.style.width = width + "px";
        shell.style.minHeight = viewportHeight + "px";
        shell.style.setProperty("--h4bs-device-width", width + "px");
        shell.style.setProperty("--h4bs-device-height", viewportHeight + "px");
        shell.style.position = "absolute";
        shell.style.left = "0";
        shell.style.top = "0";
        shell.style.transformOrigin = "top left";

        const canvas = document.createElement("div");
        canvas.className = "h4bs-preview-canvas h4bs-mini-canvas";
        canvas.style.minHeight = viewportHeight + "px";
        canvas.innerHTML = renderedMarkup;
        sanitizeMiniPreviewClone(canvas);
        shell.appendChild(canvas);

        els.miniPreviewShell.innerHTML = "";
        els.miniPreviewShell.appendChild(shell);

        const frameWidth = Math.max(120, els.miniPreviewFrame.clientWidth - 6);
        const frameHeight = Math.max(120, els.miniPreviewFrame.clientHeight - 6);
        const scale = Math.min(1, frameWidth / width, frameHeight / viewportHeight);
        const scaledWidth = Math.max(1, Math.round(width * scale));
        const scaledHeight = Math.max(1, Math.round(viewportHeight * scale));

        els.miniPreviewScale.style.width = scaledWidth + "px";
        els.miniPreviewScale.style.height = scaledHeight + "px";
        els.miniPreviewScale.style.position = "relative";
        els.miniPreviewScale.style.margin = "0 auto";
        shell.style.transform = "scale(" + scale.toFixed(4) + ")";

        if (els.miniPreviewLabel) {
            els.miniPreviewLabel.textContent =
                "Viewport: " +
                String(viewport.label || "Preset") +
                " (" +
                width +
                "x" +
                height +
                ")";
        }
        updateMiniPreviewViewportWindow();
    }

    function updateMiniPreviewViewportWindow() {
        if (
            !state.miniPreviewOpen ||
            !els.previewStage ||
            !els.miniPreviewScale ||
            !els.miniPreviewWindow
        ) {
            return;
        }
        const trackHeight = Math.max(1, els.miniPreviewScale.clientHeight);
        const scrollHeight = Math.max(1, els.previewStage.scrollHeight);
        const clientHeight = Math.max(1, els.previewStage.clientHeight);
        const maxScroll = Math.max(0, scrollHeight - clientHeight);
        const scrollTop = Math.max(0, Math.min(maxScroll, els.previewStage.scrollTop || 0));
        const visibleRatio = Math.max(0.08, Math.min(1, clientHeight / scrollHeight));
        const topRatio = maxScroll > 0 ? scrollTop / maxScroll : 0;
        const windowHeight = Math.max(16, Math.round(trackHeight * visibleRatio));
        const maxTop = Math.max(0, trackHeight - windowHeight);
        const windowTop = Math.round(maxTop * topRatio);

        els.miniPreviewWindow.style.height = windowHeight + "px";
        els.miniPreviewWindow.style.top = windowTop + "px";
        els.miniPreviewWindow.style.display = visibleRatio >= 0.995 ? "none" : "block";

        if (els.miniPreviewScroll) {
            const percent = maxScroll > 0 ? Math.round((scrollTop / maxScroll) * 100) : 0;
            els.miniPreviewScroll.textContent = "Scroll: " + percent + "%";
        }
    }

    function contextMenuItems() {
        return [
            { action: "edit", label: "Edit Element" },
            { action: "duplicate", label: "Duplicate Element" },
            { action: "delete", label: "Delete Element" },
            { action: "copy_style", label: "Copy Style" },
            { action: "paste_style", label: "Paste Style" },
        ];
    }

    function initContextMenu() {
        ensureContextMenu();
        document.addEventListener("click", function (event) {
            if (!state.contextMenuOpen || !els.contextMenu) {
                return;
            }
            const target = event.target;
            if (target instanceof HTMLElement && els.contextMenu.contains(target)) {
                return;
            }
            closeContextMenu();
        });
        document.addEventListener(
            "scroll",
            function () {
                if (state.contextMenuOpen) {
                    closeContextMenu();
                }
            },
            true
        );
        window.addEventListener("resize", function () {
            if (state.contextMenuOpen) {
                closeContextMenu();
            }
        });
    }

    function ensureContextMenu() {
        if (els.contextMenu instanceof HTMLElement) {
            return els.contextMenu;
        }
        let menu = document.querySelector("[data-h4bs-context-menu]");
        if (!(menu instanceof HTMLElement)) {
            menu = document.createElement("div");
            menu.className = "h4bs-context-menu";
            menu.setAttribute("data-h4bs-context-menu", "1");
            menu.hidden = true;
            contextMenuItems().forEach(function (item) {
                const button = document.createElement("button");
                button.type = "button";
                button.className = "h4bs-context-menu-item";
                button.textContent = String(item.label || item.action);
                button.setAttribute("data-h4bs-context-action", String(item.action || ""));
                button.addEventListener("click", function (event) {
                    event.preventDefault();
                    event.stopPropagation();
                    handleContextMenuAction(String(item.action || ""));
                });
                menu.appendChild(button);
            });
            document.body.appendChild(menu);
        }
        els.contextMenu = menu;
        return menu;
    }

    function updateContextMenuState() {
        const menu = ensureContextMenu();
        if (!(menu instanceof HTMLElement)) {
            return;
        }
        const canPasteStyle = !!(
            state.styleClipboard &&
            state.styleClipboard.settings &&
            typeof state.styleClipboard.settings === "object"
        );
        menu.querySelectorAll(".h4bs-context-menu-item").forEach(function (button) {
            if (!(button instanceof HTMLButtonElement)) {
                return;
            }
            const action = String(button.getAttribute("data-h4bs-context-action") || "");
            const disabled = action === "paste_style" && !canPasteStyle;
            button.disabled = disabled;
            button.classList.toggle("is-disabled", disabled);
        });
    }

    function openContextMenu(blockId, clientX, clientY) {
        const id = String(blockId || "");
        if (id === "") {
            return;
        }
        const menu = ensureContextMenu();
        if (!(menu instanceof HTMLElement)) {
            return;
        }
        state.contextMenuOpen = true;
        state.contextMenuBlockId = id;
        updateContextMenuState();
        menu.hidden = false;
        menu.style.left = Math.max(8, Number(clientX || 0)) + "px";
        menu.style.top = Math.max(8, Number(clientY || 0)) + "px";

        const rect = menu.getBoundingClientRect();
        const viewportWidth = Math.max(320, window.innerWidth || 0);
        const viewportHeight = Math.max(220, window.innerHeight || 0);
        let left = Number(clientX || 0);
        let top = Number(clientY || 0);
        if (left + rect.width > viewportWidth - 8) {
            left = viewportWidth - rect.width - 8;
        }
        if (top + rect.height > viewportHeight - 8) {
            top = viewportHeight - rect.height - 8;
        }
        menu.style.left = Math.max(8, left) + "px";
        menu.style.top = Math.max(8, top) + "px";
    }

    function closeContextMenu() {
        state.contextMenuOpen = false;
        state.contextMenuBlockId = null;
        if (els.contextMenu instanceof HTMLElement) {
            els.contextMenu.hidden = true;
        }
    }

    function extractStyleSettings(settings) {
        const source = settings && typeof settings === "object" ? settings : {};
        const copied = {};
        Object.keys(source).forEach(function (key) {
            if (String(key || "").indexOf("design_") === 0) {
                copied[key] = source[key];
            }
        });
        return copied;
    }

    function copyStyleFromBlock(blockId) {
        const block = findBlockById(blockId);
        if (!block) {
            return false;
        }
        state.styleClipboard = {
            settings: extractStyleSettings(block.settings),
        };
        persistStyleClipboard();
        return true;
    }

    function pasteStyleToBlock(blockId) {
        const block = findBlockById(blockId);
        if (
            !block ||
            !state.styleClipboard ||
            !state.styleClipboard.settings ||
            typeof state.styleClipboard.settings !== "object"
        ) {
            return false;
        }
        if (!block.settings || typeof block.settings !== "object") {
            block.settings = {};
        }
        captureHistoryBeforeMutation();
        Object.keys(state.styleClipboard.settings).forEach(function (key) {
            block.settings[key] = state.styleClipboard.settings[key];
        });
        if (
            state.modalMode === "block" &&
            state.modalDraftBlock &&
            String(state.modalDraftBlock.id || "") === String(block.id || "")
        ) {
            state.modalDraftBlock = deepClone(block);
        }

        setDirty(true);
        renderAll();
        return true;
    }

    function handleContextMenuAction(action) {
        const blockId = String(state.contextMenuBlockId || "");
        if (blockId === "") {
            closeContextMenu();
            return;
        }

        if (action === "edit") {
            state.selectedId = blockId;
            renderBlockList();
            openBlockModal(blockId);
            closeContextMenu();
            return;
        }
        if (action === "duplicate") {
            duplicateBlock(blockId);
            closeContextMenu();
            return;
        }
        if (action === "delete") {
            deleteBlock(blockId);
            closeContextMenu();
            return;
        }
        if (action === "copy_style") {
            copyStyleFromBlock(blockId);
            updateContextMenuState();
            closeContextMenu();
            return;
        }
        if (action === "paste_style") {
            pasteStyleToBlock(blockId);
            closeContextMenu();
            return;
        }
        closeContextMenu();
    }

    function makeFloatingModalDraggable(modal, handle, cancelSelector) {
        if (!modal || !handle) {
            return;
        }

        let dragging = false;
        let offsetX = 0;
        let offsetY = 0;

        handle.addEventListener("mousedown", function (event) {
            const target = event.target;
            if (
                target instanceof HTMLElement &&
                cancelSelector &&
                target.closest(cancelSelector)
            ) {
                return;
            }
            dragging = true;
            const rect = modal.getBoundingClientRect();
            offsetX = event.clientX - rect.left;
            offsetY = event.clientY - rect.top;
            modal.style.left = rect.left + "px";
            modal.style.top = rect.top + "px";
            modal.style.transform = "none";
            event.preventDefault();
        });

        document.addEventListener("mousemove", function (event) {
            if (!dragging) {
                return;
            }
            const x = Math.max(6, event.clientX - offsetX);
            const y = Math.max(6, event.clientY - offsetY);
            modal.style.left = x + "px";
            modal.style.top = y + "px";
        });

        document.addEventListener("mouseup", function () {
            dragging = false;
        });
    }

    function renderAll() {
        renderStartJourney();
        renderBlockList();
        renderPreview();
        updateEstimate();
        updatePageLayoutLabel();
        applyViewport();
        if (state.modalMode === "block" && state.modalBlockId) {
            const active = findBlockById(state.modalBlockId);
            if (!active) {
                closeBuilderModal(true);
                return;
            }
            if (!state.modalDraftBlock || String(state.modalDraftBlock.id) !== String(active.id)) {
                state.modalDraftBlock = deepClone(active);
            }
            const preserveFocusedEditor =
                state.modalDirty &&
                (isModalFieldFocused() || shouldDelayModalPreviewRender());
            if (!preserveFocusedEditor) {
                renderModalForBlock(state.modalDraftBlock);
            }
            syncModalTitle(state.modalDraftBlock);
        } else if (state.modalMode === "page") {
            renderPageSettingsModal();
        } else if (
            (els.modal && !els.modal.hidden) ||
            (els.modalBackdrop && !els.modalBackdrop.hidden)
        ) {
            closeBuilderModal(true);
        }
        scheduleMiniPreviewSync(false);
    }

    function renderBlockList() {
        if (!els.blockList) {
            syncSelectedPreviewBlockVisual();
            syncSelectionActionBar();
            return;
        }
        els.blockList.innerHTML = "";

        if (state.layout.length === 0) {
            const empty = document.createElement("li");
            empty.className = "h4bs-inspector-empty";
            empty.textContent = "No blocks yet. Drag elements, templates, or widgets from the library panel.";
            els.blockList.appendChild(empty);
            syncSelectedPreviewBlockVisual();
            syncSelectionActionBar();
            return;
        }

        const tree = document.createElement("ul");
        tree.className = "h4bs-nav-tree";

        const visited = new Set();
        const orderMap = buildNavigatorOrderMap();
        sortBlocksForNavigator(topLevelBlocks(), orderMap).forEach(function (block) {
            appendNavigatorBlockItem(tree, block, 0, visited, orderMap);
        });

        els.blockList.appendChild(tree);
        syncSelectedPreviewBlockVisual();
        syncSelectionActionBar();
    }

    function findPreviewBlockNodeById(blockId) {
        if (!els.previewCanvas) {
            return null;
        }
        const id = String(blockId || "");
        if (id === "") {
            return null;
        }
        const candidates = els.previewCanvas.querySelectorAll(
            ".h4bs-preview-block[data-h4bs-preview-block]"
        );
        for (let i = 0; i < candidates.length; i += 1) {
            const node = candidates[i];
            if (!(node instanceof HTMLElement)) {
                continue;
            }
            if (String(node.getAttribute("data-h4bs-preview-block") || "") === id) {
                return node;
            }
        }
        return null;
    }

    function selectedEditableBlockTarget() {
        const selectedId = String(state.selectedId || "");
        if (selectedId === "") {
            return { block: null, isDraft: false };
        }
        if (
            state.modalMode === "block" &&
            state.modalDraftBlock &&
            String(state.modalDraftBlock.id || "") === selectedId
        ) {
            return { block: state.modalDraftBlock, isDraft: true };
        }
        return {
            block: findBlockById(selectedId),
            isDraft: false,
        };
    }

    function numberFromCssPixels(raw) {
        const parsed = Number.parseFloat(String(raw || "").trim());
        if (!Number.isFinite(parsed)) {
            return 0;
        }
        return parsed;
    }

    function readNumericSetting(settings, key, fallback) {
        const source =
            settings &&
            key !== "" &&
            Object.prototype.hasOwnProperty.call(settings, key)
                ? settings[key]
                : "";
        const parsed = Number.parseFloat(String(source || "").trim());
        if (Number.isFinite(parsed)) {
            return parsed;
        }
        return Number(fallback || 0);
    }

    function readComputedSpacing(node) {
        const computed =
            node instanceof HTMLElement ? window.getComputedStyle(node) : null;
        const fallback = {
            margin: { top: 0, right: 0, bottom: 0, left: 0 },
            padding: { top: 0, right: 0, bottom: 0, left: 0 },
            border: { top: 0, right: 0, bottom: 0, left: 0 },
        };
        if (!computed) {
            return fallback;
        }
        return {
            margin: {
                top: numberFromCssPixels(computed.marginTop),
                right: numberFromCssPixels(computed.marginRight),
                bottom: numberFromCssPixels(computed.marginBottom),
                left: numberFromCssPixels(computed.marginLeft),
            },
            padding: {
                top: Math.max(0, numberFromCssPixels(computed.paddingTop)),
                right: Math.max(0, numberFromCssPixels(computed.paddingRight)),
                bottom: Math.max(0, numberFromCssPixels(computed.paddingBottom)),
                left: Math.max(0, numberFromCssPixels(computed.paddingLeft)),
            },
            border: {
                top: Math.max(0, numberFromCssPixels(computed.borderTopWidth)),
                right: Math.max(0, numberFromCssPixels(computed.borderRightWidth)),
                bottom: Math.max(0, numberFromCssPixels(computed.borderBottomWidth)),
                left: Math.max(0, numberFromCssPixels(computed.borderLeftWidth)),
            },
        };
    }

    function normalizeBoxHandleToken(raw) {
        const token = String(raw || "").trim().toLowerCase();
        const match = token.match(/^(margin|padding)_(top|right|bottom|left)$/);
        if (!match) {
            return null;
        }
        return {
            group: String(match[1]),
            side: String(match[2]),
        };
    }

    function setModalInputValueBySettingKey(settingKey, nextValue) {
        if (!(els.modalBody instanceof HTMLElement)) {
            return;
        }
        const key = String(settingKey || "");
        if (key === "") {
            return;
        }
        const fields = els.modalBody.querySelectorAll("[data-h4bs-setting-key]");
        fields.forEach(function (field) {
            if (!(field instanceof HTMLElement)) {
                return;
            }
            if (String(field.getAttribute("data-h4bs-setting-key") || "") !== key) {
                return;
            }
            if (!("value" in field)) {
                return;
            }
            field.value = String(nextValue || "");
        });
    }

    function applySpacingStylesToNode(node, settings) {
        if (!(node instanceof HTMLElement)) {
            return;
        }
        const source = settings && typeof settings === "object" ? settings : {};
        const marginUnit = cssSafeUnit(source.design_margin_unit || "px", "px");
        const paddingUnit = cssSafeUnit(source.design_padding_unit || "px", "px");

        const marginTop = cssDimension(source.design_margin_top || "", marginUnit, "");
        const marginRight = cssDimension(source.design_margin_right || "", marginUnit, "");
        const marginBottom = cssDimension(source.design_margin_bottom || "", marginUnit, "");
        const marginLeft = cssDimension(source.design_margin_left || "", marginUnit, "");

        const paddingTop = cssDimension(source.design_padding_top || "", paddingUnit, "");
        const paddingRight = cssDimension(source.design_padding_right || "", paddingUnit, "");
        const paddingBottom = cssDimension(source.design_padding_bottom || "", paddingUnit, "");
        const paddingLeft = cssDimension(source.design_padding_left || "", paddingUnit, "");

        node.style.marginTop = marginTop;
        node.style.marginRight = marginRight;
        node.style.marginBottom = marginBottom;
        node.style.marginLeft = marginLeft;

        node.style.paddingTop = paddingTop;
        node.style.paddingRight = paddingRight;
        node.style.paddingBottom = paddingBottom;
        node.style.paddingLeft = paddingLeft;
    }

    function ensureBoxModelOverlay() {
        if (!(els.previewShell instanceof HTMLElement)) {
            return null;
        }
        if (els.boxModelOverlay instanceof HTMLElement) {
            return els.boxModelOverlay;
        }
        const overlay = document.createElement("div");
        overlay.className = "h4bs-boxmodel-overlay";
        overlay.setAttribute("data-h4bs-boxmodel-overlay", "1");
        overlay.hidden = true;
        overlay.innerHTML =
            "<div class='h4bs-boxmodel-layer h4bs-boxmodel-layer-margin' data-h4bs-box-layer='margin'>" +
            "<button type='button' class='h4bs-boxmodel-handle is-margin is-top' data-h4bs-box-handle='margin_top' aria-label='Adjust margin top'></button>" +
            "<button type='button' class='h4bs-boxmodel-handle is-margin is-right' data-h4bs-box-handle='margin_right' aria-label='Adjust margin right'></button>" +
            "<button type='button' class='h4bs-boxmodel-handle is-margin is-bottom' data-h4bs-box-handle='margin_bottom' aria-label='Adjust margin bottom'></button>" +
            "<button type='button' class='h4bs-boxmodel-handle is-margin is-left' data-h4bs-box-handle='margin_left' aria-label='Adjust margin left'></button>" +
            "</div>" +
            "<div class='h4bs-boxmodel-layer h4bs-boxmodel-layer-border' data-h4bs-box-layer='border'>" +
            "<button type='button' class='h4bs-boxmodel-handle is-padding is-top' data-h4bs-box-handle='padding_top' aria-label='Adjust padding top'></button>" +
            "<button type='button' class='h4bs-boxmodel-handle is-padding is-right' data-h4bs-box-handle='padding_right' aria-label='Adjust padding right'></button>" +
            "<button type='button' class='h4bs-boxmodel-handle is-padding is-bottom' data-h4bs-box-handle='padding_bottom' aria-label='Adjust padding bottom'></button>" +
            "<button type='button' class='h4bs-boxmodel-handle is-padding is-left' data-h4bs-box-handle='padding_left' aria-label='Adjust padding left'></button>" +
            "</div>" +
            "<div class='h4bs-boxmodel-layer h4bs-boxmodel-layer-content' data-h4bs-box-layer='content'></div>" +
            "<div class='h4bs-boxmodel-pill' data-h4bs-boxmodel-pill>Drag orange handles for margin and blue handles for padding.</div>";
        overlay.addEventListener("mousedown", function (event) {
            if (!(event.target instanceof HTMLElement)) {
                return;
            }
            const handle = event.target.closest("[data-h4bs-box-handle]");
            if (!(handle instanceof HTMLElement)) {
                return;
            }
            if (Number(event.button || 0) !== 0) {
                return;
            }
            event.preventDefault();
            event.stopPropagation();
            startBoxModelDrag(handle, event);
        });
        els.previewShell.appendChild(overlay);
        els.boxModelOverlay = overlay;
        return overlay;
    }

    function hideBoxModelOverlay() {
        const overlay = ensureBoxModelOverlay();
        if (!(overlay instanceof HTMLElement)) {
            return;
        }
        overlay.hidden = true;
        overlay.classList.remove("is-active", "is-dragging");
    }

    function syncBoxModelPillText(text) {
        const overlay = ensureBoxModelOverlay();
        if (!(overlay instanceof HTMLElement)) {
            return;
        }
        const pill = overlay.querySelector("[data-h4bs-boxmodel-pill]");
        if (!(pill instanceof HTMLElement)) {
            return;
        }
        const value = String(text || "").trim();
        if (value !== "") {
            pill.textContent = value;
            return;
        }
        pill.textContent =
            "Drag orange handles for margin and blue handles for padding.";
    }

    function updateBoxModelOverlayMetrics(node, block) {
        const overlay = ensureBoxModelOverlay();
        if (!(overlay instanceof HTMLElement)) {
            return;
        }
        if (
            !(node instanceof HTMLElement) ||
            !(els.previewShell instanceof HTMLElement)
        ) {
            hideBoxModelOverlay();
            return;
        }
        const shellRect = els.previewShell.getBoundingClientRect();
        const nodeRect = node.getBoundingClientRect();
        if (
            nodeRect.width <= 0 ||
            nodeRect.height <= 0 ||
            shellRect.width <= 0 ||
            shellRect.height <= 0
        ) {
            hideBoxModelOverlay();
            return;
        }

        const spacing = readComputedSpacing(node);
        const margin = spacing.margin;
        const padding = spacing.padding;
        const border = spacing.border;

        const overlayLeft = nodeRect.left - shellRect.left - margin.left;
        const overlayTop = nodeRect.top - shellRect.top - margin.top;
        const overlayWidth = nodeRect.width + margin.left + margin.right;
        const overlayHeight = nodeRect.height + margin.top + margin.bottom;

        const borderLeft = margin.left;
        const borderTop = margin.top;
        const borderWidth = nodeRect.width;
        const borderHeight = nodeRect.height;

        const contentLeft = borderLeft + border.left + padding.left;
        const contentTop = borderTop + border.top + padding.top;
        const contentWidth = Math.max(
            8,
            borderWidth - border.left - border.right - padding.left - padding.right
        );
        const contentHeight = Math.max(
            8,
            borderHeight - border.top - border.bottom - padding.top - padding.bottom
        );

        overlay.hidden = false;
        overlay.classList.add("is-active");
        overlay.style.left = overlayLeft + "px";
        overlay.style.top = overlayTop + "px";
        overlay.style.width = overlayWidth + "px";
        overlay.style.height = overlayHeight + "px";
        overlay.style.setProperty("--h4bs-box-margin-top", margin.top + "px");
        overlay.style.setProperty("--h4bs-box-margin-right", margin.right + "px");
        overlay.style.setProperty("--h4bs-box-margin-bottom", margin.bottom + "px");
        overlay.style.setProperty("--h4bs-box-margin-left", margin.left + "px");

        const borderLayer = overlay.querySelector(
            "[data-h4bs-box-layer='border']"
        );
        if (borderLayer instanceof HTMLElement) {
            borderLayer.style.left = borderLeft + "px";
            borderLayer.style.top = borderTop + "px";
            borderLayer.style.width = borderWidth + "px";
            borderLayer.style.height = borderHeight + "px";
        }
        const contentLayer = overlay.querySelector(
            "[data-h4bs-box-layer='content']"
        );
        if (contentLayer instanceof HTMLElement) {
            contentLayer.style.left = contentLeft + "px";
            contentLayer.style.top = contentTop + "px";
            contentLayer.style.width = contentWidth + "px";
            contentLayer.style.height = contentHeight + "px";
        }

        const targetType =
            block && block.type ? String(block.type || "").trim() : "element";
        syncBoxModelPillText(
            "Spacing: " +
                targetType +
                " | M " +
                Math.round(margin.top) +
                "/" +
                Math.round(margin.right) +
                "/" +
                Math.round(margin.bottom) +
                "/" +
                Math.round(margin.left) +
                " | P " +
                Math.round(padding.top) +
                "/" +
                Math.round(padding.right) +
                "/" +
                Math.round(padding.bottom) +
                "/" +
                Math.round(padding.left)
        );
    }

    function syncSelectedPreviewBlockVisual() {
        if (!els.previewCanvas) {
            hideBoxModelOverlay();
            return;
        }
        const selectedId = String(state.selectedId || "");
        const previewBlocks = els.previewCanvas.querySelectorAll(
            ".h4bs-preview-block[data-h4bs-preview-block]"
        );
        let selectedNode = null;
        previewBlocks.forEach(function (node) {
            if (!(node instanceof HTMLElement)) {
                return;
            }
            const nodeId = String(node.getAttribute("data-h4bs-preview-block") || "");
            const active = selectedId !== "" && nodeId === selectedId;
            node.classList.toggle("is-selected", active);
            if (active) {
                selectedNode = node;
            }
        });
        if (!(selectedNode instanceof HTMLElement)) {
            hideBoxModelOverlay();
            return;
        }
        const selectedTarget = selectedEditableBlockTarget();
        updateBoxModelOverlayMetrics(selectedNode, selectedTarget.block);
    }

    function applyBoxModelValueToTarget(target, group, side, numericValue) {
        if (
            !target ||
            typeof target !== "object" ||
            !target.block ||
            typeof target.block !== "object"
        ) {
            return;
        }
        const groupKey = String(group || "");
        const sideKey = String(side || "");
        const map =
            groupKey !== "" &&
            Object.prototype.hasOwnProperty.call(BOX_MODEL_KEYS, groupKey)
                ? BOX_MODEL_KEYS[groupKey]
                : null;
        if (!map || !Object.prototype.hasOwnProperty.call(map, sideKey)) {
            return;
        }

        const normalized =
            normalizeDecimalValue(String(numericValue), 2) || "0";
        if (!target.block.settings || typeof target.block.settings !== "object") {
            target.block.settings = {};
        }
        target.block.settings[map.unit] = "px";
        target.block.settings[map[sideKey]] = normalized;
        setModalInputValueBySettingKey(map.unit, "px");
        setModalInputValueBySettingKey(map[sideKey], normalized);

        if (target.isDraft) {
            markModalDirty(true);
            syncModalTitle(target.block);
        } else {
            setDirty(true);
            refreshBlockLabels();
            updateEstimate();
        }

        const selectedNode = findPreviewBlockNodeById(state.selectedId);
        if (selectedNode instanceof HTMLElement) {
            applySpacingStylesToNode(selectedNode, target.block.settings || {});
            updateBoxModelOverlayMetrics(selectedNode, target.block);
        }
    }

    function startBoxModelDrag(handle, event) {
        if (!(handle instanceof HTMLElement) || !event) {
            return;
        }
        const token = normalizeBoxHandleToken(
            handle.getAttribute("data-h4bs-box-handle")
        );
        if (!token) {
            return;
        }
        const selectedId = String(state.selectedId || "");
        if (selectedId === "") {
            return;
        }
        const target = selectedEditableBlockTarget();
        if (!target.block || typeof target.block !== "object") {
            return;
        }
        const selectedNode = findPreviewBlockNodeById(selectedId);
        if (!(selectedNode instanceof HTMLElement)) {
            return;
        }

        if (!target.block.settings || typeof target.block.settings !== "object") {
            target.block.settings = {};
        }
        const map = BOX_MODEL_KEYS[token.group];
        const computed = readComputedSpacing(selectedNode);
        const startValue = readNumericSetting(
            target.block.settings,
            map[token.side],
            computed[token.group][token.side]
        );

        if (!target.isDraft) {
            captureHistoryBeforeMutation();
        }

        target.block.settings[map.unit] = "px";
        setModalInputValueBySettingKey(map.unit, "px");

        state.boxModelDrag = {
            group: token.group,
            side: token.side,
            target: target,
            startX: Number(event.clientX || 0),
            startY: Number(event.clientY || 0),
            startValue: startValue,
            lastValue: startValue,
            changed: false,
        };
        const overlay = ensureBoxModelOverlay();
        if (overlay instanceof HTMLElement) {
            overlay.classList.add("is-dragging");
        }
        root.classList.add("is-dragging-boxmodel");
        document.addEventListener("mousemove", onBoxModelDragMove);
        document.addEventListener("mouseup", stopBoxModelDrag);
    }

    function onBoxModelDragMove(event) {
        if (!state.boxModelDrag || !event) {
            return;
        }
        const drag = state.boxModelDrag;
        const deltaX = Number(event.clientX || 0) - Number(drag.startX || 0);
        const deltaY = Number(event.clientY || 0) - Number(drag.startY || 0);
        let delta = 0;
        if (drag.side === "top") {
            delta = -deltaY;
        } else if (drag.side === "bottom") {
            delta = deltaY;
        } else if (drag.side === "left") {
            delta = -deltaX;
        } else {
            delta = deltaX;
        }
        let nextValue = Number(drag.startValue || 0) + delta;
        if (drag.group === "padding") {
            nextValue = Math.max(0, nextValue);
        } else {
            nextValue = Math.max(-5000, nextValue);
        }
        nextValue = Math.round(nextValue * 100) / 100;
        if (Math.abs(nextValue - Number(drag.lastValue || 0)) < 0.01) {
            return;
        }
        drag.lastValue = nextValue;
        drag.changed = true;
        applyBoxModelValueToTarget(
            drag.target,
            drag.group,
            drag.side,
            nextValue
        );
        syncBoxModelPillText(
            (drag.group === "margin" ? "Margin " : "Padding ") +
                drag.side +
                ": " +
                normalizeDecimalValue(String(nextValue), 2) +
                "px"
        );
    }

    function stopBoxModelDrag() {
        const drag = state.boxModelDrag;
        state.boxModelDrag = null;
        document.removeEventListener("mousemove", onBoxModelDragMove);
        document.removeEventListener("mouseup", stopBoxModelDrag);
        root.classList.remove("is-dragging-boxmodel");
        const overlay = ensureBoxModelOverlay();
        if (overlay instanceof HTMLElement) {
            overlay.classList.remove("is-dragging");
        }
        if (!drag || !drag.changed) {
            syncSelectedPreviewBlockVisual();
            return;
        }
        if (drag.target && drag.target.isDraft) {
            requestModalPreviewRender();
        } else {
            requestServerPreviewRender(0);
        }
        syncSelectedPreviewBlockVisual();
    }

    function appendNavigatorBlockItem(parentList, block, depth, visited, orderMap) {
        if (!block || typeof block !== "object" || !parentList) {
            return;
        }
        const blockId = String(block.id || "");
        if (blockId === "" || visited.has(blockId)) {
            return;
        }
        visited.add(blockId);

        const li = document.createElement("li");
        li.className = "h4bs-block-item h4bs-nav-item";
        li.dataset.blockId = blockId;
        li.dataset.depth = String(Math.max(0, Number(depth || 0)));
        if (blockId === String(state.selectedId || "")) {
            li.classList.add("is-selected");
        }

        const head = document.createElement("div");
        head.className = "h4bs-block-item-head h4bs-nav-item-head";
        head.style.setProperty("--h4bs-nav-depth", String(Math.max(0, Number(depth || 0))));

        const columnGroups = navigatorColumnGroups(block, orderMap);
        const hasChildren = columnGroups.some(function (group) {
            return Array.isArray(group.children) && group.children.length > 0;
        });

        const toggle = document.createElement("button");
        toggle.type = "button";
        toggle.className = "h4bs-nav-toggle button-link";
        toggle.setAttribute("aria-label", hasChildren ? "Toggle children" : "No child elements");
        const toggleIcon = document.createElement("span");
        toggleIcon.className =
            "dashicons " +
            (hasChildren
                ? (isNavigatorCollapsed(blockId)
                    ? "dashicons-arrow-right-alt2"
                    : "dashicons-arrow-down-alt2")
                : "dashicons-minus");
        toggle.appendChild(toggleIcon);
        if (!hasChildren) {
            toggle.disabled = true;
        } else {
            toggle.addEventListener("click", function (event) {
                event.preventDefault();
                event.stopPropagation();
                state.navigatorCollapsed[blockId] = !isNavigatorCollapsed(blockId);
                renderBlockList();
            });
        }
        head.appendChild(toggle);

        const icon = document.createElement("span");
        icon.className = "h4bs-nav-type-icon dashicons " + elementIcon(block.type);
        icon.setAttribute("aria-hidden", "true");
        head.appendChild(icon);

        const label = document.createElement("button");
        label.type = "button";
        label.className = "h4bs-block-item-label h4bs-nav-item-label button-link";
        const flatIndex = Math.max(
            0,
            state.layout.findIndex(function (row) {
                return String(row.id || "") === blockId;
            })
        );
        label.textContent = blockLabel(block, flatIndex);
        label.addEventListener("click", function () {
            state.selectedId = blockId;
            renderBlockList();
            openBlockModal(blockId);
        });
        head.appendChild(label);

        const actions = document.createElement("div");
        actions.className = "h4bs-block-item-actions h4bs-nav-item-actions";

        const dup = document.createElement("button");
        dup.type = "button";
        dup.className = "h4bs-nav-icon-btn";
        dup.setAttribute("aria-label", "Duplicate element");
        dup.title = "Duplicate";
        dup.innerHTML = "<span class='dashicons dashicons-admin-page' aria-hidden='true'></span>";
        dup.addEventListener("click", function (event) {
            event.preventDefault();
            event.stopPropagation();
            duplicateBlock(blockId);
        });
        actions.appendChild(dup);

        const del = document.createElement("button");
        del.type = "button";
        del.className = "h4bs-nav-icon-btn is-danger";
        del.setAttribute("aria-label", "Delete element");
        del.title = "Delete";
        del.innerHTML = "<span class='dashicons dashicons-trash' aria-hidden='true'></span>";
        del.addEventListener("click", function (event) {
            event.preventDefault();
            event.stopPropagation();
            deleteBlock(blockId);
        });
        actions.appendChild(del);

        head.appendChild(actions);
        li.appendChild(head);

        if (hasChildren && !isNavigatorCollapsed(blockId)) {
            const childrenList = document.createElement("ul");
            childrenList.className = "h4bs-nav-children";

            columnGroups.forEach(function (group) {
                const slotItem = document.createElement("li");
                slotItem.className = "h4bs-nav-slot";

                const slotLabel = document.createElement("div");
                slotLabel.className = "h4bs-nav-slot-label";
                slotLabel.style.setProperty(
                    "--h4bs-nav-depth",
                    String(Math.max(0, Number(depth || 0)) + 1)
                );
                slotLabel.innerHTML =
                    "<span class='dashicons dashicons-columns' aria-hidden='true'></span>" +
                    escHtml(String(group.label || "Column"));
                slotItem.appendChild(slotLabel);

                const slotChildren = document.createElement("ul");
                slotChildren.className = "h4bs-nav-children h4bs-nav-children-slot";
                if (!group.children.length) {
                    const empty = document.createElement("li");
                    empty.className = "h4bs-nav-empty";
                    empty.style.setProperty(
                        "--h4bs-nav-depth",
                        String(Math.max(0, Number(depth || 0)) + 2)
                    );
                    empty.textContent = "Empty";
                    slotChildren.appendChild(empty);
                } else {
                    group.children.forEach(function (child) {
                        appendNavigatorBlockItem(
                            slotChildren,
                            child,
                            Math.max(0, Number(depth || 0)) + 2,
                            visited,
                            orderMap
                        );
                    });
                }
                slotItem.appendChild(slotChildren);
                childrenList.appendChild(slotItem);
            });

            li.appendChild(childrenList);
        }

        parentList.appendChild(li);
    }

    function isNavigatorCollapsed(blockId) {
        const key = String(blockId || "");
        if (key === "") {
            return false;
        }
        return !!state.navigatorCollapsed[key];
    }

    function buildNavigatorOrderMap() {
        const orderMap = {};
        if (els.previewCanvas) {
            const domOrder = Array.from(
                els.previewCanvas.querySelectorAll(".h4bs-preview-block[data-h4bs-preview-block]")
            );
            domOrder.forEach(function (node, index) {
                if (!(node instanceof HTMLElement)) {
                    return;
                }
                const id = String(node.getAttribute("data-h4bs-preview-block") || "");
                if (id !== "" && !Object.prototype.hasOwnProperty.call(orderMap, id)) {
                    orderMap[id] = index;
                }
            });
        }
        state.layout.forEach(function (block, index) {
            const id = String(block && block.id ? block.id : "");
            if (id !== "" && !Object.prototype.hasOwnProperty.call(orderMap, id)) {
                orderMap[id] = 100000 + index;
            }
        });
        return orderMap;
    }

    function compareBlocksForNavigator(a, b, orderMap) {
        const aId = String(a && a.id ? a.id : "");
        const bId = String(b && b.id ? b.id : "");
        const fallbackA = Math.max(
            0,
            state.layout.findIndex(function (row) {
                return String(row && row.id ? row.id : "") === aId;
            })
        );
        const fallbackB = Math.max(
            0,
            state.layout.findIndex(function (row) {
                return String(row && row.id ? row.id : "") === bId;
            })
        );
        const aOrder =
            orderMap && Object.prototype.hasOwnProperty.call(orderMap, aId)
                ? Number(orderMap[aId] || 0)
                : 100000 + fallbackA;
        const bOrder =
            orderMap && Object.prototype.hasOwnProperty.call(orderMap, bId)
                ? Number(orderMap[bId] || 0)
                : 100000 + fallbackB;
        return aOrder - bOrder;
    }

    function sortBlocksForNavigator(blocks, orderMap) {
        return (Array.isArray(blocks) ? blocks.slice() : []).sort(function (a, b) {
            return compareBlocksForNavigator(a, b, orderMap);
        });
    }

    function navigatorColumnGroups(block, orderMap) {
        if (!block || !isContainerType(block.type)) {
            return [];
        }
        const blockId = String(block.id || "");
        if (blockId === "") {
            return [];
        }
        const settings =
            block.settings && typeof block.settings === "object"
                ? block.settings
                : {};
        const configuredColumns = Math.max(
            1,
            Math.min(MAX_COLUMNS, Number(settings.columns || 2) || 2)
        );
        const labels = splitTextItems(String(settings.column_labels || "Column 1|Column 2"));
        const bySlot = {};
        state.layout.forEach(function (row) {
            if (String(row && row.parent_id ? row.parent_id : "") !== blockId) {
                return;
            }
            const slot = normalizedSlot(row && row.slot ? row.slot : 0);
            if (!Array.isArray(bySlot[slot])) {
                bySlot[slot] = [];
            }
            bySlot[slot].push(row);
        });

        const slots = [];
        for (let i = 0; i < configuredColumns; i += 1) {
            slots.push(i);
        }
        Object.keys(bySlot).forEach(function (slotKey) {
            const slot = normalizedSlot(slotKey);
            if (slots.indexOf(slot) < 0) {
                slots.push(slot);
            }
        });
        slots.sort(function (a, b) {
            return a - b;
        });

        return slots.map(function (slot) {
            const label = labels[slot] || "Column " + String(slot + 1);
            return {
                slot: slot,
                label: label,
                children: Array.isArray(bySlot[slot])
                    ? sortBlocksForNavigator(bySlot[slot], orderMap)
                    : [],
            };
        });
    }

    function blockLabel(block, index) {
        const settings =
            block && block.settings && typeof block.settings === "object"
                ? block.settings
                : {};
        const prefix = "";
        const adminLabel = String(settings.advanced_admin_label || "").trim();
        if (adminLabel !== "") {
            return prefix + adminLabel;
        }
        if (block.type === "heading") {
            return prefix + "Heading: " + String(settings.text || "Heading");
        }
        if (block.type === "section") {
            return prefix + "Section (" + String(settings.columns || 2) + " cols)";
        }
        if (block.type === "text") {
            return prefix + "Text: " + shortText(String(settings.text || ""), 36);
        }
        if (block.type === "button") {
            return prefix + "Button: " + String(settings.label || "Button");
        }
        if (block.type === "shortcode") {
            const widgetLabel = String(settings.widget_label || "").trim();
            if (widgetLabel !== "") {
                return prefix + widgetLabel;
            }
            const spec = parseShortcodeEditorValue(
                String(settings.shortcode || "")
            );
            return prefix + (spec.tag ? "Widget: " + spec.tag : "Shortcode");
        }
        if (block.type === "commerce_indicator") {
            return prefix + "Commerce: " + String(settings.label || settings.source || "Indicator");
        }
        if (block.type === "slider") {
            return prefix + "Slider #" + String(settings.slider_id || 0);
        }
        if (block.type === "image") {
            return prefix + "Image";
        }
        if (block.type === "html") {
            return prefix + "HTML Block";
        }
        if (block.type === "spacer") {
            return prefix + "Spacer";
        }
        if (block.type === "divider") {
            return prefix + "Divider";
        }
        if (block.type === "video") {
            return prefix + "Video";
        }
        if (block.type === "icon") {
            return prefix + "Icon";
        }
        if (block.type === "list") {
            return prefix + "List";
        }
        if (block.type === "quote") {
            return prefix + "Quote";
        }
        if (block.type === "cta") {
            return prefix + "CTA: " + String(settings.title || "Call To Action");
        }
        if (block.type === "gallery") {
            return prefix + "Gallery";
        }
        if (block.type === "map") {
            return prefix + "Map";
        }
        if (block.type === "faq") {
            return prefix + "FAQ";
        }
        if (block.type === "counter") {
            return prefix + "Counter: " + String(settings.value || "0");
        }
        if (block.type === "progress") {
            return prefix + "Progress";
        }
        if (block.type === "menu") {
            return prefix + "Menu";
        }
        if (block.type === "container") {
            return prefix + "Container (" + String(settings.columns || 2) + " cols)";
        }
        if (block.type === "inner_section") {
            return prefix + "Inner Section";
        }
        return prefix + "Block " + String(index + 1);
    }

    function shortText(value, max) {
        if (value.length <= max) {
            return value;
        }
        return value.slice(0, max) + "...";
    }

    function siblingContext(blockId) {
        const id = String(blockId || "");
        const block = findBlockById(id);
        if (!block) {
            return null;
        }
        const parentId = String(block.parent_id || "");
        const slot = normalizedSlot(block.slot || 0);
        const siblings = state.layout
            .filter(function (candidate) {
                return (
                    String(candidate && candidate.parent_id ? candidate.parent_id : "") ===
                        parentId &&
                    normalizedSlot(candidate && candidate.slot ? candidate.slot : 0) === slot
                );
            })
            .sort(function (a, b) {
                return state.layout.indexOf(a) - state.layout.indexOf(b);
            });
        const siblingIndex = siblings.findIndex(function (candidate) {
            return String(candidate && candidate.id ? candidate.id : "") === id;
        });
        if (siblingIndex < 0) {
            return null;
        }
        return {
            block: block,
            parent_id: parentId,
            slot: slot,
            siblings: siblings,
            siblingIndex: siblingIndex,
        };
    }

    function blockTreeIds(blockId) {
        const rootId = String(blockId || "");
        const ids = new Set(rootId !== "" ? [rootId] : []);
        let changed = true;
        while (changed) {
            changed = false;
            state.layout.forEach(function (block) {
                const id = String(block && block.id ? block.id : "");
                const parentId = String(
                    block && block.parent_id ? block.parent_id : ""
                );
                if (id !== "" && ids.has(parentId) && !ids.has(id)) {
                    ids.add(id);
                    changed = true;
                }
            });
        }
        return ids;
    }

    function prepareSelectionStructureChange() {
        if (state.modalMode && state.modalDirty) {
            updateSelectionStatus(
                "Save or cancel the open element changes before changing page order."
            );
            if (els.modalSaveButton instanceof HTMLElement) {
                els.modalSaveButton.focus();
            }
            return false;
        }
        if (state.modalMode) {
            closeBuilderModal(true);
        }
        return true;
    }

    function updateSelectionStatus(message) {
        if (els.selectionStatus) {
            els.selectionStatus.textContent = String(message || "");
        }
    }

    function syncPendingInsertTarget() {
        const target =
            state.pendingInsertTarget &&
            typeof state.pendingInsertTarget === "object"
                ? state.pendingInsertTarget
                : null;
        if (!els.insertTarget) {
            return;
        }
        els.insertTarget.hidden = !target;
        if (els.insertTargetLabel) {
            els.insertTargetLabel.textContent = target
                ? String(target.label || "Choose what to add at the selected location.")
                : "";
        }
    }

    function clearPendingInsertTarget() {
        state.pendingInsertTarget = null;
        syncPendingInsertTarget();
    }

    function clearPendingInsertWhenSelectionChanges(blockId) {
        const pending =
            state.pendingInsertTarget &&
            typeof state.pendingInsertTarget === "object"
                ? state.pendingInsertTarget
                : null;
        if (
            pending &&
            String(pending.anchor_id || "") !== String(blockId || "")
        ) {
            clearPendingInsertTarget();
        }
    }

    function requestContextualInsert(blockId, position) {
        const context = siblingContext(blockId);
        if (!context || !prepareSelectionStructureChange()) {
            return;
        }
        const mode = String(position || "after");
        const anchorLabel = blockLabel(
            context.block,
            Math.max(0, state.layout.indexOf(context.block))
        );
        let target = null;
        if (mode === "inside") {
            if (!isContainerType(String(context.block.type || ""))) {
                return;
            }
            const slot = els.selectionSlot
                ? normalizedSlot(els.selectionSlot.value || 0)
                : 0;
            const children = state.layout.filter(function (candidate) {
                return (
                    String(candidate && candidate.parent_id ? candidate.parent_id : "") ===
                        String(context.block.id || "") &&
                    normalizedSlot(candidate && candidate.slot ? candidate.slot : 0) === slot
                );
            });
            target = {
                anchor_id: String(context.block.id || ""),
                parent_id: String(context.block.id || ""),
                slot: slot,
                index: children.length,
                label:
                    "Adding inside " +
                    anchorLabel +
                    ", column " +
                    String(slot + 1) +
                    ". Choose an element.",
            };
        } else if (context.parent_id !== "") {
            target = {
                anchor_id: String(context.block.id || ""),
                parent_id: context.parent_id,
                slot: context.slot,
                index:
                    context.siblingIndex +
                    (mode === "before" ? 0 : 1),
                label:
                    "Adding " +
                    (mode === "before" ? "before " : "after ") +
                    anchorLabel +
                    ". Choose an element.",
            };
        } else {
            const groupIds = blockTreeIds(context.block.id);
            const indexes = state.layout
                .map(function (candidate, index) {
                    return groupIds.has(String(candidate && candidate.id ? candidate.id : ""))
                        ? index
                        : -1;
                })
                .filter(function (index) {
                    return index >= 0;
                });
            const first = indexes.length ? Math.min.apply(null, indexes) : 0;
            const last = indexes.length
                ? Math.max.apply(null, indexes)
                : state.layout.length - 1;
            target = {
                anchor_id: String(context.block.id || ""),
                parent_id: "",
                slot: 0,
                index: mode === "before" ? first : last + 1,
                label:
                    "Adding " +
                    (mode === "before" ? "before " : "after ") +
                    anchorLabel +
                    ". Choose an element.",
            };
        }

        state.pendingInsertTarget = target;
        state.inspectorAutoCollapsedSide = false;
        state.sideCollapsed = false;
        persistStoredBoolean(SIDE_COLLAPSED_KEY, false);
        applySidePanelState();
        activateLibraryTab("elements", true);
        syncPendingInsertTarget();
        updateSelectionStatus(String(target.label || "Choose an element."));
        window.requestAnimationFrame(function () {
            if (els.elementSearch instanceof HTMLElement) {
                els.elementSearch.focus();
            }
        });
    }

    function moveBlockBySibling(blockId, direction) {
        const context = siblingContext(blockId);
        const offset = Number(direction || 0) < 0 ? -1 : 1;
        if (!context || !prepareSelectionStructureChange()) {
            return false;
        }
        const targetSibling = context.siblings[context.siblingIndex + offset] || null;
        if (!targetSibling) {
            return false;
        }
        captureHistoryBeforeMutation();
        const selectedIds = blockTreeIds(context.block.id);
        const targetIds = blockTreeIds(targetSibling.id);
        const selectedRows = state.layout.filter(function (candidate) {
            return selectedIds.has(String(candidate && candidate.id ? candidate.id : ""));
        });
        const remaining = state.layout.filter(function (candidate) {
            return !selectedIds.has(String(candidate && candidate.id ? candidate.id : ""));
        });
        const targetIndexes = remaining
            .map(function (candidate, index) {
                return targetIds.has(String(candidate && candidate.id ? candidate.id : ""))
                    ? index
                    : -1;
            })
            .filter(function (index) {
                return index >= 0;
            });
        if (!targetIndexes.length) {
            return false;
        }
        const insertAt =
            offset < 0
                ? Math.min.apply(null, targetIndexes)
                : Math.max.apply(null, targetIndexes) + 1;
        remaining.splice.apply(remaining, [insertAt, 0].concat(selectedRows));
        state.layout = remaining;
        state.selectedId = String(context.block.id || "");
        setDirty(true);
        renderAll();
        updateSelectionStatus(offset < 0 ? "Moved earlier." : "Moved later.");
        return true;
    }

    function syncSelectionActionBar() {
        if (!els.selectionActions) {
            return;
        }
        const block = findBlockById(state.selectedId);
        const hidden = !block || state.parityMode;
        els.selectionActions.hidden = hidden;
        if (hidden) {
            return;
        }
        const index = Math.max(0, state.layout.indexOf(block));
        if (els.selectionLabel) {
            els.selectionLabel.textContent = blockLabel(block, index);
        }
        const context = siblingContext(block.id);
        const canMoveUp = !!context && context.siblingIndex > 0;
        const canMoveDown =
            !!context && context.siblingIndex < context.siblings.length - 1;
        els.selectionButtons.forEach(function (button) {
            if (!(button instanceof HTMLButtonElement)) {
                return;
            }
            const action = String(
                button.getAttribute("data-h4bs-selection-action") || ""
            );
            if (action === "up") {
                button.disabled = !canMoveUp;
            } else if (action === "down") {
                button.disabled = !canMoveDown;
            }
        });

        const isContainer = isContainerType(String(block.type || ""));
        if (els.selectionInside) {
            els.selectionInside.hidden = !isContainer;
        }
        if (isContainer && els.selectionSlot) {
            const settings =
                block.settings && typeof block.settings === "object"
                    ? block.settings
                    : {};
            const columns = Math.max(
                1,
                Math.min(MAX_COLUMNS, Number(settings.columns || 2) || 2)
            );
            const previous = normalizedSlot(els.selectionSlot.value || 0);
            els.selectionSlot.innerHTML = "";
            for (let slot = 0; slot < columns; slot += 1) {
                const option = document.createElement("option");
                option.value = String(slot);
                option.textContent = "Column " + String(slot + 1);
                option.selected = slot === Math.min(previous, columns - 1);
                els.selectionSlot.appendChild(option);
            }
        }
        syncPendingInsertTarget();
    }

    function initSelectionActionBar() {
        els.selectionButtons.forEach(function (button) {
            if (!(button instanceof HTMLButtonElement)) {
                return;
            }
            button.addEventListener("click", function () {
                const blockId = String(state.selectedId || "");
                if (blockId === "") {
                    return;
                }
                const action = String(
                    button.getAttribute("data-h4bs-selection-action") || ""
                );
                if (action === "edit") {
                    openBlockModal(blockId);
                    return;
                }
                if (["before", "after", "inside"].includes(action)) {
                    requestContextualInsert(blockId, action);
                    return;
                }
                if (action === "up" || action === "down") {
                    moveBlockBySibling(blockId, action === "up" ? -1 : 1);
                    return;
                }
                if (action === "duplicate") {
                    if (!prepareSelectionStructureChange()) {
                        return;
                    }
                    duplicateBlock(blockId);
                    updateSelectionStatus("Element duplicated. The copy is selected.");
                    return;
                }
                if (action === "delete") {
                    if (!prepareSelectionStructureChange()) {
                        return;
                    }
                    const beforeCount = state.layout.length;
                    deleteBlock(blockId);
                    if (state.layout.length < beforeCount) {
                        updateSelectionStatus("Element removed. Undo is available.");
                    }
                }
            });
        });
        if (els.insertTargetCancel) {
            els.insertTargetCancel.addEventListener("click", function () {
                clearPendingInsertTarget();
                updateSelectionStatus("Contextual insertion canceled.");
            });
        }
        syncSelectionActionBar();
    }

    function duplicateBlock(blockId) {
        const idx = state.layout.findIndex(function (block) {
            return String(block.id) === blockId;
        });
        if (idx < 0) {
            return;
        }
        captureHistoryBeforeMutation();
        const original = state.layout[idx];
        const treeIds = isContainerType(String(original.type || ""))
            ? blockTreeIds(blockId)
            : new Set([blockId]);
        const sourceRows = state.layout.filter(function (block) {
            return treeIds.has(String(block && block.id ? block.id : ""));
        });
        const idMap = {};
        sourceRows.forEach(function (source, offset) {
            idMap[String(source.id || "")] = makeId(
                String(source.type || "text"),
                idx + offset + 1
            );
        });
        const copies = sourceRows.map(function (source) {
            const copy = deepClone(source);
            const sourceId = String(source.id || "");
            const sourceParent = String(source.parent_id || "");
            copy.id = String(idMap[sourceId] || makeId(String(copy.type || "text"), idx + 1));
            if (Object.prototype.hasOwnProperty.call(idMap, sourceParent)) {
                copy.parent_id = String(idMap[sourceParent]);
            }
            return copy;
        });
        const sourceIndexes = state.layout
            .map(function (block, index) {
                return treeIds.has(String(block && block.id ? block.id : ""))
                    ? index
                    : -1;
            })
            .filter(function (index) {
                return index >= 0;
            });
        const insertAt = sourceIndexes.length
            ? Math.max.apply(null, sourceIndexes) + 1
            : idx + 1;
        state.layout.splice.apply(state.layout, [insertAt, 0].concat(copies));
        state.selectedId = String(idMap[blockId] || (copies[0] && copies[0].id) || "");
        setDirty(true);
        renderAll();
    }

    function deleteBlock(blockId) {
        const idx = state.layout.findIndex(function (block) {
            return String(block.id) === blockId;
        });
        if (idx < 0) {
            return;
        }
        if (!window.confirm("Delete this block?")) {
            return;
        }
        captureHistoryBeforeMutation();
        const deleting = state.layout[idx];
        const removeIds = new Set([blockId]);
        if (deleting && isContainerType(String(deleting.type || ""))) {
            let foundDescendant = true;
            while (foundDescendant) {
                foundDescendant = false;
                state.layout.forEach(function (block) {
                    const id = String(block && block.id ? block.id : "");
                    const parentId = String(
                        block && block.parent_id ? block.parent_id : ""
                    );
                    if (id !== "" && removeIds.has(parentId) && !removeIds.has(id)) {
                        removeIds.add(id);
                        foundDescendant = true;
                    }
                });
            }
        }
        state.layout = state.layout.filter(function (block) {
            return !removeIds.has(String(block && block.id ? block.id : ""));
        });
        if (removeIds.has(String(state.selectedId || ""))) {
            state.selectedId = state.layout[0] ? String(state.layout[0].id) : null;
        }
        if (removeIds.has(String(state.modalBlockId || ""))) {
            closeBuilderModal(true);
        }
        setDirty(true);
        renderAll();
    }

    function responsiveStructureFields() {
        const alignOptions = ["stretch", "flex-start", "center", "flex-end", "baseline"];
        const alignContentOptions = [
            "stretch",
            "flex-start",
            "center",
            "flex-end",
            "space-between",
            "space-around",
            "space-evenly",
        ];
        const justifyOptions = [
            "flex-start",
            "center",
            "flex-end",
            "space-between",
            "space-around",
            "space-evenly",
        ];
        return [
            { key: "layout_mode_tablet", label: "Tablet Layout Mode", type: "select", options: [{ value: "", label: "Inherit desktop" }, "grid", "flex"], default: "" },
            { key: "layout_mode_mobile", label: "Mobile Layout Mode", type: "select", options: [{ value: "", label: "Inherit tablet" }, "grid", "flex"], default: "" },
            { key: "columns_tablet", label: "Tablet Columns", type: "number", default: "" },
            { key: "columns_mobile", label: "Mobile Columns", type: "number", default: "" },
            { key: "column_widths_tablet", label: "Tablet Column Width Split (%)", type: "text", default: "" },
            { key: "column_widths_mobile", label: "Mobile Column Width Split (%)", type: "text", default: "" },
            { key: "gap_tablet", label: "Tablet Gap (px)", type: "number", default: "" },
            { key: "gap_mobile", label: "Mobile Gap (px)", type: "number", default: "" },
            { key: "min_height_tablet", label: "Tablet Min Height (px)", type: "number", default: "" },
            { key: "min_height_mobile", label: "Mobile Min Height (px)", type: "number", default: "" },
            {
                key: "content_width_mode_tablet",
                label: "Tablet Width Mode",
                type: "select",
                options: [{ value: "", label: "Inherit desktop" }, "inherit", "custom", "full"],
                default: "",
            },
            {
                key: "content_width_mode_mobile",
                label: "Mobile Width Mode",
                type: "select",
                options: [{ value: "", label: "Inherit tablet" }, "inherit", "custom", "full"],
                default: "",
            },
            {
                key: "content_width_tablet",
                label: "Tablet Max Width",
                type: "size",
                unit_key: "content_width_tablet_unit",
                unit_default: "px",
                units: ["px", "%", "vw", "rem", "em"],
                default: "",
            },
            {
                key: "content_width_mobile",
                label: "Mobile Max Width",
                type: "size",
                unit_key: "content_width_mobile_unit",
                unit_default: "%",
                units: ["px", "%", "vw", "rem", "em"],
                default: "",
            },
            { key: "align_items_tablet", label: "Tablet Align Items", type: "select", options: [{ value: "", label: "Inherit desktop" }].concat(alignOptions), default: "" },
            { key: "align_items_mobile", label: "Mobile Align Items", type: "select", options: [{ value: "", label: "Inherit desktop" }].concat(alignOptions), default: "" },
            { key: "justify_content_tablet", label: "Tablet Justify Content", type: "select", options: [{ value: "", label: "Inherit desktop" }].concat(justifyOptions), default: "" },
            { key: "justify_content_mobile", label: "Mobile Justify Content", type: "select", options: [{ value: "", label: "Inherit desktop" }].concat(justifyOptions), default: "" },
            { key: "flex_direction_tablet", label: "Tablet Flex Direction", type: "select", options: [{ value: "", label: "Inherit desktop" }, "row", "row-reverse", "column", "column-reverse"], default: "" },
            { key: "flex_direction_mobile", label: "Mobile Flex Direction", type: "select", options: [{ value: "", label: "Inherit desktop" }, "row", "row-reverse", "column", "column-reverse"], default: "" },
            { key: "flex_wrap_tablet", label: "Tablet Flex Wrap", type: "select", options: [{ value: "", label: "Inherit desktop" }, "nowrap", "wrap", "wrap-reverse"], default: "" },
            { key: "flex_wrap_mobile", label: "Mobile Flex Wrap", type: "select", options: [{ value: "", label: "Inherit tablet" }, "nowrap", "wrap", "wrap-reverse"], default: "" },
            { key: "align_content_tablet", label: "Tablet Align Content", type: "select", options: [{ value: "", label: "Inherit desktop" }].concat(alignContentOptions), default: "" },
            { key: "align_content_mobile", label: "Mobile Align Content", type: "select", options: [{ value: "", label: "Inherit tablet" }].concat(alignContentOptions), default: "" },
        ];
    }

    function parseShortcodeEditorValue(rawValue) {
        const source = String(rawValue || "").trim();
        const match = source.match(/^\[([a-zA-Z0-9_-]+)([^\]]*)\]([\s\S]*)$/);
        if (!match) {
            return { tag: "", attributes: [], suffix: "" };
        }
        const attributes = [];
        const attributeSource = String(match[2] || "");
        const pattern = /([a-zA-Z0-9_-]+)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s\]]+))/g;
        let attributeMatch;
        while ((attributeMatch = pattern.exec(attributeSource)) !== null) {
            attributes.push({
                key: String(attributeMatch[1] || ""),
                value: String(
                    typeof attributeMatch[2] !== "undefined"
                        ? attributeMatch[2]
                        : typeof attributeMatch[3] !== "undefined"
                        ? attributeMatch[3]
                        : attributeMatch[4] || ""
                ),
            });
        }
        return {
            tag: String(match[1] || ""),
            attributes: attributes,
            suffix: String(match[3] || ""),
        };
    }

    function shortcodeAttributeValue(rawValue) {
        return String(rawValue || "")
            .replace(/&/g, "&amp;")
            .replace(/"/g, "&quot;");
    }

    function buildShortcodeEditorValue(spec) {
        if (!spec || typeof spec !== "object" || !spec.tag) {
            return "";
        }
        const attributes = Array.isArray(spec.attributes)
            ? spec.attributes
                  .filter(function (attribute) {
                      return /^[a-zA-Z0-9_-]+$/.test(
                          String(attribute && attribute.key ? attribute.key : "")
                      );
                  })
                  .map(function (attribute) {
                      return (
                          String(attribute.key) +
                          '=\"' +
                          shortcodeAttributeValue(attribute.value) +
                          '\"'
                      );
                  })
            : [];
        return (
            "[" +
            String(spec.tag) +
            (attributes.length ? " " + attributes.join(" ") : "") +
            "]" +
            String(spec.suffix || "")
        );
    }

    function widgetForShortcodeBlock(modalBlock, spec) {
        const settings =
            modalBlock && modalBlock.settings && typeof modalBlock.settings === "object"
                ? modalBlock.settings
                : {};
        const storedSlug = String(settings.widget_slug || "").trim();
        const catalog = widgetCatalog();
        if (storedSlug !== "") {
            const stored = catalog.find(function (item) {
                return String(item && item.slug ? item.slug : "") === storedSlug;
            });
            if (stored) {
                return stored;
            }
        }
        const tag = String(spec && spec.tag ? spec.tag : "");
        if (tag === "") {
            return null;
        }
        return (
            catalog.find(function (item) {
                const itemSpec = parseShortcodeEditorValue(
                    String(item && item.shortcode ? item.shortcode : "")
                );
                return itemSpec.tag === tag;
            }) || null
        );
    }

    function widgetControlDefinitions(widget) {
        if (!widget || !Array.isArray(widget.controls)) {
            return [];
        }
        return widget.controls
            .filter(function (control) {
                return (
                    control &&
                    typeof control === "object" &&
                    /^[a-zA-Z0-9_-]+$/.test(String(control.key || ""))
                );
            })
            .map(function (control) {
                return {
                    key: String(control.key || ""),
                    label: String(control.label || control.key || "Option"),
                    type: ["text", "number", "select"].includes(
                        String(control.type || "text")
                    )
                        ? String(control.type || "text")
                        : "text",
                    default: String(control.default || ""),
                    options: normalizeSelectOptions(control.options || []),
                };
            });
    }

    function advancedFieldsForType(type) {
        return [
            { key: "advanced_admin_label", label: "Navigator Label", type: "text", default: "" },
            { key: "advanced_css_classes", label: "CSS Classes", type: "text", default: "" },
            { key: "advanced_anchor_id", label: "Anchor ID", type: "text", default: "" },
            { key: "advanced_html_title", label: "HTML Title", type: "text", default: "" },
            { key: "advanced_aria_label", label: "Accessible Label", type: "text", default: "" },
            {
                key: "advanced_role",
                label: "Semantic Role",
                type: "select",
                options: [
                    { value: "", label: "Automatic" },
                    "region",
                    "navigation",
                    "main",
                    "banner",
                    "contentinfo",
                    "complementary",
                    "article",
                    "form",
                    "search",
                    "group",
                ],
                default: "",
            },
            {
                key: "advanced_tabindex",
                label: "Keyboard Tab Order",
                type: "select",
                options: [
                    { value: "", label: "Automatic" },
                    { value: "0", label: "Include in natural order" },
                    { value: "-1", label: "Programmatic focus only" },
                ],
                default: "",
            },
            {
                key: "advanced_aria_hidden",
                label: "Hide From Assistive Technology",
                type: "select",
                options: [
                    { value: "0", label: "No" },
                    { value: "1", label: "Yes" },
                ],
                default: "0",
            },
            {
                key: "advanced_data_attributes",
                label: "Data Attributes (one name=value per line)",
                type: "textarea",
                rows: 5,
                default: "",
            },
        ];
    }

    function inspectorContractSnapshot() {
        const blockContracts = (Array.isArray(data.blockTypes)
            ? data.blockTypes
            : []
        ).map(function (item) {
            const type = String(item && item.slug ? item.slug : "");
            return {
                type: type,
                content: blockFieldsByType(type).map(function (field) {
                    return {
                        key: String(field.key || ""),
                        type: String(field.type || "text"),
                    };
                }),
                design: designFieldsForType(type).map(function (field) {
                    return {
                        key: String(field.key || field.label || ""),
                        type: String(field.type || "text"),
                    };
                }),
                advanced: advancedFieldsForType(type).map(function (field) {
                    return {
                        key: String(field.key || ""),
                        type: String(field.type || "text"),
                    };
                }),
                preview: String(item && item.preview_mode ? item.preview_mode : ""),
            };
        });
        const widgetContracts = widgetCatalog().map(function (widget) {
            const spec = parseShortcodeEditorValue(
                String(widget && widget.shortcode ? widget.shortcode : "")
            );
            return {
                slug: String(widget && widget.slug ? widget.slug : ""),
                blockType: String(
                    widget && (widget.block_type || widget.blockType)
                        ? widget.block_type || widget.blockType
                        : "shortcode"
                ),
                shortcodeTag: spec.tag,
                parameterCount: spec.attributes.length,
                availableControlCount: widgetControlDefinitions(widget).length,
                structured: spec.tag !== "" || !!(widget && widget.block_type),
            };
        });
        return {
            schemaVersion: "1.1",
            blocks: blockContracts,
            widgets: widgetContracts,
        };
    }

    function backgroundVideoFields() {
        return [
            { key: "background_video_enabled", label: "Background Video", type: "select", options: [{ value: "0", label: "Off" }, { value: "1", label: "On" }], default: "0" },
            { key: "background_video_hls", label: "HLS Manifest URL (.m3u8)", type: "text", default: "" },
            { key: "background_video_src", label: "Primary MP4 / M4V / WebM / Ogg URL", type: "text", default: "" },
            { key: "background_video_media_src", label: "Media Library Primary Video", type: "media", mediaType: "video", attachmentKey: "background_video_media_attachment_id", allowManualInput: false, default: "" },
            { key: "background_video_fallback_src", label: "Fallback Video URL", type: "text", default: "" },
            { key: "background_video_fallback_media_src", label: "Media Library Fallback Video", type: "media", mediaType: "video", attachmentKey: "background_video_fallback_media_attachment_id", allowManualInput: false, default: "" },
            { key: "background_video_poster", label: "Poster Image URL", type: "text", imageProfile: "video_poster", default: "" },
            { key: "background_video_poster_media_src", label: "Media Library Poster", type: "media", mediaType: "image", imageProfile: "video_poster", attachmentKey: "background_video_poster_attachment_id", allowManualInput: false, default: "" },
            { key: "background_video_failure_image", label: "Playback Failure Image URL", type: "text", imageProfile: "video_poster", default: "" },
            { key: "background_video_failure_image_media_src", label: "Media Library Failure Image", type: "media", mediaType: "image", imageProfile: "video_poster", attachmentKey: "background_video_failure_image_attachment_id", allowManualInput: false, default: "" },
            { key: "background_video_autoplay", label: "Autoplay (always muted)", type: "select", options: [{ value: "1", label: "On" }, { value: "0", label: "Off" }], default: "1" },
            { key: "background_video_muted", label: "Muted", type: "select", options: [{ value: "1", label: "On" }, { value: "0", label: "Off" }], default: "1" },
            { key: "background_video_loop", label: "Loop", type: "select", options: [{ value: "1", label: "On" }, { value: "0", label: "Off" }], default: "1" },
            { key: "background_video_controls", label: "Controls (non-decorative only)", type: "select", options: [{ value: "0", label: "Off" }, { value: "1", label: "On" }], default: "0" },
            { key: "background_video_preload", label: "Preload", type: "select", options: ["none", "metadata", "auto"], default: "metadata" },
            { key: "background_video_fit", label: "Video Fit", type: "select", options: ["cover", "contain"], default: "cover" },
            { key: "background_video_position", label: "Desktop Focal Position", type: "text", default: "center center" },
            { key: "background_video_position_tablet", label: "Tablet Focal Position", type: "text", default: "center center" },
            { key: "background_video_position_mobile", label: "Mobile Focal Position", type: "text", default: "center center" },
            { key: "background_video_overflow", label: "Edge Clipping", type: "select", options: ["hidden", "clip"], default: "hidden" },
            { key: "background_video_overlay_color", label: "Overlay Color", type: "color", default: "#000000" },
            { key: "background_video_overlay_gradient", label: "Overlay Gradient (CSS)", type: "text", default: "" },
            { key: "background_video_overlay_opacity", label: "Overlay Opacity (0 to 1)", type: "text", default: "0.35" },
            { key: "background_video_decorative", label: "Decorative Background", type: "select", options: [{ value: "1", label: "Yes (recommended)" }, { value: "0", label: "No" }], default: "1" },
            { key: "background_video_title", label: "Accessible Video Label", type: "text", default: "Background video" },
        ];
    }

    function blockFieldsByType(type) {
        if (type === "section") {
            return [
                { key: "columns", label: "Columns", type: "number", default: 2 },
                { key: "gap", label: "Column Gap (px)", type: "number", default: 18 },
                { key: "min_height", label: "Min Height (px)", type: "number", default: 140 },
                { key: "column_labels", label: "Column Labels (pipe separated)", type: "text", default: "Column 1|Column 2" },
                {
                    key: "column_widths",
                    label: "Column Width Split (%)",
                    type: "text",
                    default: "",
                },
                {
                    key: "layout_mode",
                    label: "Layout Mode",
                    type: "select",
                    options: [
                        { value: "grid", label: "Grid (columns)" },
                        { value: "flex", label: "Flex (free flow)" },
                    ],
                    default: "grid",
                },
                {
                    key: "content_width_mode",
                    label: "Section Container Width Mode",
                    type: "select",
                    options: [
                        { value: "inherit", label: "Use global container width" },
                        { value: "custom", label: "Custom container width" },
                        { value: "full", label: "Full width (100%)" },
                    ],
                    default: "inherit",
                },
                {
                    key: "content_width",
                    label: "Section Container Max Width",
                    type: "size",
                    unit_key: "content_width_unit",
                    unit_default: "px",
                    units: ["px", "%", "vw", "vh", "rem", "em"],
                    default: "",
                },
                {
                    key: "flex_direction",
                    label: "Flex Direction",
                    type: "select",
                    options: ["row", "row-reverse", "column", "column-reverse"],
                    default: "row",
                },
                {
                    key: "flex_wrap",
                    label: "Flex Wrap",
                    type: "select",
                    options: ["nowrap", "wrap", "wrap-reverse"],
                    default: "wrap",
                },
                {
                    key: "justify_content",
                    label: "Justify Content",
                    type: "select",
                    options: [
                        "flex-start",
                        "center",
                        "flex-end",
                        "space-between",
                        "space-around",
                        "space-evenly",
                    ],
                    default: "flex-start",
                },
                {
                    key: "align_items",
                    label: "Align Items",
                    type: "select",
                    options: ["stretch", "flex-start", "center", "flex-end", "baseline"],
                    default: "stretch",
                },
                {
                    key: "align_content",
                    label: "Align Content",
                    type: "select",
                    options: [
                        "stretch",
                        "flex-start",
                        "center",
                        "flex-end",
                        "space-between",
                        "space-around",
                        "space-evenly",
                    ],
                    default: "stretch",
                },
            ].concat(backgroundVideoFields(), responsiveStructureFields());
        }
        if (type === "heading") {
            return [
                { key: "text", label: "Text", type: "textarea", rows: 3, default: "Heading" },
                { key: "tag", label: "Tag", type: "select", options: ["h1", "h2", "h3", "h4", "h5", "h6"], default: "h2" },
            ];
        }
        if (type === "text") {
            return [{ key: "text", label: "Text", type: "textarea", rows: 6, default: "" }];
        }
        if (type === "image") {
            return [
                {
                    key: "src",
                    label: "Image",
                    type: "media",
                    mediaType: "image",
                    imageProfile: "content",
                    attachmentKey: "attachment_id",
                    default: "",
                },
                { key: "alt", label: "Alt Text", type: "text", default: "" },
                { key: "title", label: "Image Title", type: "text", default: "" },
                { key: "caption", label: "Caption", type: "text", default: "" },
                { key: "size", label: "Image Size", type: "select", options: ["full", "large", "medium", "thumbnail"], default: "full" },
                { key: "align", label: "Image Align", type: "select", options: ["none", "left", "center", "right"], default: "none" },
                {
                    key: "loading",
                    label: "Loading Priority",
                    type: "select",
                    options: [
                        { value: "auto", label: "Automatic (first header image loads now)" },
                        { value: "eager", label: "Load now (above the fold)" },
                        { value: "lazy", label: "Lazy load (below the fold)" },
                    ],
                    default: "auto",
                },
                {
                    key: "width",
                    label: "Image Width",
                    type: "size",
                    unit_key: "width_unit",
                    unit_default: "%",
                    units: sizeUnitOptions(false),
                    default: "",
                },
                {
                    key: "max_width",
                    label: "Image Max Width",
                    type: "size",
                    unit_key: "max_width_unit",
                    unit_default: "px",
                    units: sizeUnitOptions(false),
                    default: "",
                },
                {
                    key: "height",
                    label: "Image Height",
                    type: "size",
                    unit_key: "height_unit",
                    unit_default: "px",
                    units: sizeUnitOptions(false),
                    default: "",
                },
                { key: "object_fit", label: "Object Fit", type: "select", options: ["cover", "contain", "fill", "none", "scale-down"], default: "cover" },
                {
                    key: "border_radius",
                    label: "Image Border Radius",
                    type: "size",
                    unit_key: "border_radius_unit",
                    unit_default: "px",
                    units: sizeUnitOptions(false),
                    default: "",
                },
                { key: "box_shadow", label: "Image Shadow", type: "text", default: "" },
                { key: "overlay_color", label: "Overlay Color", type: "color", default: "#000000" },
                { key: "overlay_opacity", label: "Overlay Opacity (0 to 1)", type: "text", default: "0" },
                { key: "hover_scale", label: "Hover Scale (ex: 1.05)", type: "text", default: "" },
                { key: "lightbox", label: "Open in lightbox", type: "select", options: [{ value: "0", label: "No" }, { value: "1", label: "Yes" }], default: "0" },
            ];
        }
        if (type === "button") {
            return [
                { key: "label", label: "Label", type: "text", default: "Button" },
                { key: "url", label: "URL", type: "text", default: "#" },
                { key: "target", label: "Open Link", type: "select", options: [{ value: "same", label: "Same tab" }, { value: "new", label: "New tab" }], default: "same" },
                { key: "rel", label: "Link Relationship", type: "text", default: "" },
            ];
        }
        if (type === "shortcode") {
            return [{ key: "shortcode", label: "Widget Settings", type: "shortcode_builder", rows: 5, default: "" }];
        }
        if (type === "product_reviews") {
            return [
                { key: "product_id", label: "Product ID", type: "number", default: 0 },
                { key: "limit", label: "Reviews To Show", type: "number", default: 5 },
                {
                    key: "title",
                    label: "Widget Title (optional)",
                    type: "text",
                    default: "",
                },
                {
                    key: "empty_text",
                    label: "Empty State Message",
                    type: "text",
                    default: "No reviews yet.",
                },
                {
                    key: "show_summary",
                    label: "Show Rating Summary",
                    type: "select",
                    options: [
                        { value: "1", label: "Yes" },
                        { value: "0", label: "No" },
                    ],
                    default: "1",
                },
                {
                    key: "show_form",
                    label: "Show Submit Form",
                    type: "select",
                    options: [
                        { value: "1", label: "Yes" },
                        { value: "0", label: "No" },
                    ],
                    default: "1",
                },
            ];
        }
        if (type === "commerce_indicator") {
            return [
                {
                    key: "source",
                    label: "Count Source",
                    type: "select",
                    options: [
                        { value: "cart", label: "Cart" },
                        { value: "wishlist", label: "Wishlist" },
                        { value: "compare", label: "Product Compare" },
                        { value: "notifications", label: "Notifications" },
                        { value: "custom", label: "Custom / Add-on" },
                    ],
                    default: "cart",
                },
                { key: "label", label: "Accessible Label", type: "text", default: "Cart" },
                { key: "url", label: "Destination URL", type: "text", default: "/cart/" },
                { key: "icon_class", label: "Font Awesome Icon Class", type: "text", default: "fa-solid fa-cart-shopping" },
                {
                    key: "show_when_zero",
                    label: "Show Indicator When Count Is Zero",
                    type: "select",
                    options: [
                        { value: "0", label: "Hide at zero" },
                        { value: "1", label: "Show at zero" },
                    ],
                    default: "0",
                },
                {
                    key: "show_quantity",
                    label: "Show Quantity Number",
                    type: "select",
                    options: [
                        { value: "1", label: "Show number" },
                        { value: "0", label: "Hide number" },
                    ],
                    default: "1",
                },
                {
                    key: "show_label",
                    label: "Show Text Label",
                    type: "select",
                    options: [
                        { value: "0", label: "Icon only" },
                        { value: "1", label: "Icon and label" },
                    ],
                    default: "0",
                },
                { key: "max_count", label: "Number Cap Before Plus Sign", type: "number", default: 99 },
                { key: "preview_count", label: "Studio Preview Count", type: "number", default: 0 },
                { key: "storage_key", label: "Browser Storage Key", type: "text", default: "h4bsCommerceCart" },
                { key: "unit_singular", label: "Singular Count Word", type: "text", default: "item" },
                { key: "unit_plural", label: "Plural Count Word", type: "text", default: "items" },
            ];
        }
        if (type === "google_business") {
            return [
                {
                    key: "domain",
                    label: "Business Domain (optional)",
                    type: "text",
                    default: "",
                },
                {
                    key: "view",
                    label: "Display Mode",
                    type: "select",
                    options: [
                        { value: "business", label: "Map + Reviews" },
                        { value: "reviews", label: "Reviews Only" },
                        { value: "map", label: "Map Only" },
                    ],
                    default: "business",
                },
                { key: "reviews", label: "Review Count", type: "number", default: 5 },
                { key: "location", label: "Location Number", type: "number", default: 1 },
                { key: "height", label: "Map Height (px)", type: "number", default: 360 },
                {
                    key: "show_header",
                    label: "Show Domain Header",
                    type: "select",
                    options: [
                        { value: "1", label: "Yes" },
                        { value: "0", label: "No" },
                    ],
                    default: "1",
                },
                {
                    key: "show_aggregate",
                    label: "Show Aggregate Rating",
                    type: "select",
                    options: [
                        { value: "1", label: "Yes" },
                        { value: "0", label: "No" },
                    ],
                    default: "1",
                },
                {
                    key: "show_map",
                    label: "Map Enabled",
                    type: "select",
                    options: [
                        { value: "1", label: "Yes" },
                        { value: "0", label: "No" },
                    ],
                    default: "1",
                },
                {
                    key: "show_reviews",
                    label: "Reviews Enabled",
                    type: "select",
                    options: [
                        { value: "1", label: "Yes" },
                        { value: "0", label: "No" },
                    ],
                    default: "1",
                },
                {
                    key: "show_service_areas",
                    label: "Show Service Areas",
                    type: "select",
                    options: [
                        { value: "1", label: "Yes" },
                        { value: "0", label: "No" },
                    ],
                    default: "1",
                },
                {
                    key: "empty_text",
                    label: "Empty State Message",
                    type: "text",
                    default: "Google Business profile not configured for this domain yet.",
                },
            ];
        }
        if (type === "slider") {
            return [
                { key: "slider_id", label: "Slider ID", type: "number", default: 0 },
                {
                    key: "source",
                    label: "Slide Source",
                    type: "select",
                    options: [
                        { value: "manual", label: "Saved Slider Slides" },
                        { value: "posts", label: "Dynamic WordPress Content" },
                    ],
                    default: "manual",
                },
                { key: "post_type", label: "Dynamic Post Type", type: "text", default: "post" },
                { key: "limit", label: "Dynamic Slide Limit", type: "number", default: 8 },
                { key: "taxonomy", label: "Dynamic Taxonomy", type: "text", default: "" },
                { key: "terms", label: "Dynamic Term Slugs", type: "text", default: "" },
                {
                    key: "orderby",
                    label: "Dynamic Order By",
                    type: "select",
                    options: ["date", "modified", "title", "menu_order", "rand"],
                    default: "date",
                },
                {
                    key: "order",
                    label: "Dynamic Order",
                    type: "select",
                    options: ["DESC", "ASC"],
                    default: "DESC",
                },
                {
                    key: "fit",
                    label: "Image Fit",
                    type: "select",
                    options: [
                        { value: "cover", label: "Cover" },
                        { value: "contain", label: "Contain (full image)" },
                        { value: "fill", label: "Fill" },
                        { value: "stretch", label: "Stretch" },
                        { value: "none", label: "None" },
                    ],
                    default: "contain",
                },
                {
                    key: "snapshot_fit",
                    label: "Website Snapshot Fit",
                    type: "select",
                    options: [
                        { value: "cover", label: "Cover" },
                        { value: "contain", label: "Contain (full screenshot)" },
                        { value: "fill", label: "Fill" },
                        { value: "stretch", label: "Stretch" },
                        { value: "none", label: "None" },
                    ],
                    default: "contain",
                },
                {
                    key: "bg",
                    label: "Side Fill Color",
                    type: "color",
                    default: "#0b1118",
                },
                {
                    key: "height_mode",
                    label: "Height Mode",
                    type: "select",
                    options: [
                        { value: "fixed", label: "Fixed Hero Height" },
                        { value: "auto", label: "Auto (full image height)" },
                    ],
                    default: "fixed",
                },
                {
                    key: "height_px",
                    label: "Desktop Height (px)",
                    type: "number",
                    default: 540,
                },
                { key: "height_tablet", label: "Tablet Height (px)", type: "number", default: 480 },
                { key: "height_mobile", label: "Mobile Height (px)", type: "number", default: 420 },
                {
                    key: "transition",
                    label: "Slide Transition",
                    type: "select",
                    options: [
                        { value: "slide", label: "Slide" },
                        { value: "fade", label: "Fade" },
                        { value: "zoom", label: "Zoom" },
                        { value: "flip", label: "Flip" },
                        { value: "stack", label: "Stack" },
                        { value: "none", label: "None" },
                    ],
                    default: "slide",
                },
                { key: "transition_duration", label: "Transition Duration (ms)", type: "number", default: 600 },
                {
                    key: "easing",
                    label: "Transition Easing",
                    type: "select",
                    options: ["ease", "ease_in", "ease_out", "ease_in_out", "linear", "spring"],
                    default: "ease",
                },
                {
                    key: "motion",
                    label: "Image Motion",
                    type: "select",
                    options: [
                        { value: "none", label: "None (safer framing)" },
                        { value: "zoom_in", label: "Zoom In" },
                        { value: "zoom_out", label: "Zoom Out" },
                        { value: "pan_left", label: "Pan Left" },
                        { value: "pan_right", label: "Pan Right" },
                        { value: "pan_up", label: "Pan Up" },
                        { value: "pan_down", label: "Pan Down" },
                    ],
                    default: "none",
                },
                { key: "motion_duration", label: "Motion Duration (ms)", type: "number", default: 9000 },
                {
                    key: "motion_force",
                    label: "Force Motion on Contain Fit",
                    type: "select",
                    options: [
                        { value: "0", label: "No (keep full image visible)" },
                        { value: "1", label: "Yes (allow animated crop)" },
                    ],
                    default: "0",
                },
                { key: "autoplay", label: "Autoplay (ms, 0=off)", type: "number", default: 4500 },
                { key: "start_index", label: "Starting Slide (0-based)", type: "number", default: 0 },
                ...["loop", "shuffle", "arrows", "dots", "thumbnails", "progress", "pause_button", "pause_on_hover", "pause_out_of_view", "keyboard", "swipe"].map(function (key) {
                    const labels = {
                        loop: "Loop Slides",
                        shuffle: "Shuffle on Load",
                        arrows: "Show Arrows",
                        dots: "Show Dots",
                        thumbnails: "Show Thumbnails",
                        progress: "Show Autoplay Progress",
                        pause_button: "Show Play/Pause",
                        pause_on_hover: "Pause on Hover",
                        pause_out_of_view: "Pause Outside Viewport",
                        keyboard: "Keyboard Navigation",
                        swipe: "Touch and Pointer Swipe",
                    };
                    return {
                        key: key,
                        label: labels[key],
                        type: "select",
                        options: [
                            { value: "1", label: "Yes" },
                            { value: "0", label: "No" },
                        ],
                        default: ["shuffle", "thumbnails"].indexOf(key) >= 0 ? "0" : "1",
                    };
                }),
            ];
        }
        if (type === "html") {
            return [
                { key: "html", label: "HTML source (advanced)", type: "textarea", rows: 7, default: "" },
                { key: "design_background_color", label: "Wrapper Background", type: "text", default: "" },
                {
                    type: "box4",
                    label: "Wrapper Padding",
                    unit_key: "design_padding_unit",
                    unit_default: "px",
                    units: sizeUnitOptions(false),
                    keys: {
                        top: "design_padding_top",
                        right: "design_padding_right",
                        bottom: "design_padding_bottom",
                        left: "design_padding_left",
                    },
                    default: { top: "", right: "", bottom: "", left: "" },
                },
            ];
        }
        if (type === "spacer") {
            return [{ key: "height", label: "Height (px)", type: "number", default: 28 }];
        }
        if (type === "divider") {
            return [
                { key: "thickness", label: "Thickness (px)", type: "number", default: 1 },
                { key: "style", label: "Style", type: "select", options: ["solid", "dashed", "dotted"], default: "solid" },
                { key: "color", label: "Color", type: "text", default: "#dbe7f3" },
            ];
        }
        if (type === "video") {
            return [
                {
                    key: "provider",
                    label: "Provider",
                    type: "select",
                    options: [
                        { value: "youtube", label: "YouTube" },
                        { value: "vimeo", label: "Vimeo" },
                        { value: "selfhosted", label: "Self-hosted MP4/WebM URL" },
                        { value: "hls", label: "HLS stream with video fallback" },
                        { value: "embed", label: "Generic iframe URL" },
                    ],
                    default: "youtube",
                },
                {
                    key: "src",
                    label: "Video URL / ID / Embed URL",
                    type: "text",
                    default: "",
                },
                {
                    key: "hls_src",
                    label: "HLS Manifest URL (.m3u8)",
                    type: "text",
                    default: "",
                },
                {
                    key: "media_src",
                    label: "Media Library Primary / HLS Fallback Video",
                    type: "media",
                    mediaType: "video",
                    attachmentKey: "media_attachment_id",
                    allowManualInput: false,
                    default: "",
                },
                {
                    key: "fallback_src",
                    label: "Fallback MP4 / WebM URL",
                    type: "text",
                    default: "",
                },
                {
                    key: "fallback_media_src",
                    label: "Media Library Fallback Video",
                    type: "media",
                    mediaType: "video",
                    attachmentKey: "fallback_media_attachment_id",
                    allowManualInput: false,
                    default: "",
                },
                {
                    key: "poster_src",
                    label: "Poster Image URL",
                    type: "text",
                    imageProfile: "video_poster",
                    default: "",
                },
                {
                    key: "poster_media_src",
                    label: "Media Library Poster Image",
                    type: "media",
                    mediaType: "image",
                    imageProfile: "video_poster",
                    attachmentKey: "poster_media_attachment_id",
                    allowManualInput: false,
                    default: "",
                },
                {
                    key: "fallback_image_src",
                    label: "Playback Failure Image URL",
                    type: "text",
                    imageProfile: "video_poster",
                    default: "",
                },
                {
                    key: "fallback_image_media_src",
                    label: "Media Library Failure Image",
                    type: "media",
                    mediaType: "image",
                    imageProfile: "video_poster",
                    attachmentKey: "fallback_image_attachment_id",
                    allowManualInput: false,
                    default: "",
                },
                { key: "title", label: "Accessible Player Label", type: "text", default: "Video player" },
                {
                    key: "aspect_ratio",
                    label: "Responsive Aspect Ratio",
                    type: "select",
                    options: ["16:9", "4:3", "1:1", "9:16", "21:9"],
                    default: "16:9",
                },
                { key: "height", label: "Player Height (px)", type: "number", default: 360 },
                {
                    key: "preload",
                    label: "Preload",
                    type: "select",
                    options: [
                        { value: "none", label: "None" },
                        { value: "metadata", label: "Metadata" },
                        { value: "auto", label: "Auto" },
                    ],
                    default: "metadata",
                },
                { key: "autoplay", label: "Autoplay", type: "select", options: [{ value: "0", label: "Off" }, { value: "1", label: "On" }], default: "0" },
                { key: "controls", label: "Controls", type: "select", options: [{ value: "1", label: "Show" }, { value: "0", label: "Hide" }], default: "1" },
                { key: "muted", label: "Muted", type: "select", options: [{ value: "0", label: "Off" }, { value: "1", label: "On" }], default: "0" },
                { key: "loop", label: "Loop", type: "select", options: [{ value: "0", label: "Off" }, { value: "1", label: "On" }], default: "0" },
            ];
        }
        if (type === "icon") {
            return [
                { key: "icon_set", label: "Icon Set", type: "select", options: [{ value: "dashicons", label: "Dashicons" }, { value: "fontawesome", label: "Font Awesome Free" }], default: "dashicons" },
                { key: "icon", label: "Dashicon Class", type: "text", default: "dashicons-star-filled" },
                { key: "fa_class", label: "Font Awesome Class", type: "text", default: "fa-solid fa-star" },
                { key: "color", label: "Icon Color", type: "text", default: "#0f6cbf" },
                { key: "size", label: "Icon Size (px)", type: "number", default: 28 },
                { key: "label", label: "Label (optional)", type: "text", default: "" },
            ];
        }
        if (type === "list") {
            return [
                { key: "items", label: "Items (one per line)", type: "textarea", rows: 6, default: "Item one\nItem two" },
                { key: "ordered", label: "Ordered List", type: "select", options: [{ value: "0", label: "No" }, { value: "1", label: "Yes" }], default: "0" },
            ];
        }
        if (type === "quote") {
            return [
                { key: "text", label: "Quote", type: "textarea", rows: 4, default: "" },
                { key: "cite", label: "Citation", type: "text", default: "" },
            ];
        }
        if (type === "cta") {
            return [
                { key: "title", label: "Title", type: "text", default: "" },
                { key: "heading_tag", label: "Title Heading Level", type: "select", options: ["h2", "h3", "h4", "h5", "h6"], default: "h2" },
                { key: "text", label: "Description", type: "textarea", rows: 4, default: "" },
                { key: "button_label", label: "Button Label", type: "text", default: "Learn More" },
                { key: "button_url", label: "Button URL", type: "text", default: "#" },
                { key: "button_target", label: "Open Button Link", type: "select", options: [{ value: "same", label: "Same tab" }, { value: "new", label: "New tab" }], default: "same" },
                { key: "button_rel", label: "Button Link Relationship", type: "text", default: "" },
            ];
        }
        if (type === "gallery") {
            return [
                { key: "images", label: "Gallery Images", type: "media_multiple", mediaType: "image", imageProfile: "gallery", default: "" },
                { key: "columns", label: "Columns", type: "number", default: 3 },
            ];
        }
        if (type === "map") {
            return [
                { key: "embed_url", label: "Map Embed URL", type: "text", default: "" },
                { key: "height", label: "Height (px)", type: "number", default: 360 },
            ];
        }
        if (type === "faq") {
            return [
                { key: "items", label: "FAQ Items (Question::Answer per line)", type: "textarea", rows: 7, default: "" },
                { key: "open_first", label: "Open first item", type: "select", options: [{ value: "0", label: "No" }, { value: "1", label: "Yes" }], default: "0" },
            ];
        }
        if (type === "collection") {
            return [
                { key: "_collection_preset", label: "Start from a Preset", type: "collection_presets" },
                { key: "fields", label: "Item Field Definitions", type: "collection_filters", default: [{ key: "title", label: "Title" }, { key: "description", label: "Description" }, { key: "group", label: "Group" }, { key: "type", label: "Type" }, { key: "badge", label: "Badge" }, { key: "url", label: "Link URL" }] },
                { key: "items", label: "Collection Items", type: "collection_items", default: [] },
                { key: "filters", label: "Named Filters", type: "collection_filters", default: [{ key: "group", label: "Day" }, { key: "type", label: "Type" }] },
                { key: "default_view", label: "Default View", type: "select", options: [{ value: "grid", label: "Grid by group" }, { value: "list", label: "Filterable list" }], default: "grid" },
                { key: "search_label", label: "Search Label", type: "text", default: "Search items" },
                { key: "grid_label", label: "Grid View Label", type: "text", default: "Grid by group" },
                { key: "list_label", label: "List View Label", type: "text", default: "Filterable list" },
                { key: "empty_text", label: "Empty Results Message", type: "text", default: "No items match your filters." },
                { key: "columns", label: "Desktop Columns", type: "number", default: 3 },
                { key: "columns_tablet", label: "Tablet Columns", type: "number", default: 2 },
                { key: "columns_mobile", label: "Mobile Columns", type: "number", default: 1 },
            ];
        }
        if (type === "calendar") {
            return [
                { key: "source_ids", label: "Source IDs (comma separated; blank shows all)", type: "text", default: "" },
                { key: "presentation", label: "Presentation", type: "select", options: [{ value: "calendar", label: "Calendar cards" }, { value: "list", label: "Accessible list" }], default: "calendar" },
                { key: "show_search", label: "Event Search", type: "select", options: [{ value: "1", label: "Show" }, { value: "0", label: "Hide" }], default: "1" },
                { key: "show_filters", label: "Category Filter", type: "select", options: [{ value: "1", label: "Show" }, { value: "0", label: "Hide" }], default: "1" },
                { key: "empty_text", label: "Empty Results Message", type: "text", default: "No events match your filters." },
                { key: "columns", label: "Desktop Columns", type: "number", default: 3 },
                { key: "columns_tablet", label: "Tablet Columns", type: "number", default: 2 },
                { key: "columns_mobile", label: "Mobile Columns", type: "number", default: 1 },
            ];
        }
        if (type === "staff_directory") {
            return [
                { key: "show_search", label: "Staff Search", type: "select", options: [{ value: "1", label: "Show" }, { value: "0", label: "Hide" }], default: "1" },
                { key: "show_tier_headings", label: "Tier Headings", type: "select", options: [{ value: "1", label: "Show" }, { value: "0", label: "Hide" }], default: "1" },
                { key: "empty_text", label: "Empty Results Message", type: "text", default: "No staff profiles match this view." },
                { key: "columns", label: "Desktop Columns", type: "number", default: 3 },
                { key: "columns_tablet", label: "Tablet Columns", type: "number", default: 2 },
                { key: "columns_mobile", label: "Mobile Columns", type: "number", default: 1 },
            ];
        }
        if (type === "counter") {
            return [
                { key: "value", label: "Value", type: "number", default: 100 },
                { key: "prefix", label: "Prefix", type: "text", default: "" },
                { key: "suffix", label: "Suffix", type: "text", default: "+" },
                { key: "label", label: "Label", type: "text", default: "" },
            ];
        }
        if (type === "progress") {
            return [
                { key: "label", label: "Label", type: "text", default: "Progress" },
                { key: "value", label: "Current Value", type: "number", default: 65 },
                { key: "max", label: "Max Value", type: "number", default: 100 },
            ];
        }
        if (type === "menu") {
            return [
                { key: "menu_slug", label: "WordPress Menu Slug", type: "text", default: "" },
                { key: "orientation", label: "Orientation", type: "select", options: [{ value: "horizontal", label: "Horizontal" }, { value: "vertical", label: "Vertical" }], default: "horizontal" },
                { key: "depth", label: "Menu Depth (0 = all)", type: "number", default: 0 },
                { key: "dropdown_mode", label: "Dropdown Behavior", type: "select", options: [{ value: "hover", label: "Hover / focus" }, { value: "open", label: "Always expanded" }, { value: "none", label: "Top level only" }], default: "hover" },
                { key: "mobile_hamburger", label: "Mobile Hamburger", type: "select", options: [{ value: "1", label: "Enabled" }, { value: "0", label: "Disabled" }], default: "1" },
                { key: "menu_label", label: "Accessible Menu Label", type: "text", default: "Site Menu" },
            ];
        }
        if (type === "container") {
            return [
                { key: "columns", label: "Columns", type: "number", default: 2 },
                { key: "gap", label: "Gap (px)", type: "number", default: 16 },
                { key: "min_height", label: "Min Height (px)", type: "number", default: 120 },
                { key: "column_labels", label: "Column Labels (pipe separated)", type: "text", default: "Column 1|Column 2" },
                {
                    key: "column_widths",
                    label: "Column Width Split (%)",
                    type: "text",
                    default: "",
                },
                {
                    key: "layout_mode",
                    label: "Layout Mode",
                    type: "select",
                    options: [
                        { value: "grid", label: "Grid (columns)" },
                        { value: "flex", label: "Flex (free flow)" },
                    ],
                    default: "grid",
                },
                {
                    key: "content_width_mode",
                    label: "Container Width Mode",
                    type: "select",
                    options: [
                        { value: "inherit", label: "Use global container width" },
                        { value: "custom", label: "Custom container width" },
                        { value: "full", label: "Full width (100%)" },
                    ],
                    default: "inherit",
                },
                {
                    key: "content_width",
                    label: "Container Max Width",
                    type: "size",
                    unit_key: "content_width_unit",
                    unit_default: "px",
                    units: ["px", "%", "vw", "vh", "rem", "em"],
                    default: "",
                },
                {
                    key: "flex_direction",
                    label: "Flex Direction",
                    type: "select",
                    options: ["row", "row-reverse", "column", "column-reverse"],
                    default: "row",
                },
                {
                    key: "flex_wrap",
                    label: "Flex Wrap",
                    type: "select",
                    options: ["nowrap", "wrap", "wrap-reverse"],
                    default: "wrap",
                },
                {
                    key: "justify_content",
                    label: "Justify Content",
                    type: "select",
                    options: [
                        "flex-start",
                        "center",
                        "flex-end",
                        "space-between",
                        "space-around",
                        "space-evenly",
                    ],
                    default: "flex-start",
                },
                {
                    key: "align_items",
                    label: "Align Items",
                    type: "select",
                    options: ["stretch", "flex-start", "center", "flex-end", "baseline"],
                    default: "stretch",
                },
                {
                    key: "align_content",
                    label: "Align Content",
                    type: "select",
                    options: [
                        "stretch",
                        "flex-start",
                        "center",
                        "flex-end",
                        "space-between",
                        "space-around",
                        "space-evenly",
                    ],
                    default: "stretch",
                },
                { key: "note", label: "Container Note", type: "textarea", rows: 3, default: "" },
            ].concat(backgroundVideoFields(), responsiveStructureFields());
        }
        if (type === "inner_section") {
            return [
                { key: "columns", label: "Columns", type: "number", default: 2 },
                { key: "gap", label: "Gap (px)", type: "number", default: 16 },
                { key: "min_height", label: "Min Height (px)", type: "number", default: 120 },
                { key: "column_labels", label: "Column Labels (pipe separated)", type: "text", default: "Column 1|Column 2" },
                {
                    key: "column_widths",
                    label: "Column Width Split (%)",
                    type: "text",
                    default: "",
                },
                {
                    key: "layout_mode",
                    label: "Layout Mode",
                    type: "select",
                    options: [
                        { value: "grid", label: "Grid (columns)" },
                        { value: "flex", label: "Flex (free flow)" },
                    ],
                    default: "grid",
                },
                {
                    key: "content_width_mode",
                    label: "Inner Section Width Mode",
                    type: "select",
                    options: [
                        { value: "inherit", label: "Use global container width" },
                        { value: "custom", label: "Custom container width" },
                        { value: "full", label: "Full width (100%)" },
                    ],
                    default: "inherit",
                },
                {
                    key: "content_width",
                    label: "Inner Section Max Width",
                    type: "size",
                    unit_key: "content_width_unit",
                    unit_default: "px",
                    units: ["px", "%", "vw", "vh", "rem", "em"],
                    default: "",
                },
                {
                    key: "flex_direction",
                    label: "Flex Direction",
                    type: "select",
                    options: ["row", "row-reverse", "column", "column-reverse"],
                    default: "row",
                },
                {
                    key: "flex_wrap",
                    label: "Flex Wrap",
                    type: "select",
                    options: ["nowrap", "wrap", "wrap-reverse"],
                    default: "wrap",
                },
                {
                    key: "justify_content",
                    label: "Justify Content",
                    type: "select",
                    options: [
                        "flex-start",
                        "center",
                        "flex-end",
                        "space-between",
                        "space-around",
                        "space-evenly",
                    ],
                    default: "flex-start",
                },
                {
                    key: "align_items",
                    label: "Align Items",
                    type: "select",
                    options: ["stretch", "flex-start", "center", "flex-end", "baseline"],
                    default: "stretch",
                },
                {
                    key: "align_content",
                    label: "Align Content",
                    type: "select",
                    options: [
                        "stretch",
                        "flex-start",
                        "center",
                        "flex-end",
                        "space-between",
                        "space-around",
                        "space-evenly",
                    ],
                    default: "stretch",
                },
            ].concat(responsiveStructureFields());
        }
        return [];
    }

    function fontFamilyCatalog() {
        return [
            { value: "", label: "Theme Default" },
            { value: "Roboto", label: "Roboto (Google)" },
            { value: "Open Sans", label: "Open Sans (Google)" },
            { value: "Lato", label: "Lato (Google)" },
            { value: "Montserrat", label: "Montserrat (Google)" },
            { value: "Poppins", label: "Poppins (Google)" },
            { value: "Inter", label: "Inter (Google)" },
            { value: "Nunito", label: "Nunito (Google)" },
            { value: "Oswald", label: "Oswald (Google)" },
            { value: "Merriweather", label: "Merriweather (Google)" },
            { value: "Playfair Display", label: "Playfair Display (Google)" },
            { value: "Raleway", label: "Raleway (Google)" },
            { value: "Rubik", label: "Rubik (Google)" },
            { value: "Source Sans 3", label: "Source Sans 3 (Google)" },
            { value: "Work Sans", label: "Work Sans (Google)" },
            { value: "DM Sans", label: "DM Sans (Google)" },
            { value: "system-ui", label: "System UI" },
        ];
    }

    function sizeUnitOptions(includeUnitless) {
        const units = [
            "px",
            "rem",
            "em",
            "%",
            "vw",
            "vh",
            "vmin",
            "vmax",
            "ch",
            "ex",
            "pt",
            "pc",
        ];
        if (includeUnitless) {
            units.unshift("");
        }
        return units;
    }

    function viewportVisibilityOptions() {
        return [
            { value: "all", label: "Show on all devices" },
            { value: "monitor_only", label: "Only monitors" },
            { value: "tablet_only", label: "Only tablets" },
            { value: "mobile_only", label: "Only mobile" },
            { value: "tv_only", label: "Only TV / very wide" },
            { value: "hide_monitor", label: "Hide on monitors" },
            { value: "hide_tablet", label: "Hide on tablets" },
            { value: "hide_mobile", label: "Hide on mobile" },
            { value: "hide_tv", label: "Hide on TV / very wide" },
        ];
    }

    function labelizeTokenKey(key) {
        return String(key || "")
            .replace(/[_-]+/g, " ")
            .replace(/\s+/g, " ")
            .trim()
            .replace(/\b\w/g, function (match) {
                return match.toUpperCase();
            });
    }

    function globalColorTokenOptions() {
        const colors =
            state.globalDesignTokens &&
            state.globalDesignTokens.colors &&
            typeof state.globalDesignTokens.colors === "object"
                ? state.globalDesignTokens.colors
                : {};
        const options = [{ value: "", label: "Custom color value" }];
        Object.keys(colors).forEach(function (key) {
            options.push({
                value: String(key),
                label: labelizeTokenKey(key) + " (" + String(colors[key]) + ")",
            });
        });
        return options;
    }

    function globalFontTokenOptions() {
        const fonts =
            state.globalDesignTokens &&
            state.globalDesignTokens.fonts &&
            typeof state.globalDesignTokens.fonts === "object"
                ? state.globalDesignTokens.fonts
                : {};
        const options = [{ value: "", label: "Custom font family" }];
        Object.keys(fonts).forEach(function (key) {
            if (key === "base_size") {
                return;
            }
            options.push({
                value: String(key),
                label: labelizeTokenKey(key) + " (" + String(fonts[key]) + ")",
            });
        });
        return options;
    }

    function designDeviceFromViewportGroup(group) {
        const value = String(group || "").toLowerCase();
        if (value === "tablet" || value === "mobile") {
            return value;
        }
        return "desktop";
    }

    function normalizeDesignDevice(device) {
        const value = String(device || "").toLowerCase();
        return value === "tablet" || value === "mobile" ? value : "desktop";
    }

    function normalizeDesignState(interactionState) {
        return String(interactionState || "").toLowerCase() === "hover"
            ? "hover"
            : "normal";
    }

    function designContextSuffix(device, interactionState) {
        const safeDevice = normalizeDesignDevice(device);
        const safeState = normalizeDesignState(interactionState);
        if (safeDevice === "desktop" && safeState === "normal") {
            return "";
        }
        if (safeState === "hover") {
            return safeDevice === "desktop" ? "_hover" : "_" + safeDevice + "_hover";
        }
        return "_" + safeDevice;
    }

    function designContextChain(device, interactionState) {
        const safeDevice = normalizeDesignDevice(device);
        const safeState = normalizeDesignState(interactionState);
        const suffixes = [];
        if (safeDevice === "tablet" || safeDevice === "mobile") {
            suffixes.push("_tablet");
        }
        if (safeDevice === "mobile") {
            suffixes.push("_mobile");
        }
        if (safeState === "hover") {
            suffixes.push("_hover");
            if (safeDevice === "tablet" || safeDevice === "mobile") {
                suffixes.push("_tablet_hover");
            }
            if (safeDevice === "mobile") {
                suffixes.push("_mobile_hover");
            }
        }
        return suffixes;
    }

    function overlayDesignContext(output, source, suffix) {
        if (!suffix) {
            return;
        }
        Object.keys(source || {}).forEach(function (key) {
            if (key.indexOf("design_") !== 0 || !key.endsWith(suffix)) {
                return;
            }
            const baseKey = key.substring(0, key.length - suffix.length);
            if (/(?:_tablet|_mobile|_hover)$/.test(baseKey)) {
                return;
            }
            const value = source[key];
            if (value === null || typeof value === "undefined" || String(value) === "") {
                return;
            }
            output[baseKey] = value;
        });
    }

    function designSettingsForContext(settings, device, interactionState, excludeActive) {
        const source = settings && typeof settings === "object" ? settings : {};
        const output = { ...source };
        const suffixes = designContextChain(device, interactionState);
        if (excludeActive && suffixes.length > 0) {
            suffixes.pop();
        }
        suffixes.forEach(function (suffix) {
            overlayDesignContext(output, source, suffix);
        });
        return output;
    }

    function designFieldForActiveContext(baseField, settings) {
        const field = { ...baseField };
        const suffix = designContextSuffix(
            state.modalDesignDevice,
            state.modalDesignState
        );
        if (field.type === "color") {
            const semanticKey = baseField.key === "design_text_color"
                ? "design_text_color_global"
                : (baseField.key === "design_background_color"
                    ? "design_background_color_global"
                    : "");
            const inheritedContext = designSettingsForContext(
                settings,
                state.modalDesignDevice,
                state.modalDesignState,
                suffix !== ""
            );
            const semanticToken = semanticKey !== ""
                ? String(inheritedContext[semanticKey] || settings[semanticKey] || "")
                : "";
            const semanticColor = globalColorTokenValue(semanticToken);
            if (semanticColor !== "") {
                field.resetValue = "";
                field.resetDisplay = semanticColor;
                field.resetLabel = "Use " + semanticToken.replace(/_/g, " ") + " token";
            }
        }
        if (suffix === "") {
            return field;
        }

        const inherited = designSettingsForContext(
            settings,
            state.modalDesignDevice,
            state.modalDesignState,
            true
        );
        if (field.key) {
            field.key = String(field.key) + suffix;
        }
        if (field.unit_key) {
            const baseUnitKey = String(field.unit_key);
            field.unit_key = baseUnitKey + suffix;
            field.unit_default = String(
                inherited[baseUnitKey] || field.unit_default || "px"
            );
        }
        if (field.keys && typeof field.keys === "object") {
            const nextKeys = {};
            Object.keys(field.keys).forEach(function (direction) {
                nextKeys[direction] = String(field.keys[direction]) + suffix;
            });
            field.keys = nextKeys;
            field.default = { top: "", right: "", bottom: "", left: "" };
        } else if (field.type === "color") {
            const inheritedColor = String(inherited[baseField.key] || "");
            field.default = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(inheritedColor)
                ? inheritedColor
                : "#000000";
        } else {
            field.default = "";
        }
        if (field.type === "select") {
            field.options = [
                { value: "", label: "Inherit from earlier context" },
            ].concat(normalizeSelectOptions(baseField.options || []));
        }
        const inheritedValue = baseField.key
            ? String(inherited[baseField.key] || "")
            : "";
        if (inheritedValue !== "" && field.type !== "select" && field.type !== "color") {
            field.placeholder = "Inherited: " + inheritedValue;
        }
        return field;
    }

    function designFieldSettingKeys(field) {
        const keys = [];
        if (field && field.key) {
            keys.push(String(field.key));
        }
        if (field && field.unit_key) {
            keys.push(String(field.unit_key));
        }
        if (field && field.keys && typeof field.keys === "object") {
            Object.keys(field.keys).forEach(function (direction) {
                keys.push(String(field.keys[direction]));
            });
        }
        return keys.filter(function (key, index) {
            return key !== "" && keys.indexOf(key) === index;
        });
    }

    function decorateDesignContextControl(control, baseField, field, settings, modalBlock) {
        const suffix = designContextSuffix(
            state.modalDesignDevice,
            state.modalDesignState
        );
        if (suffix === "" || !(control instanceof HTMLElement)) {
            return control;
        }

        const keys = designFieldSettingKeys(field);
        const contextHasOverride = function () {
            return keys.some(function (key) {
                return Object.prototype.hasOwnProperty.call(settings, key) &&
                    String(settings[key] === null || typeof settings[key] === "undefined" ? "" : settings[key]) !== "";
            });
        };
        const hasOverride = contextHasOverride();
        control.classList.add(
            hasOverride ? "has-design-override" : "is-design-inherited"
        );

        const meta = document.createElement("div");
        meta.className = "h4bs-design-override-meta";
        const status = document.createElement("span");
        status.textContent = hasOverride ? "Override active" : "Inherited";
        meta.appendChild(status);

        const reset = document.createElement("button");
        reset.type = "button";
        reset.className = "h4bs-design-reset-field";
        reset.title = "Clear this context override";
        reset.setAttribute("aria-label", "Clear " + String(baseField.label || "style") + " override");
        reset.innerHTML = '<span class="dashicons dashicons-image-rotate" aria-hidden="true"></span>';
        reset.disabled = !hasOverride;
        reset.addEventListener("click", function () {
            keys.forEach(function (key) {
                delete settings[key];
            });
            markModalDirty(true);
            renderModalForBlock(modalBlock, "style");
            requestModalPreviewRender();
        });
        meta.appendChild(reset);
        control.appendChild(meta);
        const syncStatus = function () {
            const active = contextHasOverride();
            control.classList.toggle("has-design-override", active);
            control.classList.toggle("is-design-inherited", !active);
            status.textContent = active ? "Override active" : "Inherited";
            reset.disabled = !active;
        };
        control.addEventListener("input", syncStatus);
        control.addEventListener("change", syncStatus);
        return control;
    }

    function renderDesignContextControls(modalBlock) {
        const wrap = document.createElement("section");
        wrap.className = "h4bs-design-context-controls";

        const deviceRow = document.createElement("div");
        deviceRow.className = "h4bs-design-context-row";
        const deviceLabel = document.createElement("span");
        deviceLabel.className = "h4bs-design-context-label";
        deviceLabel.textContent = "Device";
        deviceRow.appendChild(deviceLabel);

        const deviceSwitch = document.createElement("div");
        deviceSwitch.className = "h4bs-design-segmented";
        [
            { key: "desktop", label: "Desktop", icon: "dashicons-desktop" },
            { key: "tablet", label: "Tablet", icon: "dashicons-tablet" },
            { key: "mobile", label: "Mobile", icon: "dashicons-smartphone" },
        ].forEach(function (item) {
            const button = document.createElement("button");
            button.type = "button";
            button.className = "h4bs-design-context-button";
            button.classList.toggle(
                "is-active",
                normalizeDesignDevice(state.modalDesignDevice) === item.key
            );
            button.title = item.label + " design values";
            button.setAttribute("aria-label", item.label + " design values");
            button.innerHTML =
                '<span class="dashicons ' + item.icon + '" aria-hidden="true"></span>' +
                '<span>' + item.label + '</span>';
            button.addEventListener("click", function () {
                state.modalDesignDevice = item.key;
                state.viewportGroup = item.key === "desktop" ? "monitor" : item.key;
                renderViewportIcons();
                renderViewportSelect();
                applyViewport();
                renderModalForBlock(modalBlock, "style");
                requestModalPreviewRender();
            });
            deviceSwitch.appendChild(button);
        });
        deviceRow.appendChild(deviceSwitch);
        wrap.appendChild(deviceRow);

        const stateRow = document.createElement("div");
        stateRow.className = "h4bs-design-context-row";
        const stateLabel = document.createElement("span");
        stateLabel.className = "h4bs-design-context-label";
        stateLabel.textContent = "State";
        stateRow.appendChild(stateLabel);
        const stateSwitch = document.createElement("div");
        stateSwitch.className = "h4bs-design-segmented";
        [
            { key: "normal", label: "Normal" },
            { key: "hover", label: "Hover" },
        ].forEach(function (item) {
            const button = document.createElement("button");
            button.type = "button";
            button.className = "h4bs-design-context-button";
            button.classList.toggle(
                "is-active",
                normalizeDesignState(state.modalDesignState) === item.key
            );
            button.textContent = item.label;
            button.addEventListener("click", function () {
                state.modalDesignState = item.key;
                renderModalForBlock(modalBlock, "style");
                requestModalPreviewRender();
            });
            stateSwitch.appendChild(button);
        });
        stateRow.appendChild(stateSwitch);
        wrap.appendChild(stateRow);

        const hint = document.createElement("p");
        hint.className = "h4bs-design-context-hint";
        hint.textContent =
            "Tablet inherits Desktop. Mobile inherits Tablet. Hover inherits the active device's Normal values.";
        wrap.appendChild(hint);

        const suffix = designContextSuffix(
            state.modalDesignDevice,
            state.modalDesignState
        );
        if (suffix !== "") {
            const clear = document.createElement("button");
            clear.type = "button";
            clear.className = "h4bs-design-clear-context";
            clear.textContent = "Clear this context";
            const contextKeys = Object.keys(modalBlock.settings || {}).filter(function (key) {
                if (key.indexOf("design_") !== 0 || !key.endsWith(suffix)) {
                    return false;
                }
                const baseKey = key.substring(0, key.length - suffix.length);
                return !/(?:_tablet|_mobile|_hover)$/.test(baseKey);
            });
            clear.disabled = contextKeys.length < 1;
            clear.addEventListener("click", function () {
                contextKeys.forEach(function (key) {
                    delete modalBlock.settings[key];
                });
                markModalDirty(true);
                renderModalForBlock(modalBlock, "style");
                requestModalPreviewRender();
            });
            wrap.appendChild(clear);
        }
        return wrap;
    }

    function designFieldsForType(type) {
        const fields = [
            {
                key: "design_style_preset",
                label: "Global Style Preset",
                type: "select",
                options: [
                    { value: "", label: "No preset / custom" },
                    { value: "button_primary", label: "Button: Primary" },
                    { value: "button_secondary", label: "Button: Secondary" },
                    { value: "button_outline", label: "Button: Outline" },
                    { value: "button_ghost", label: "Button: Ghost" },
                    { value: "card", label: "Card: Standard" },
                    { value: "card_elevated", label: "Card: Elevated" },
                    { value: "card_soft", label: "Card: Soft" },
                    { value: "callout", label: "Callout: Accent" },
                ],
                default: "",
            },
            { key: "design_text_color_global", label: "Text Color Token", type: "select", options: globalColorTokenOptions(), default: "" },
            { key: "design_text_color", label: "Text Color", type: "color", default: "#1f2937" },
            { key: "design_background_color_global", label: "Background Color Token", type: "select", options: globalColorTokenOptions(), default: "" },
            { key: "design_background_color", label: "Background Color", type: "color", default: "#ffffff" },
            { key: "design_background_image", label: "Background Image", type: "media", mediaType: "image", imageProfile: "background", default: "" },
            { key: "design_background_gradient", label: "Background Gradient (CSS)", type: "text", default: "" },
            { key: "design_background_size", label: "Background Size", type: "select", options: ["cover", "contain", "auto"], default: "cover" },
            { key: "design_background_position", label: "Background Position", type: "text", default: "center center" },
            { key: "design_background_repeat", label: "Background Repeat", type: "select", options: ["no-repeat", "repeat", "repeat-x", "repeat-y"], default: "no-repeat" },
            { key: "design_overlay_color", label: "Overlay Color", type: "color", default: "#000000" },
            { key: "design_overlay_opacity", label: "Overlay Opacity (0 to 1)", type: "text", default: "0" },
            {
                type: "box4",
                label: "Padding",
                unit_key: "design_padding_unit",
                unit_default: "px",
                units: sizeUnitOptions(false),
                keys: {
                    top: "design_padding_top",
                    right: "design_padding_right",
                    bottom: "design_padding_bottom",
                    left: "design_padding_left",
                },
                default: { top: "0", right: "0", bottom: "0", left: "0" },
            },
            {
                type: "box4",
                label: "Margin",
                unit_key: "design_margin_unit",
                unit_default: "px",
                units: sizeUnitOptions(false),
                keys: {
                    top: "design_margin_top",
                    right: "design_margin_right",
                    bottom: "design_margin_bottom",
                    left: "design_margin_left",
                },
                default: { top: "0", right: "0", bottom: "0", left: "0" },
            },
            {
                key: "design_border_width",
                label: "Border Width",
                type: "size",
                unit_key: "design_border_width_unit",
                unit_default: "px",
                units: sizeUnitOptions(false),
                default: "0",
            },
            { key: "design_border_style", label: "Border Style", type: "select", options: ["solid", "dashed", "dotted", "none"], default: "solid" },
            { key: "design_border_color", label: "Border Color", type: "color", default: "#dbe7f3" },
            {
                key: "design_border_radius",
                label: "Border Radius",
                type: "size",
                unit_key: "design_border_radius_unit",
                unit_default: "px",
                units: sizeUnitOptions(false),
                default: "0",
            },
            { key: "design_box_shadow", label: "Box Shadow", type: "text", default: "" },
            { key: "design_text_shadow", label: "Text Shadow", type: "text", default: "" },
            { key: "design_opacity", label: "Opacity (0 to 1)", type: "text", default: "" },
            { key: "design_filter", label: "Filter", type: "text", default: "" },
            { key: "design_backdrop_filter", label: "Backdrop Filter", type: "text", default: "" },
            { key: "design_transform", label: "Transform", type: "text", default: "" },
            { key: "design_transform_origin", label: "Transform Origin", type: "text", default: "" },
            { key: "design_transition", label: "Transition", type: "text", default: "" },
            { key: "design_motion_entrance", label: "Entrance Motion", type: "select", options: [{ value: "", label: "None" }, { value: "fade_up", label: "Fade Up" }, { value: "fade_down", label: "Fade Down" }, { value: "fade_left", label: "Fade Left" }, { value: "fade_right", label: "Fade Right" }, { value: "zoom_in", label: "Zoom In" }], default: "" },
            { key: "design_motion_trigger", label: "Motion Trigger", type: "select", options: [{ value: "page_load", label: "Page load" }, { value: "in_view", label: "When in view" }, { value: "interaction", label: "First interaction" }], default: "page_load" },
            { key: "design_motion_hover", label: "Hover Motion", type: "select", options: [{ value: "", label: "None" }, { value: "lift", label: "Lift" }, { value: "grow", label: "Grow" }, { value: "tilt", label: "Tilt" }, { value: "glow", label: "Glow" }], default: "" },
            { key: "design_motion_background", label: "Background Motion", type: "select", options: [{ value: "", label: "None" }, { value: "drift_x", label: "Horizontal Drift" }, { value: "drift_y", label: "Vertical Drift" }, { value: "pulse", label: "Soft Pulse" }], default: "" },
            { key: "design_motion_duration", label: "Motion Duration (ms)", type: "number", default: "600" },
            { key: "design_motion_delay", label: "Motion Delay (ms)", type: "number", default: "0" },
            { key: "design_motion_easing", label: "Motion Easing", type: "select", options: ["ease", "linear", "ease-in", "ease-out", "ease-in-out"], default: "ease-out" },
            { key: "design_motion_iteration", label: "Motion Iterations", type: "select", options: [{ value: "1", label: "Once" }, { value: "2", label: "Twice" }, { value: "3", label: "Three times" }, { value: "infinite", label: "Continuous" }], default: "1" },
            { key: "design_motion_reduced", label: "Reduced Motion", type: "select", options: [{ value: "respect", label: "Respect device preference" }, { value: "disable", label: "Always disable motion" }, { value: "allow", label: "Always allow motion" }], default: "respect" },
            { key: "design_cursor", label: "Cursor", type: "select", options: ["", "auto", "pointer", "default", "text", "move", "grab", "not-allowed"], default: "" },
            { key: "design_text_align", label: "Text Align", type: "select", options: ["", "left", "center", "right", "justify"], default: "" },
            { key: "design_font_family_global", label: "Font Token", type: "select", options: globalFontTokenOptions(), default: "" },
            { key: "design_font_family", label: "Font Family", type: "select", options: fontFamilyCatalog(), default: "" },
            {
                key: "design_font_size",
                label: "Font Size",
                type: "size",
                unit_key: "design_font_size_unit",
                unit_default: "px",
                units: sizeUnitOptions(false),
                default: "",
            },
            { key: "design_font_weight", label: "Font Weight", type: "text", default: "" },
            {
                key: "design_line_height",
                label: "Line Height",
                type: "size",
                unit_key: "design_line_height_unit",
                unit_default: "",
                units: sizeUnitOptions(true),
                default: "",
            },
            {
                key: "design_letter_spacing",
                label: "Letter Spacing",
                type: "size",
                unit_key: "design_letter_spacing_unit",
                unit_default: "px",
                units: sizeUnitOptions(false),
                default: "0",
            },
            {
                key: "design_width",
                label: "Width",
                type: "size",
                unit_key: "design_width_unit",
                unit_default: "%",
                units: sizeUnitOptions(false),
                default: "",
            },
            {
                key: "design_max_width",
                label: "Max Width",
                type: "size",
                unit_key: "design_max_width_unit",
                unit_default: "px",
                units: sizeUnitOptions(false),
                default: "",
            },
            {
                key: "design_min_height",
                label: "Min Height",
                type: "size",
                unit_key: "design_min_height_unit",
                unit_default: "px",
                units: sizeUnitOptions(false),
                default: "",
            },
            {
                key: "design_height",
                label: "Height",
                type: "size",
                unit_key: "design_height_unit",
                unit_default: "px",
                units: sizeUnitOptions(false),
                default: "",
            },
            {
                key: "design_max_height",
                label: "Max Height",
                type: "size",
                unit_key: "design_max_height_unit",
                unit_default: "px",
                units: sizeUnitOptions(false),
                default: "",
            },
            { key: "design_display", label: "Display", type: "select", options: ["", "block", "inline-block", "flex", "grid", "inline-flex"], default: "" },
            { key: "design_position", label: "Position", type: "select", options: ["", "static", "relative", "absolute", "sticky", "fixed"], default: "" },
            { key: "design_z_index", label: "Z-Index", type: "text", default: "" },
            { key: "design_overflow", label: "Overflow", type: "select", options: ["", "visible", "hidden", "auto", "scroll"], default: "" },
            { key: "design_text_transform", label: "Text Transform", type: "select", options: ["", "none", "uppercase", "lowercase", "capitalize"], default: "" },
            {
                key: "design_top",
                label: "Top Offset",
                type: "size",
                unit_key: "design_top_unit",
                unit_default: "px",
                units: sizeUnitOptions(false),
                default: "",
            },
            {
                key: "design_right",
                label: "Right Offset",
                type: "size",
                unit_key: "design_right_unit",
                unit_default: "px",
                units: sizeUnitOptions(false),
                default: "",
            },
            {
                key: "design_bottom",
                label: "Bottom Offset",
                type: "size",
                unit_key: "design_bottom_unit",
                unit_default: "px",
                units: sizeUnitOptions(false),
                default: "",
            },
            {
                key: "design_left",
                label: "Left Offset",
                type: "size",
                unit_key: "design_left_unit",
                unit_default: "px",
                units: sizeUnitOptions(false),
                default: "",
            },
            { key: "design_flex_direction", label: "Flex Direction", type: "select", options: ["", "row", "column", "row-reverse", "column-reverse"], default: "" },
            { key: "design_justify_content", label: "Justify Content", type: "select", options: ["", "flex-start", "center", "flex-end", "space-between", "space-around", "space-evenly"], default: "" },
            { key: "design_align_items", label: "Align Items", type: "select", options: ["", "stretch", "flex-start", "center", "flex-end", "baseline"], default: "" },
            { key: "design_align_self", label: "Align Self", type: "select", options: ["", "auto", "stretch", "flex-start", "center", "flex-end", "baseline"], default: "" },
        ];

        const contextualFields = fields.map(function (field) {
            const next = { ...field };
            if (type === "button" && field.type === "box4" && field.label === "Padding") {
                next.label = "Button Padding";
            }
            if (type === "button" && field.key === "design_font_size") {
                next.label = "Button Text Size";
            }
            if (type === "heading" && field.key === "design_font_size") {
                next.label = "Heading Size";
            }
            if (type === "cta" && field.key === "design_font_size") {
                next.label = "Title Size";
            }
            return next;
        });

        if (type === "spacer" || type === "divider") {
            return contextualFields.filter(function (field) {
                return ![
                    "design_text_color_global",
                    "design_text_color",
                    "design_font_family_global",
                    "design_font_family",
                    "design_font_size",
                    "design_font_weight",
                    "design_line_height",
                    "design_letter_spacing",
                    "design_text_shadow",
                    "design_text_align",
                ].includes(field.key);
            });
        }
        return contextualFields;
    }

    function fieldSelect(label, name, current, options, onChange) {
        const wrapper = document.createElement("div");
        wrapper.className = "h4bs-field";
        const lbl = document.createElement("label");
        lbl.textContent = label;
        wrapper.appendChild(lbl);
        const select = document.createElement("select");
        select.name = name;
        normalizeSelectOptions(options).forEach(function (option) {
            const opt = document.createElement("option");
            opt.value = option.value;
            opt.textContent = option.label;
            if (option.value === current) {
                opt.selected = true;
            }
            select.appendChild(opt);
        });
        select.addEventListener("change", function () {
            onChange(String(select.value || ""));
        });
        wrapper.appendChild(select);
        return wrapper;
    }

    function normalizeSelectOptions(rawOptions) {
        if (Array.isArray(rawOptions)) {
            return rawOptions.map(function (option) {
                if (option && typeof option === "object") {
                    return {
                        value: String(option.value || ""),
                        label: String(option.label || option.value || ""),
                    };
                }
                return { value: String(option), label: String(option) };
            });
        }

        if (rawOptions && typeof rawOptions === "object") {
            return Object.keys(rawOptions).map(function (key) {
                return { value: String(key), label: String(rawOptions[key]) };
            });
        }

        return [];
    }

    function normalizeDecimalValue(rawValue, maxDecimals) {
        const source = String(rawValue === null || typeof rawValue === "undefined" ? "" : rawValue).trim();
        if (source === "") {
            return "";
        }
        const parsed = Number(source);
        if (!Number.isFinite(parsed)) {
            return "";
        }
        const decimals = Math.max(0, Math.min(6, Number(maxDecimals || 0)));
        const factor = Math.pow(10, decimals);
        const rounded = Math.round(parsed * factor) / factor;
        if (decimals === 0) {
            return String(Math.round(rounded));
        }
        const fixed = rounded.toFixed(decimals);
        return fixed.replace(/\.?0+$/, "");
    }

    function collectionPresetCatalog() {
        return {
            programs: { label: "Programs by day", fields: [["title", "Program"], ["description", "Description"], ["day", "Day"], ["type", "Program type"], ["badge", "Badge"], ["url", "Details link"]], filters: [["day", "Day"], ["type", "Type"]] },
            events: { label: "Events calendar", fields: [["title", "Event"], ["description", "Description"], ["date", "Date"], ["category", "Category"], ["badge", "Badge"], ["url", "Event link"]], filters: [["date", "Date"], ["category", "Category"]] },
            directory: { label: "Staff or service directory", fields: [["title", "Name"], ["description", "Summary"], ["group", "Group"], ["category", "Category"], ["badge", "Badge"], ["url", "Profile link"]], filters: [["group", "Group"], ["category", "Category"]] },
        };
    }

    function createCollectionPresetField(modalBlock) {
        const wrapper = document.createElement("div");
        wrapper.className = "h4bs-field h4bs-collection-presets";
        const label = document.createElement("strong");
        label.textContent = "Start from a reusable setup";
        wrapper.appendChild(label);
        const hint = document.createElement("p");
        hint.className = "description";
        hint.textContent = "Presets update field and filter controls. Existing items stay in place and unknown data is preserved.";
        wrapper.appendChild(hint);
        const actions = document.createElement("div");
        actions.className = "h4bs-collection-preset-actions";
        Object.entries(collectionPresetCatalog()).forEach(function (entry) {
            const button = document.createElement("button");
            button.type = "button";
            button.className = "button";
            button.textContent = entry[1].label;
            button.addEventListener("click", function () {
                modalBlock.settings.fields = entry[1].fields.map(function (field) { return { key: field[0], label: field[1] }; });
                modalBlock.settings.filters = entry[1].filters.map(function (filter) { return { key: filter[0], label: filter[1] }; });
                markModalDirty(true);
                renderModalForBlock(modalBlock, "content");
            });
            actions.appendChild(button);
        });
        wrapper.appendChild(actions);
        return wrapper;
    }

    function validateModalBlock(block) {
        if (!block || String(block.type || "") !== "collection") return [];
        const settings = block.settings && typeof block.settings === "object" ? block.settings : {};
        const fields = Array.isArray(settings.fields) ? settings.fields : [];
        const filters = Array.isArray(settings.filters) ? settings.filters : [];
        const errors = [];
        const keys = [];
        fields.forEach(function (field, index) {
            const key = String(field && field.key ? field.key : "").trim().toLowerCase();
            const label = String(field && field.label ? field.label : "").trim();
            if (!/^[a-z][a-z0-9_-]*$/.test(key)) errors.push("Field " + (index + 1) + " needs a key beginning with a letter and containing only letters, numbers, underscores, or hyphens.");
            if (!label) errors.push("Field " + (index + 1) + " needs a visible label.");
            if (key && keys.indexOf(key) >= 0) errors.push("Field key ‘" + key + "’ is duplicated.");
            if (key) keys.push(key);
        });
        if (keys.indexOf("title") < 0) errors.push("A Collection needs a title field so every item has an accessible heading.");
        filters.forEach(function (filter, index) {
            const key = String(filter && filter.key ? filter.key : "").trim().toLowerCase();
            if (key && keys.indexOf(key) < 0) errors.push("Filter " + (index + 1) + " uses ‘" + key + "’, but that item field is not defined.");
        });
        return Array.from(new Set(errors));
    }

    function showModalValidationErrors(errors) {
        if (!els.modalBody) return;
        const previous = els.modalBody.querySelector("[data-h4bs-validation-summary]");
        if (previous) previous.remove();
        const summary = document.createElement("div");
        summary.className = "notice notice-error h4bs-modal-validation";
        summary.setAttribute("data-h4bs-validation-summary", "1");
        summary.setAttribute("role", "alert");
        summary.tabIndex = -1;
        const heading = document.createElement("strong");
        heading.textContent = "Fix these settings before saving:";
        summary.appendChild(heading);
        const list = document.createElement("ul");
        errors.forEach(function (error) { const item = document.createElement("li"); item.textContent = error; list.appendChild(item); });
        summary.appendChild(list);
        els.modalBody.insertBefore(summary, els.modalBody.firstChild);
        summary.focus();
    }

    function createCollectionEditorField(wrapper, field, value, onChange, filtersOnly) {
        let rows = Array.isArray(value) ? value.map(function (item) { return item && typeof item === "object" ? { ...item } : {}; }) : [];
        const list = document.createElement("div");
        list.className = "h4bs-collection-editor";
        const emit = function () { markModalInputActive(); onChange(rows.map(function (item) { return { ...item }; })); };
        const render = function () {
            list.innerHTML = "";
            rows.forEach(function (item, index) {
                const row = document.createElement("fieldset");
                row.className = "h4bs-collection-editor-row";
                const legend = document.createElement("legend");
                legend.textContent = filtersOnly ? "Filter " + (index + 1) : "Item " + (index + 1);
                row.appendChild(legend);
                const configuredFields = Array.isArray(field.collectionFields) ? field.collectionFields : [];
                const keys = filtersOnly ? ["key", "label"] : (configuredFields.length ? configuredFields.map(function (definition) { return String(definition && definition.key ? definition.key : ""); }).filter(Boolean) : ["title", "description", "group", "type", "badge", "url"]);
                keys.forEach(function (key) {
                    const label = document.createElement("label");
                    const definition = configuredFields.find(function (candidate) { return String(candidate && candidate.key ? candidate.key : "") === key; });
                    label.textContent = definition && definition.label ? String(definition.label) : key.charAt(0).toUpperCase() + key.slice(1);
                    const input = key === "description" ? document.createElement("textarea") : document.createElement("input");
                    if (input instanceof HTMLInputElement) input.type = key === "url" ? "url" : "text";
                    input.value = String(item[key] || "");
                    input.addEventListener("input", function () { rows[index][key] = String(input.value || ""); emit(); });
                    label.appendChild(input);
                    row.appendChild(label);
                });
                const actions = document.createElement("div");
                actions.className = "h4bs-collection-editor-actions";
                [["Move up", -1], ["Move down", 1]].forEach(function (action) {
                    const button = document.createElement("button");
                    button.type = "button"; button.className = "button"; button.textContent = action[0];
                    button.disabled = index + action[1] < 0 || index + action[1] >= rows.length;
                    button.addEventListener("click", function () { const target = index + action[1]; const moved = rows.splice(index, 1)[0]; rows.splice(target, 0, moved); emit(); render(); });
                    actions.appendChild(button);
                });
                const remove = document.createElement("button");
                remove.type = "button"; remove.className = "button button-link-delete"; remove.textContent = "Remove";
                remove.addEventListener("click", function () { rows.splice(index, 1); emit(); render(); });
                actions.appendChild(remove); row.appendChild(actions); list.appendChild(row);
            });
        };
        wrapper.appendChild(list);
        const add = document.createElement("button");
        add.type = "button"; add.className = "button button-secondary"; add.textContent = filtersOnly ? "Add Filter" : "Add Item";
        add.addEventListener("click", function () { rows.push(filtersOnly ? { key: "", label: "" } : { id: "item-" + Date.now(), title: "New item", description: "", group: "", type: "", badge: "", url: "" }); emit(); render(); });
        wrapper.appendChild(add); render(); return wrapper;
    }

    function createField(field, value, onChange) {
        const wrapper = document.createElement("div");
        wrapper.className = "h4bs-field";
        if (field && field.key) {
            wrapper.setAttribute("data-h4bs-field-key", String(field.key));
        }
        const guidanceProfile = String(
            field.imageProfile ||
            ((field.type === "media" || field.type === "media_multiple") && field.mediaType === "image"
                ? (field.type === "media_multiple" ? "gallery" : "content")
                : "")
        ).trim();
        if (guidanceProfile) {
            wrapper.setAttribute("data-h4bs-image-profile", guidanceProfile);
        }

        const label = document.createElement("label");
        label.textContent = String(field.label || "");
        wrapper.appendChild(label);

        let input = null;
        const type = String(field.type || "text");
        if (type === "collection_items" || type === "collection_filters") {
            return createCollectionEditorField(wrapper, field, value, onChange, type === "collection_filters");
        }
        if (type === "media" || type === "media_multiple") {
            const allowManualInput = field.allowManualInput === true;
            const row = document.createElement("div");
            row.className = "h4bs-media-row";
            const preview = document.createElement("div");
            preview.className = "h4bs-media-preview";

            input = document.createElement("input");
            input.type = "text";
            input.value = String(value || "");
            input.readOnly = !allowManualInput;
            input.placeholder =
                type === "media_multiple"
                    ? "Choose media from library"
                    : "Choose media from library";
            if (allowManualInput) {
                input.addEventListener("input", function () {
                    markModalInputActive();
                    onChange(String(input.value || ""), { attachmentId: 0 });
                    refreshMediaPreview();
                });
            }
            row.appendChild(input);

            const choose = document.createElement("button");
            choose.type = "button";
            choose.className = "button";
            choose.textContent =
                type === "media_multiple"
                    ? "Choose Media"
                    : "Choose from Media Library";
            choose.addEventListener("click", function () {
                if (
                    !window.wp ||
                    !window.wp.media ||
                    typeof window.wp.media !== "function"
                ) {
                    window.alert(
                        "WordPress media library is not available on this screen."
                    );
                    return;
                }
                const frame = window.wp.media({
                    title:
                        type === "media_multiple"
                            ? "Select media"
                            : "Select media",
                    multiple: type === "media_multiple",
                    library: { type: String(field.mediaType || "") || undefined },
                    button: {
                        text:
                            type === "media_multiple"
                                ? "Use selected media"
                                : "Use this media",
                    },
                });
                frame.on("select", function () {
                    const selection = frame.state().get("selection");
                    if (!selection) {
                        return;
                    }
                    const jsonItems = selection.toJSON();
                    if (!Array.isArray(jsonItems) || jsonItems.length < 1) {
                        return;
                    }
                    if (type === "media_multiple") {
                        const urls = jsonItems
                            .map(function (item) {
                                return String(item && item.url ? item.url : "").trim();
                            })
                            .filter(function (url) {
                                return url !== "";
                            });
                        const joined = urls.join(", ");
                        input.value = joined;
                        onChange(joined, { attachmentId: 0 });
                        refreshMediaPreview();
                        return;
                    }
                    const selected = jsonItems[0] || {};
                    const nextUrl = String(selected.url || "");
                    input.value = nextUrl;
                    onChange(nextUrl, {
                        attachmentId: Number(selected.id || 0) || 0,
                        attachment: selected,
                    });
                    refreshMediaPreview();
                });
                frame.open();
            });
            row.appendChild(choose);

            const clear = document.createElement("button");
            clear.type = "button";
            clear.className = "button button-link-delete";
            clear.textContent = "Remove";
            clear.addEventListener("click", function () {
                markModalInputActive();
                input.value = "";
                onChange("", { attachmentId: 0 });
                refreshMediaPreview();
            });
            row.appendChild(clear);

            const refreshMediaPreview = function () {
                const rawValue = String(input.value || "").trim();
                preview.innerHTML = "";

                if (rawValue === "") {
                    choose.textContent =
                        type === "media_multiple"
                            ? "Choose Media"
                            : "Choose from Media Library";
                    return;
                }

                choose.textContent =
                    type === "media_multiple" ? "Replace Media" : "Replace Image";

                if (type === "media_multiple") {
                    const urls = rawValue
                        .split(",")
                        .map(function (part) {
                            return String(part || "").trim();
                        })
                        .filter(function (part) {
                            return part !== "";
                        });
                    if (!urls.length) {
                        return;
                    }
                    const strip = document.createElement("div");
                    strip.className = "h4bs-media-strip";
                    urls.slice(0, 5).forEach(function (url) {
                        const img = document.createElement("img");
                        img.loading = "lazy";
                        img.src = url;
                        img.alt = "";
                        strip.appendChild(img);
                    });
                    preview.appendChild(strip);
                    const meta = document.createElement("small");
                    meta.textContent =
                        urls.length + (urls.length === 1 ? " image selected" : " images selected");
                    preview.appendChild(meta);
                    return;
                }

                const img = document.createElement("img");
                img.loading = "lazy";
                img.src = rawValue;
                img.alt = "";
                img.className = "h4bs-media-preview-image";
                preview.appendChild(img);
            };

            wrapper.appendChild(row);
            wrapper.appendChild(preview);
            refreshMediaPreview();
            return wrapper;
        }
        if (type === "textarea") {
            input = document.createElement("textarea");
            input.rows = Number(field.rows || 4);
            input.value = value;
            input.addEventListener("input", function () {
                markModalInputActive();
                onChange(String(input.value || ""), null);
            });
        } else if (type === "select") {
            input = document.createElement("select");
            normalizeSelectOptions(field.options || []).forEach(function (option) {
                const opt = document.createElement("option");
                opt.value = option.value;
                opt.textContent = option.label;
                if (String(option.value) === value) {
                    opt.selected = true;
                }
                input.appendChild(opt);
            });
            input.addEventListener("change", function () {
                markModalInputActive();
                onChange(String(input.value || ""), null);
            });
        } else if (type === "color") {
            const fallbackColor = /^#([0-9a-f]{6})$/i.test(String(field.default || ""))
                ? String(field.default)
                : "#000000";
            const resetDisplay = /^#([0-9a-f]{6})$/i.test(String(field.resetDisplay || ""))
                ? String(field.resetDisplay)
                : fallbackColor;
            const initialColor = /^#([0-9a-f]{6})$/i.test(String(value || ""))
                ? String(value)
                : resetDisplay;
            const row = document.createElement("div");
            row.className = "h4bs-color-control";
            const swatch = document.createElement("input");
            swatch.type = "color";
            swatch.className = "h4bs-color-swatch";
            swatch.value = initialColor;
            swatch.setAttribute("aria-label", String(field.label || "Color") + " swatch");
            const hex = document.createElement("input");
            hex.type = "text";
            hex.className = "h4bs-color-hex";
            hex.value = initialColor.toUpperCase();
            hex.maxLength = 7;
            hex.spellcheck = false;
            hex.setAttribute("aria-label", String(field.label || "Color") + " hex value");
            const reset = document.createElement("button");
            reset.type = "button";
            reset.className = "button h4bs-color-reset";
            reset.textContent = "Reset";
            reset.title = String(field.resetLabel || "Reset color");

            const emitColor = function (nextColor) {
                const normalized = String(nextColor || "").trim().toUpperCase();
                if (!/^#[0-9A-F]{6}$/.test(normalized)) {
                    hex.setAttribute("aria-invalid", "true");
                    return false;
                }
                hex.removeAttribute("aria-invalid");
                hex.value = normalized;
                swatch.value = normalized.toLowerCase();
                markModalInputActive();
                onChange(normalized.toLowerCase(), null);
                return true;
            };
            swatch.addEventListener("input", function () {
                emitColor(swatch.value);
            });
            hex.addEventListener("input", function () {
                const raw = String(hex.value || "").trim();
                if (/^#?[0-9a-f]{6}$/i.test(raw)) {
                    emitColor(raw.charAt(0) === "#" ? raw : "#" + raw);
                } else {
                    hex.setAttribute("aria-invalid", "true");
                }
            });
            hex.addEventListener("blur", function () {
                if (!emitColor(hex.value)) {
                    hex.value = swatch.value.toUpperCase();
                    hex.removeAttribute("aria-invalid");
                }
            });
            hex.addEventListener("keydown", function (event) {
                if (String(event.key || "") === "Enter") {
                    event.preventDefault();
                    emitColor(hex.value);
                }
            });
            reset.addEventListener("click", function () {
                const nextDisplay = resetDisplay.toUpperCase();
                hex.value = nextDisplay;
                hex.removeAttribute("aria-invalid");
                swatch.value = nextDisplay.toLowerCase();
                markModalInputActive();
                if (Object.prototype.hasOwnProperty.call(field, "resetValue")) {
                    onChange(String(field.resetValue || ""), null);
                } else {
                    onChange(nextDisplay.toLowerCase(), null);
                }
            });
            row.appendChild(swatch);
            row.appendChild(hex);
            row.appendChild(reset);
            wrapper.appendChild(row);
            return wrapper;
        } else {
            input = document.createElement("input");
            if (type === "number") {
                input.type = "number";
                input.value = value;
                input.step = "1";
            } else {
                input.type = "text";
                input.value = value;
            }
            if (field.placeholder) {
                input.placeholder = String(field.placeholder);
            }
            input.addEventListener("input", function () {
                markModalInputActive();
                onChange(String(input.value || ""), null);
            });
            if (type === "number") {
                const normalizeAndEmit = function () {
                    markModalInputActive();
                    const normalized = normalizeDecimalValue(
                        String(input.value || ""),
                        2
                    );
                    if (String(input.value || "") !== normalized) {
                        input.value = normalized;
                    }
                    onChange(String(input.value || ""), null);
                };
                input.addEventListener("change", normalizeAndEmit);
                input.addEventListener("blur", normalizeAndEmit);
            }
        }

        wrapper.appendChild(input);
        return wrapper;
    }

    function createSizeField(field, value, unit, onChange) {
        const wrapper = document.createElement("div");
        wrapper.className = "h4bs-field";
        if (field && field.key) {
            wrapper.setAttribute("data-h4bs-field-key", String(field.key));
        }

        const label = document.createElement("label");
        label.textContent = String(field.label || "");
        wrapper.appendChild(label);

        const row = document.createElement("div");
        row.className = "h4bs-size-row";

        const input = document.createElement("input");
        input.type = "number";
        input.step = "1";
        input.inputMode = "decimal";
        input.value = String(value || "");
        if (field && field.key) {
            input.setAttribute("data-h4bs-setting-key", String(field.key));
        }
        row.appendChild(input);

        const select = document.createElement("select");
        if (field && field.unit_key) {
            select.setAttribute("data-h4bs-setting-key", String(field.unit_key));
        }
        const options = Array.isArray(field.units) && field.units.length
            ? field.units
            : ["px", "rem", "em", "%", "vw", "vh"];
        options.forEach(function (unitOption) {
            const option = document.createElement("option");
            option.value = String(unitOption);
            option.textContent = String(unitOption || "unitless");
            const currentUnitRaw =
                unit === null || typeof unit === "undefined"
                    ? field.unit_default
                    : unit;
            const currentUnit =
                currentUnitRaw === null || typeof currentUnitRaw === "undefined"
                    ? field.unit_default || "px"
                    : currentUnitRaw;
            if (String(unitOption) === String(currentUnit)) {
                option.selected = true;
            }
            select.appendChild(option);
        });
        row.appendChild(select);

        const emit = function (normalize) {
            markModalInputActive();
            let nextValue = String(input.value || "");
            if (normalize) {
                nextValue = normalizeDecimalValue(nextValue, 2);
                if (String(input.value || "") !== nextValue) {
                    input.value = nextValue;
                }
            }
            onChange(nextValue, String(select.value || "px"));
        };
        input.addEventListener("input", function () {
            emit(false);
        });
        input.addEventListener("change", function () {
            emit(true);
        });
        input.addEventListener("blur", function () {
            emit(true);
        });
        select.addEventListener("change", function () {
            emit(false);
        });

        wrapper.appendChild(row);
        return wrapper;
    }

    function createBoxField(field, settings, onChange) {
        const wrapper = document.createElement("div");
        wrapper.className = "h4bs-field";

        const label = document.createElement("label");
        label.textContent = String(field.label || "");
        wrapper.appendChild(label);

        const grid = document.createElement("div");
        grid.className = "h4bs-box4-grid";

        const keys = field.keys || {
            top: "top",
            right: "right",
            bottom: "bottom",
            left: "left",
        };
        ["top", "right", "bottom", "left"].forEach(function (dir) {
            const input = document.createElement("input");
            input.type = "number";
            input.step = "1";
            input.inputMode = "decimal";
            input.placeholder = dir.substring(0, 1).toUpperCase();
            const key = String(keys[dir] || dir);
            input.setAttribute("data-h4bs-setting-key", key);
            const fallback =
                field.default && typeof field.default === "object"
                    ? String(field.default[dir] || "0")
                    : "0";
            const raw = settings && Object.prototype.hasOwnProperty.call(settings, key)
                ? settings[key]
                : fallback;
            input.value =
                raw === null || typeof raw === "undefined" ? "" : String(raw);
            const emit = function (normalize) {
                markModalInputActive();
                let nextValue = String(input.value || "");
                if (normalize) {
                    nextValue = normalizeDecimalValue(nextValue, 2);
                    if (String(input.value || "") !== nextValue) {
                        input.value = nextValue;
                    }
                }
                onChange(key, nextValue);
            };
            input.addEventListener("input", function () {
                emit(false);
            });
            input.addEventListener("change", function () {
                emit(true);
            });
            input.addEventListener("blur", function () {
                emit(true);
            });
            grid.appendChild(input);
        });

        const unitSelect = document.createElement("select");
        unitSelect.className = "h4bs-box4-unit";
        const options = Array.isArray(field.units) && field.units.length
            ? field.units
            : ["px", "rem", "em", "%", "vw", "vh"];
        const unitKey = String(field.unit_key || "");
        const currentUnitRaw =
            unitKey !== "" &&
            settings &&
            Object.prototype.hasOwnProperty.call(settings, unitKey)
                ? settings[unitKey]
                : field.unit_default;
        const currentUnit =
            currentUnitRaw === null || typeof currentUnitRaw === "undefined"
                ? field.unit_default || "px"
                : String(currentUnitRaw);
        if (unitKey !== "") {
            unitSelect.setAttribute("data-h4bs-setting-key", unitKey);
        }
        options.forEach(function (unitOption) {
            const option = document.createElement("option");
            option.value = String(unitOption);
            option.textContent = String(unitOption || "unitless");
            if (String(unitOption) === currentUnit) {
                option.selected = true;
            }
            unitSelect.appendChild(option);
        });
        unitSelect.addEventListener("change", function () {
            if (unitKey !== "") {
                markModalInputActive();
                onChange(unitKey, String(unitSelect.value || "px"));
            }
        });

        const row = document.createElement("div");
        row.className = "h4bs-box4-row";
        row.appendChild(grid);
        row.appendChild(unitSelect);

        wrapper.appendChild(row);
        const tip = document.createElement("small");
        tip.className = "h4bs-box4-tip";
        tip.textContent =
            "Tip: click the element in canvas and drag orange/blue spacing handles.";
        wrapper.appendChild(tip);
        return wrapper;
    }

    function applyBlockSettingChange(block, key, value) {
        if (!block || typeof block !== "object") {
            return;
        }
        captureHistoryBeforeMutation();
        block.settings[key] = value;
        setDirty(true);
        refreshBlockLabels();
        renderPreview();
        updateEstimate();
        syncModalTitle(block);
    }

    function applyDraftBlockSettingChange(block, key, value) {
        if (!block || typeof block !== "object") {
            return;
        }
        if (!block.settings || typeof block.settings !== "object") {
            block.settings = {};
        }
        block.settings[key] = value;
        markModalDirty(true);
        syncInspectorPreviewStatus("updating");
        if (state.parityMode) {
            const visibleParity = els.previewShell
                ? els.previewShell.querySelector("[data-h4bs-parity-frame]")
                : null;
            if (visibleParity instanceof HTMLIFrameElement) {
                visibleParity.hidden = true;
            }
        }
        requestModalPreviewRender();
        syncModalTitle(block);
    }

    function syncInspectorPreviewStatus(status, failureCount) {
        if (!(els.inspectorStatus instanceof HTMLElement)) {
            return;
        }
        const mode = ["ready", "updating", "fallback", "incomplete"].includes(
            String(status || "")
        )
            ? String(status)
            : "ready";
        els.inspectorStatus.classList.remove(
            "is-ready",
            "is-updating",
            "is-fallback",
            "is-incomplete"
        );
        els.inspectorStatus.classList.add("is-" + mode);
        els.inspectorStatus.textContent =
            mode === "updating"
                ? "Updating preview..."
                : mode === "incomplete"
                ? "Preview incomplete: " + Math.max(1, Number(failureCount || 1)) + " page asset(s) failed to load. Reload before judging layout."
                : mode === "fallback"
                ? "Local preview active"
                : "Live preview ready";
    }

    function requestModalPreviewRender() {
        renderPreviewFallbackClient();
        state.previewRenderRevision = Number(state.previewRenderRevision || 0) + 1;
        const renderRevision = state.previewRenderRevision;
        applyImmediateDraftPreview();
        if (state.modalPreviewTimer) {
            window.clearTimeout(state.modalPreviewTimer);
        }
        state.modalPreviewTimer = window.setTimeout(function () {
            state.modalPreviewTimer = null;
            scheduleServerPreviewRender(renderRevision, 0);
        }, PREVIEW_RECONCILE_DELAY_MS);
    }

    function markModalInputActive() {
        state.modalInputActiveUntil = Date.now() + 160;
    }

    function shouldDelayModalPreviewRender() {
        if (!els.modalBody || state.modalMode !== "block") {
            return false;
        }
        return Date.now() < Number(state.modalInputActiveUntil || 0);
    }

    function isModalFieldFocused() {
        if (!els.modalBody || state.modalMode !== "block") {
            return false;
        }
        const active = document.activeElement;
        if (!(active instanceof HTMLElement) || !els.modalBody.contains(active)) {
            return false;
        }
        const tag = String(active.tagName || "").toLowerCase();
        return (
            tag === "input" ||
            tag === "textarea" ||
            tag === "select" ||
            active.isContentEditable
        );
    }

    function deepClone(value) {
        return JSON.parse(JSON.stringify(value || {}));
    }

    function stableSerialize(value) {
        if (Array.isArray(value)) {
            return "[" + value.map(stableSerialize).join(",") + "]";
        }
        if (value && typeof value === "object") {
            return (
                "{" +
                Object.keys(value)
                    .sort()
                    .map(function (key) {
                        return JSON.stringify(key) + ":" + stableSerialize(value[key]);
                    })
                    .join(",") +
                "}"
            );
        }
        const encoded = JSON.stringify(value);
        return typeof encoded === "string" ? encoded : "null";
    }

    function pageStateKeyFromValues(layout, pageLayout, pageTitleMode, templateConditions, pageCss) {
        return stableSerialize({
            layout: normalizeLayout(layout || []),
            pageLayout: normalizePageLayout(pageLayout || "default"),
            pageTitleMode: normalizePageTitleMode(pageTitleMode),
            templateConditions: normalizeTemplateConditions(templateConditions || {}),
            pageCss: String(pageCss || ""),
        });
    }

    function currentPageStateKey() {
        return pageStateKeyFromValues(
            state.layout,
            state.pageLayout,
            state.pageTitleMode,
            state.templateConditions,
            state.pageCss
        );
    }

    function globalStateKeyFromValues(tokens, customThemePacks, activeThemePack) {
        return stableSerialize({
            globalDesignTokens: normalizeGlobalDesignTokens(tokens || {}),
            customThemePacks: normalizeCustomThemePacks(customThemePacks || []),
            activeThemePack: String(activeThemePack || "").trim(),
        });
    }

    function currentGlobalStateKey() {
        return globalStateKeyFromValues(
            state.globalDesignTokens,
            state.customThemePacks,
            state.activeThemePack
        );
    }

    function captureSavedBaselines() {
        state.savedPageStateKey = currentPageStateKey();
        state.savedGlobalStateKey = currentGlobalStateKey();
        state.pageDirty = false;
        state.globalDesignDirty = false;
        state.dirty = false;
    }

    function historySnapshot() {
        return {
            layout: deepClone(state.layout),
            pageLayout: normalizePageLayout(state.pageLayout),
            pageTitleMode: normalizePageTitleMode(state.pageTitleMode),
            pageCss: String(state.pageCss || ""),
            templateConditions: normalizeTemplateConditions(
                state.templateConditions || {}
            ),
            globalDesignTokens: normalizeGlobalDesignTokens(
                state.globalDesignTokens || {}
            ),
            customThemePacks: normalizeCustomThemePacks(
                state.customThemePacks || []
            ),
            activeThemePack: String(state.activeThemePack || "").trim(),
            selectedId: String(state.selectedId || ""),
        };
    }

    function historySnapshotKey(snapshot) {
        return JSON.stringify(snapshot || {});
    }

    function pushHistorySnapshot(snapshot, clearFuture) {
        const key = historySnapshotKey(snapshot);
        const lastEntry =
            state.historyPast.length > 0
                ? state.historyPast[state.historyPast.length - 1]
                : null;
        if (lastEntry && String(lastEntry.key || "") === key) {
            updateUndoRedoButtons();
            return;
        }
        state.historyPast.push({ key: key, snapshot: snapshot });
        while (state.historyPast.length > Number(state.historyLimit || 120)) {
            state.historyPast.shift();
        }
        if (clearFuture) {
            state.historyFuture = [];
        }
        updateUndoRedoButtons();
    }

    function updateUndoRedoButtons() {
        if (els.undoButton) {
            els.undoButton.disabled = state.historyPast.length < 1;
        }
        if (els.redoButton) {
            els.redoButton.disabled = state.historyFuture.length < 1;
        }
    }

    function seedHistoryBaseline() {
        state.historyPast = [];
        state.historyFuture = [];
        updateUndoRedoButtons();
    }

    function captureHistoryBeforeMutation() {
        pushHistorySnapshot(historySnapshot(), true);
    }

    function applyHistorySnapshot(snapshot) {
        if (!snapshot || typeof snapshot !== "object") {
            return;
        }
        state.layout = normalizeLayout(snapshot.layout || []);
        state.pageLayout = normalizePageLayout(snapshot.pageLayout || "default");
        state.pageTitleMode = normalizePageTitleMode(snapshot.pageTitleMode || "auto");
        state.pageCss = String(snapshot.pageCss || "");
        state.templateConditions = normalizeTemplateConditions(
            snapshot.templateConditions || {}
        );
        state.globalDesignTokens = normalizeGlobalDesignTokens(
            snapshot.globalDesignTokens || {}
        );
        state.customThemePacks = normalizeCustomThemePacks(
            snapshot.customThemePacks || state.customThemePacks || []
        );
        state.activeThemePack = String(
            Object.prototype.hasOwnProperty.call(snapshot, "activeThemePack")
                ? snapshot.activeThemePack
                : state.activeThemePack || ""
        ).trim();
        state.selectedId = String(snapshot.selectedId || "");
        if (!state.selectedId && state.layout[0] && state.layout[0].id) {
            state.selectedId = String(state.layout[0].id);
        }
        if (state.modalMode) {
            closeBuilderModal(true);
        }
        closeContextMenu();
        closeNavigatorModal();
        setDirty(true);
        renderAll();
    }

    function undoHistory() {
        if (state.historyPast.length < 1) {
            updateUndoRedoButtons();
            return;
        }
        const previous = state.historyPast.pop();
        const currentSnapshot = historySnapshot();
        state.historyFuture.push({
            key: historySnapshotKey(currentSnapshot),
            snapshot: currentSnapshot,
        });
        updateUndoRedoButtons();
        applyHistorySnapshot(previous && previous.snapshot ? previous.snapshot : {});
    }

    function redoHistory() {
        if (state.historyFuture.length < 1) {
            updateUndoRedoButtons();
            return;
        }
        const next = state.historyFuture.pop();
        const currentSnapshot = historySnapshot();
        state.historyPast.push({
            key: historySnapshotKey(currentSnapshot),
            snapshot: currentSnapshot,
        });
        while (state.historyPast.length > Number(state.historyLimit || 120)) {
            state.historyPast.shift();
        }
        updateUndoRedoButtons();
        applyHistorySnapshot(next && next.snapshot ? next.snapshot : {});
    }

    function refreshBlockLabels() {
        if (!els.blockList) {
            syncSelectionActionBar();
            return;
        }

        const rows = els.blockList.querySelectorAll(".h4bs-block-item[data-block-id]");
        rows.forEach(function (row) {
            const blockId = String(row.getAttribute("data-block-id") || "");
            const block = findBlockById(blockId);
            if (!block) {
                return;
            }
            const label = row.querySelector(".h4bs-block-item-label");
            if (label) {
                const index = Math.max(
                    0,
                    state.layout.findIndex(function (entry) {
                        return String(entry.id || "") === blockId;
                    })
                );
                label.textContent = blockLabel(block, index);
            }
            row.classList.toggle(
                "is-selected",
                String(block.id || "") === String(state.selectedId || "")
            );
        });
        syncSelectionActionBar();
    }

    function findBlockById(blockId) {
        return (
            state.layout.find(function (block) {
                return String(block.id) === String(blockId || "");
            }) || null
        );
    }

    function currentModalBlock() {
        if (state.modalMode !== "block" || !state.modalDraftBlock) {
            return null;
        }
        return state.modalDraftBlock;
    }

    function wireModal() {
        if (els.modalCancelButtons) {
            els.modalCancelButtons.forEach(function (button) {
                button.addEventListener("click", function () {
                    closeBuilderModal(false);
                });
            });
        }

        if (els.modalBackdrop) {
            els.modalBackdrop.addEventListener("click", function () {
                closeBuilderModal(false);
            });
        }

        if (els.modalSaveButton) {
            els.modalSaveButton.addEventListener("click", function () {
                saveModalChanges();
            });
        }

        if (els.modalReviewButton) {
            els.modalReviewButton.addEventListener("click", function () {
                toggleCurrentDraftReview();
            });
        }

        if (els.modalDeleteButton) {
            els.modalDeleteButton.addEventListener("click", function () {
                if (state.modalMode !== "block" || !state.modalDraftBlock) {
                    return;
                }
                const blockId = String(state.modalDraftBlock.id || "");
                if (blockId === "") {
                    return;
                }
                closeBuilderModal(true);
                deleteBlock(blockId);
            });
        }

        document.addEventListener("click", function (event) {
            const target = event.target;
            if (!(target instanceof HTMLElement)) {
                return;
            }
            const openNav = target.closest("[data-h4bs-open-navigator]");
            if (openNav) {
                event.preventDefault();
                openNavigatorModal();
                return;
            }
            const openMini = target.closest("[data-h4bs-open-mini-preview]");
            if (openMini) {
                event.preventDefault();
                openMiniPreviewModal();
                return;
            }
            const openPage = target.closest("[data-h4bs-open-page-settings]");
            if (openPage) {
                event.preventDefault();
                openPageSettingsModal();
                return;
            }
            const closeNav = target.closest("[data-h4bs-close-navigator]");
            if (closeNav) {
                event.preventDefault();
                closeNavigatorModal(true);
                return;
            }
            const closeMini = target.closest("[data-h4bs-close-mini-preview]");
            if (closeMini) {
                event.preventDefault();
                closeMiniPreviewModal();
            }
        });

        if (els.widgetSearch) {
            els.widgetSearch.addEventListener("focus", function () {
                activateLibraryTab("widgets", true);
            });
            els.widgetSearch.addEventListener("input", function () {
                activateLibraryTab("widgets", true);
            });
        }
        if (els.elementSearch) {
            els.elementSearch.addEventListener("focus", function () {
                activateLibraryTab("elements", true);
            });
            els.elementSearch.addEventListener("input", function () {
                activateLibraryTab("elements", true);
                renderElementButtons();
            });
        }
        if (els.templateSearch) {
            els.templateSearch.addEventListener("focus", function () {
                activateLibraryTab("templates", true);
            });
            els.templateSearch.addEventListener("input", function () {
                activateLibraryTab("templates", true);
            });
        }
        if (els.templateCategory) {
            els.templateCategory.addEventListener("focus", function () {
                activateLibraryTab("templates", true);
            });
            els.templateCategory.addEventListener("change", function () {
                activateLibraryTab("templates", true);
            });
        }
        if (els.siteKitSearch) {
            els.siteKitSearch.addEventListener("focus", function () {
                activateLibraryTab("site-kits", true);
            });
            els.siteKitSearch.addEventListener("input", function () {
                activateLibraryTab("site-kits", true);
            });
        }
        if (els.themeSearch) {
            els.themeSearch.addEventListener("focus", function () {
                activateLibraryTab("themes", true);
            });
            els.themeSearch.addEventListener("input", function () {
                activateLibraryTab("themes", true);
            });
        }

        document.addEventListener("keydown", function (event) {
            if (event.key !== "Escape") {
                return;
            }
            if (state.contextMenuOpen) {
                closeContextMenu();
                return;
            }
            if (els.modal && !els.modal.hidden) {
                closeBuilderModal(false);
                return;
            }
            if (els.navigatorModal && !els.navigatorModal.hidden) {
                event.preventDefault();
                closeNavigatorModal(true);
                return;
            }
            if (els.miniPreviewModal && !els.miniPreviewModal.hidden) {
                closeMiniPreviewModal();
                return;
            }
            if (state.canvasFocus) {
                state.canvasFocus = false;
                persistStoredBoolean(CANVAS_FOCUS_KEY, false);
                applyCanvasFocusState();
            }
        });
    }

    function openBlockModal(blockId, options) {
        const found = findBlockById(blockId);
        if (!found || !els.modal || !els.modalBody) {
            return;
        }
        clearPendingInsertWhenSelectionChanges(blockId);
        closeContextMenu();
        const block = normalizeBlockForModal(found);
        const requestedHtmlTarget =
            options && options.htmlQuickEditTarget
                ? deepClone(options.htmlQuickEditTarget)
                : null;

        if (
            state.modalMode === "block" &&
            String(state.modalBlockId || "") === String(block.id || "")
        ) {
            state.selectedId = String(block.id || "");
            if (String(block.type || "") === "html") {
                state.htmlQuickEditTarget = requestedHtmlTarget;
                if (state.modalDraftBlock) {
                    renderModalForBlock(state.modalDraftBlock, "content");
                }
            }
            syncDraftFrameSelection(
                els.previewShell
                    ? els.previewShell.querySelector("[data-h4bs-draft-frame]")
                    : null
            );
            return;
        }
        if (state.modalMode === "block" && state.modalDirty) {
            commitModalBlockDraftToLayout();
        } else if (state.modalMode && state.modalDirty) {
            if (!window.confirm("Discard unsaved page settings?")) {
                return;
            }
        }

        state.modalMode = "block";
        state.modalBlockId = String(block.id);
        state.selectedId = String(block.id);
        state.modalDraftBlock = deepClone(block);
        state.htmlQuickEditTarget =
            String(block.type || "") === "html" ? requestedHtmlTarget : null;
        state.modalActiveTab = "content";
        state.modalDraftPage = null;
        state.modalDirty = false;
        state.modalDesignDevice = designDeviceFromViewportGroup(state.viewportGroup);
        state.modalDesignState = "normal";
        showBuilderModal();
        syncModalTitle(state.modalDraftBlock);
        renderModalForBlock(state.modalDraftBlock);
        focusInspectorPrimaryControl();
        refreshBlockLabels();
    }

    function openPageSettingsModal() {
        if (!els.modal || !els.modalBody) {
            return;
        }
        closeContextMenu();
        if (state.modalMode && state.modalDirty) {
            if (!window.confirm("Discard unsaved inspector changes?")) {
                return;
            }
        }

        state.modalMode = "page";
        state.modalBlockId = null;
        state.modalDraftBlock = null;
        state.htmlQuickEditTarget = null;
        state.modalActiveTab = "content";
        state.modalDraftPage = {
            pageLayout: String(state.pageLayout || "default"),
            pageTitleMode: normalizePageTitleMode(state.pageTitleMode),
            pageCss: String(state.pageCss || ""),
            templateConditions: deepClone(state.templateConditions || {}),
            globalDesignTokens: deepClone(state.globalDesignTokens || {}),
        };
        state.modalDirty = false;
        state.modalGlobalDirty = false;
        showBuilderModal();
        syncModalTitle(null);
        renderPageSettingsModal();
        focusInspectorPrimaryControl();
    }

    function closeBuilderModal(forceClose) {
        const hardClose = !!forceClose;
        const shouldRestorePreview = !hardClose && !!state.modalMode;
        if (!hardClose && state.modalDirty) {
            if (!window.confirm("Discard unsaved inspector changes?")) {
                return;
            }
        }

        state.modalMode = null;
        state.modalDirty = false;
        state.modalGlobalDirty = false;
        state.modalDraftBlock = null;
        state.modalActiveTab = "content";
        state.modalDraftPage = null;
        state.modalBlockId = null;
        state.modalDesignDevice = "desktop";
        state.modalDesignState = "normal";
        if (typeof state.inspectorSettingFinderCleanup === "function") {
            state.inspectorSettingFinderCleanup();
            state.inspectorSettingFinderCleanup = null;
        }
        if (state.modalPreviewTimer) {
            window.clearTimeout(state.modalPreviewTimer);
            state.modalPreviewTimer = null;
        }

        if (els.modal) {
            els.modal.hidden = true;
        }
        if (els.modalBackdrop) {
            els.modalBackdrop.hidden = true;
        }
        if (els.inspectorEmpty) {
            els.inspectorEmpty.hidden = false;
        }
        root.classList.remove("has-inspector");
        document.body.classList.remove("h4bs-has-builder-inspector");
        if (state.inspectorAutoCollapsedSide) {
            state.sideCollapsed = state.inspectorPreviousSideCollapsed;
            applySidePanelState();
        }
        state.inspectorAutoCollapsedSide = false;
        state.inspectorPreviousSideCollapsed = state.sideCollapsed;
        if (els.modalBody) {
            els.modalBody.innerHTML = "";
        }
        if (els.modalDeleteButton) {
            els.modalDeleteButton.hidden = true;
        }
        if (shouldRestorePreview) {
            renderPreviewFallbackClient();
            requestServerPreviewRender(0);
        }
        if (state.modalReturnFocus instanceof HTMLElement && state.modalReturnFocus.isConnected) {
            state.modalReturnFocus.focus({ preventScroll: true });
        }
        state.modalReturnFocus = null;
    }

    function showBuilderModal() {
        if (!state.modalMode) {
            return;
        }
        const opening = !els.modal || els.modal.hidden;
        if (opening) {
            state.modalReturnFocus =
                document.activeElement instanceof HTMLElement ? document.activeElement : null;
            state.inspectorPreviousSideCollapsed = state.sideCollapsed;
            state.inspectorAutoCollapsedSide = !state.sideCollapsed;
            if (state.inspectorAutoCollapsedSide) {
                state.sideCollapsed = true;
                applySidePanelState();
            }
        }
        if (els.modal) {
            els.modal.hidden = false;
        }
        if (els.modalBackdrop) {
            els.modalBackdrop.hidden = true;
        }
        if (els.inspectorEmpty) {
            els.inspectorEmpty.hidden = true;
        }
        root.classList.add("has-inspector");
        document.body.classList.add("h4bs-has-builder-inspector");
        applyInspectorWidth(state.inspectorWidth, false);
    }

    function focusInspectorPrimaryControl() {
        window.requestAnimationFrame(function () {
            if (!els.modal || els.modal.hidden || !els.modalBody) {
                return;
            }
            const target = els.modalBody.querySelector(
                ".h4bs-inspector-panel:not([hidden]) input:not([type='hidden']):not(:disabled), " +
                ".h4bs-inspector-panel:not([hidden]) textarea:not(:disabled), " +
                ".h4bs-inspector-panel:not([hidden]) select:not(:disabled), " +
                ".h4bs-inspector-panel:not([hidden]) button:not(:disabled)"
            );
            if (target instanceof HTMLElement) {
                target.focus({ preventScroll: true });
            }
        });
    }

    function syncModalTitle(block) {
        if (!els.modalTitle) {
            return;
        }

        if (state.modalMode === "page") {
            syncModalHelp(null, "layout");
            if (els.modalSaveButton) {
                els.modalSaveButton.textContent = "Save Page Settings";
            }
            els.modalTitle.textContent = state.modalDirty
                ? "Page Settings (unsaved)"
                : "Page Settings";
            syncModalDeleteButtonState();
            return;
        }

        if (els.modalSaveButton) {
            els.modalSaveButton.textContent = "Save Element Changes";
        }

        if (!block) {
            syncModalHelp(null);
            els.modalTitle.textContent = "Element Settings";
            syncModalDeleteButtonState();
            return;
        }

        const index = state.layout.findIndex(function (row) {
            return String(row.id) === String(block.id);
        });
        const label = blockLabel(block, Math.max(index, 0));
        syncModalHelp(block);
        els.modalTitle.textContent = state.modalDirty ? label + " (unsaved)" : label;
        syncModalDeleteButtonState();
    }

    function syncModalDeleteButtonState() {
        if (!els.modalDeleteButton) {
            return;
        }
        const canDelete = state.modalMode === "block" && !!state.modalDraftBlock;
        els.modalDeleteButton.hidden = !canDelete;
    }

    function markModalDirty(flag) {
        if (state.modalMode === "block" && state.modalDraftBlock) {
            const currentBlock = findBlockById(state.modalDraftBlock.id);
            state.modalDirty = currentBlock
                ? stableSerialize(normalizeBlockForModal(currentBlock)) !==
                    stableSerialize(normalizeBlockForModal(state.modalDraftBlock))
                : !!flag;
        } else if (state.modalMode === "page" && state.modalDraftPage) {
            const modalPageKey = stableSerialize({
                pageLayout: normalizePageLayout(
                    state.modalDraftPage.pageLayout || "default"
                ),
                pageTitleMode: normalizePageTitleMode(
                    state.modalDraftPage.pageTitleMode || "auto"
                ),
                pageCss: String(state.modalDraftPage.pageCss || ""),
                templateConditions: normalizeTemplateConditions(
                    state.modalDraftPage.templateConditions || {}
                ),
            });
            const currentPageKey = stableSerialize({
                pageLayout: normalizePageLayout(state.pageLayout || "default"),
                pageTitleMode: normalizePageTitleMode(state.pageTitleMode),
                pageCss: String(state.pageCss || ""),
                templateConditions: normalizeTemplateConditions(
                    state.templateConditions || {}
                ),
            });
            state.modalGlobalDirty =
                globalStateKeyFromValues(
                    state.modalDraftPage.globalDesignTokens || {},
                    state.customThemePacks,
                    state.activeThemePack
                ) !== currentGlobalStateKey();
            state.modalDirty = modalPageKey !== currentPageKey || state.modalGlobalDirty;
        } else {
            state.modalDirty = !!flag;
        }
        if (!state.modalDirty) {
            syncModalTitle(currentModalBlock());
            return;
        }
        syncModalTitle(currentModalBlock());
        if (state.modalMode === "page" && state.modalDraftPage) {
            requestModalPreviewRender();
        }
    }

    function saveModalChanges() {
        if (state.modalMode === "block" && state.modalDraftBlock) {
            const validationErrors = validateModalBlock(state.modalDraftBlock);
            if (validationErrors.length) {
                showModalValidationErrors(validationErrors);
                return;
            }
            const committed = commitModalBlockDraftToLayout();
            closeBuilderModal(true);
            renderAll();
            if (committed) {
                saveLayout(false);
            }
            return;
        }

        if (state.modalMode === "page" && state.modalDraftPage) {
            if (!state.modalDirty) {
                closeBuilderModal(true);
                return;
            }
            captureHistoryBeforeMutation();
            state.pageLayout = normalizePageLayout(
                String(state.modalDraftPage.pageLayout || "default")
            );
            state.pageTitleMode = normalizePageTitleMode(
                state.modalDraftPage.pageTitleMode || "auto"
            );
            state.pageCss = String(state.modalDraftPage.pageCss || "");
            state.globalDesignTokens = normalizeGlobalDesignTokens(
                state.modalDraftPage.globalDesignTokens || {}
            );
            state.templateConditions = normalizeTemplateConditions(
                state.modalDraftPage.templateConditions || {}
            );
            setDirty(true);
            closeBuilderModal(true);
            renderAll();
        }
    }

    function commitModalBlockDraftToLayout() {
        if (state.modalMode !== "block" || !state.modalDraftBlock) {
            return false;
        }
        const idx = state.layout.findIndex(function (block) {
            return String(block.id) === String(state.modalDraftBlock.id);
        });
        if (idx < 0 || !state.modalDirty) {
            return false;
        }
        captureHistoryBeforeMutation();
        state.layout[idx] = deepClone(state.modalDraftBlock);
        state.selectedId = String(state.layout[idx].id);
        state.modalDirty = false;
        setDirty(true);
        return true;
    }

    function commitModalDraftToWorkspace() {
        if (!state.modalDirty) {
            return false;
        }
        if (state.modalMode === "block" && state.modalDraftBlock) {
            return commitModalBlockDraftToLayout();
        }
        if (state.modalMode !== "page" || !state.modalDraftPage) {
            return false;
        }
        captureHistoryBeforeMutation();
        state.pageLayout = normalizePageLayout(
            String(state.modalDraftPage.pageLayout || "default")
        );
        state.pageTitleMode = normalizePageTitleMode(
            state.modalDraftPage.pageTitleMode || "auto"
        );
        state.pageCss = String(state.modalDraftPage.pageCss || "");
        state.globalDesignTokens = normalizeGlobalDesignTokens(
            state.modalDraftPage.globalDesignTokens || {}
        );
        state.templateConditions = normalizeTemplateConditions(
            state.modalDraftPage.templateConditions || {}
        );
        state.modalDirty = false;
        state.modalGlobalDirty = false;
        setDirty(true);
        return true;
    }

    function renderModalForBlock(block, activeTab) {
        if (!els.modalBody) {
            return;
        }
        const modalBlock = normalizeBlockForModal(block);
        if (
            state.modalDraftBlock &&
            String(state.modalDraftBlock.id || "") === String(modalBlock.id || "")
        ) {
            state.modalDraftBlock = modalBlock;
        }

        els.modalBody.innerHTML = "";

        try {
            const settings =
                modalBlock.settings && typeof modalBlock.settings === "object"
                    ? modalBlock.settings
                    : {};
            const tabs = createModalTabs([
                { key: "content", label: "Content" },
                { key: "style", label: "Design" },
                { key: "advanced", label: "Advanced" },
            ]);
            els.modalBody.appendChild(tabs.root);
            const contentPanel = tabs.panels.content;
            const stylePanel = tabs.panels.style;
            const advancedPanel = tabs.panels.advanced;

            const fields = blockFieldsByType(modalBlock.type);
            const contentGroups = buildContentGroupsForType(
                modalBlock.type,
                contentPanel
            );
            if (String(modalBlock.type || "") === "html") {
                const quickEditTarget = resolveContentGroupByKey(
                    contentGroups,
                    contentPanel,
                    "content"
                );
                quickEditTarget.appendChild(
                    buildHtmlQuickEditor(modalBlock, state.htmlQuickEditTarget)
                );
            }
            if (!Array.isArray(fields) || fields.length < 1) {
                const emptyState = document.createElement("p");
                emptyState.className = "h4bs-inspector-empty";
                emptyState.textContent =
                    "No content fields are defined for this element yet. You can edit raw settings JSON below.";
                contentPanel.appendChild(emptyState);
                contentPanel.appendChild(buildRawSettingsFallback(modalBlock));
            }
            fields.forEach(function (field) {
                const target = resolveContentTarget(
                    contentGroups,
                    contentPanel,
                    modalBlock.type,
                    field
                );
                const control = buildBlockContentFieldControl(
                    field,
                    settings,
                    modalBlock
                );
                if (control) {
                    target.appendChild(control);
                }
            });

            if (isContainerType(modalBlock.type)) {
                const inheritHint = document.createElement("p");
                inheritHint.className = "h4bs-inspector-empty";
                inheritHint.textContent =
                    "Global container max width is currently " +
                    globalContainerMaxWidthCssValue() +
                    ". Use Container Width = Custom to override on this section.";
                const layoutTarget = resolveContentGroupByKey(
                    contentGroups,
                    contentPanel,
                    "layout"
                );
                layoutTarget.appendChild(inheritHint);
                const widthsHint = document.createElement("p");
                widthsHint.className = "h4bs-inspector-empty";
                widthsHint.textContent =
                    "Column Width Split accepts pipe or comma values like 30|70 or 20,30,50. Values auto-normalize to 100%.";
                layoutTarget.appendChild(widthsHint);
            }

            if (modalBlock.type !== "section") {
                const sectionOptions = [{ value: "", label: "Top-level page flow" }];
                state.layout.forEach(function (row) {
                    if (
                        row &&
                        typeof row === "object" &&
                        isContainerType(row.type) &&
                        String(row.id || "") !== String(modalBlock.id || "")
                    ) {
                        sectionOptions.push({
                            value: String(row.id || ""),
                            label: blockLabel(row, 0),
                        });
                    }
                });

                const layoutTarget = resolveContentGroupByKey(
                    contentGroups,
                    contentPanel,
                    "layout"
                );
                layoutTarget.appendChild(
                    createField(
                        {
                            label: "Place Inside Container",
                            type: "select",
                            options: sectionOptions,
                        },
                        String(modalBlock.parent_id || ""),
                        function (value) {
                            modalBlock.parent_id = String(value || "");
                            if (modalBlock.parent_id === "") {
                                modalBlock.slot = 0;
                            }
                            markModalDirty(true);
                            requestModalPreviewRender();
                        }
                    )
                );

                if (String(modalBlock.parent_id || "") !== "") {
                    layoutTarget.appendChild(
                        createField(
                            {
                                label: "Container Column (1.." + String(MAX_COLUMNS) + ")",
                                type: "number",
                            },
                            String((Number(modalBlock.slot || 0) || 0) + 1),
                            function (value) {
                                const slot = Math.max(
                                    0,
                                    Math.min(MAX_SLOT, Number(value || "1") - 1)
                                );
                                modalBlock.slot = slot;
                                markModalDirty(true);
                                requestModalPreviewRender();
                            }
                        )
                    );
                }
            }
            finalizeContentGroups(contentGroups);

            stylePanel.appendChild(renderDesignContextControls(modalBlock));
            const styleGroups = buildStyleGroupsForType(modalBlock.type, stylePanel);
            designFieldsForType(modalBlock.type).forEach(function (baseField) {
                const field = designFieldForActiveContext(baseField, settings);
                const styleTarget = resolveStyleTarget(
                    styleGroups,
                    stylePanel,
                    modalBlock.type,
                    baseField
                );
                if (field.type === "size") {
                    const rawValue = Object.prototype.hasOwnProperty.call(settings, field.key)
                        ? settings[field.key]
                        : field.default;
                    const value =
                        rawValue === null || typeof rawValue === "undefined"
                            ? ""
                            : String(rawValue);
                    const unitRaw = field.unit_key
                        ? settings[field.unit_key]
                        : field.unit_default;
                    const unit =
                        unitRaw === null || typeof unitRaw === "undefined"
                            ? String(field.unit_default || "px")
                            : String(unitRaw || field.unit_default || "px");
                    const control = createSizeField(field, value, unit, function (
                        nextValue,
                        nextUnit
                    ) {
                        applyDraftBlockSettingChange(modalBlock, field.key, nextValue);
                        if (field.unit_key) {
                            applyDraftBlockSettingChange(
                                modalBlock,
                                field.unit_key,
                                nextUnit
                            );
                        }
                    });
                    styleTarget.appendChild(
                        decorateDesignContextControl(
                            control,
                            baseField,
                            field,
                            settings,
                            modalBlock
                        )
                    );
                    return;
                }

                if (field.type === "box4") {
                    const control = createBoxField(field, settings, function (
                        key,
                        value
                    ) {
                        applyDraftBlockSettingChange(modalBlock, key, value);
                    });
                    styleTarget.appendChild(
                        decorateDesignContextControl(
                            control,
                            baseField,
                            field,
                            settings,
                            modalBlock
                        )
                    );
                    return;
                }

                const hasValue = Object.prototype.hasOwnProperty.call(settings, field.key);
                const rawValue = hasValue ? settings[field.key] : field.default;
                const current =
                    rawValue === null || typeof rawValue === "undefined"
                        ? ""
                        : String(rawValue);
                const control = createField(field, current, function (value) {
                    applyDraftBlockSettingChange(modalBlock, field.key, value);
                });
                styleTarget.appendChild(
                    decorateDesignContextControl(
                        control,
                        baseField,
                        field,
                        settings,
                        modalBlock
                    )
                );
            });
            finalizeStyleGroups(styleGroups);

            advancedPanel.appendChild(renderAdvancedElementSettings(modalBlock));
            advancedPanel.appendChild(renderVisibilityEditor(modalBlock));
            advancedPanel.appendChild(renderBlockSpecActions(modalBlock));
            const requestedTab = ["content", "style", "advanced"].includes(
                String(activeTab || state.modalActiveTab || "content")
            )
                ? String(activeTab || state.modalActiveTab || "content")
                : "content";
            tabs.activate(requestedTab);
        } catch (error) {
            const fallback = document.createElement("p");
            fallback.className = "h4bs-inspector-empty";
            fallback.textContent =
                "Element settings failed to load. Try re-selecting the element.";
            els.modalBody.appendChild(fallback);
        }
    }

    function buildRawSettingsFallback(modalBlock) {
        const wrapper = document.createElement("div");
        wrapper.className = "h4bs-field";

        const label = document.createElement("label");
        label.textContent = "Raw Settings JSON";
        wrapper.appendChild(label);

        const textarea = document.createElement("textarea");
        textarea.rows = 10;
        textarea.style.fontFamily = "Consolas, Menlo, monospace";
        textarea.value = JSON.stringify(
            modalBlock && modalBlock.settings ? modalBlock.settings : {},
            null,
            2
        );
        wrapper.appendChild(textarea);

        const note = document.createElement("small");
        note.className = "h4bs-inspector-empty";
        note.style.display = "block";
        note.style.marginTop = "6px";
        note.textContent =
            "Use valid JSON object format. Changes apply on blur or Enter+Ctrl/Cmd.";
        wrapper.appendChild(note);

        const applyRawSettings = function () {
            markModalInputActive();
            const raw = String(textarea.value || "").trim();
            if (raw === "") {
                modalBlock.settings = {};
                markModalDirty(true);
                requestModalPreviewRender();
                note.textContent = "Settings cleared.";
                return;
            }
            try {
                const parsed = JSON.parse(raw);
                if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
                    note.textContent = "JSON must be an object (example: {\"text\":\"Hello\"}).";
                    return;
                }
                modalBlock.settings = parsed;
                markModalDirty(true);
                requestModalPreviewRender();
                note.textContent = "Settings applied.";
            } catch (_error) {
                note.textContent = "Invalid JSON. Fix syntax and try again.";
            }
        };

        textarea.addEventListener("blur", function () {
            applyRawSettings();
        });
        textarea.addEventListener("keydown", function (event) {
            const key = String(event && event.key ? event.key : "");
            const withModifier = !!(
                event &&
                (event.ctrlKey === true || event.metaKey === true)
            );
            if (key === "Enter" && withModifier) {
                event.preventDefault();
                applyRawSettings();
            }
        });

        return wrapper;
    }

    function createShortcodeBuilderField(field, value, modalBlock, onChange) {
        const wrapper = document.createElement("div");
        wrapper.className = "h4bs-field h4bs-shortcode-builder";

        const spec = parseShortcodeEditorValue(value);
        const widget = widgetForShortcodeBlock(modalBlock, spec);
        const controlDefinitions = widgetControlDefinitions(widget);
        const heading = document.createElement("div");
        heading.className = "h4bs-shortcode-builder-head";
        const title = document.createElement("strong");
        title.textContent = widget
            ? String(widget.label || spec.tag || "Widget")
            : spec.tag
            ? "Shortcode: " + spec.tag
            : "Shortcode";
        heading.appendChild(title);
        const badge = document.createElement("span");
        badge.textContent = widget
            ? String(widget.category || "Widget")
            : "Custom";
        heading.appendChild(badge);
        wrapper.appendChild(heading);

        const parameterList = document.createElement("div");
        parameterList.className = "h4bs-shortcode-parameters";
        wrapper.appendChild(parameterList);

        const rawDetails = document.createElement("details");
        rawDetails.className = "h4bs-shortcode-raw";
        const rawSummary = document.createElement("summary");
        rawSummary.textContent = "Raw shortcode";
        rawDetails.appendChild(rawSummary);
        const rawInput = document.createElement("textarea");
        rawInput.rows = Number(field.rows || 5);
        rawInput.value = String(value || "");
        rawDetails.appendChild(rawInput);
        wrapper.appendChild(rawDetails);

        const emit = function () {
            const next = buildShortcodeEditorValue(spec);
            rawInput.value = next;
            onChange(next, null);
        };

        const renderParameters = function () {
            parameterList.innerHTML = "";
            if (!spec.tag) {
                const note = document.createElement("p");
                note.className = "h4bs-inspector-empty";
                note.textContent =
                    "Enter a valid shortcode below to unlock structured widget parameters.";
                parameterList.appendChild(note);
                return;
            }

            const tagRow = document.createElement("div");
            tagRow.className = "h4bs-shortcode-tag";
            tagRow.innerHTML =
                "<span>Shortcode</span><code>[" + escHtml(spec.tag) + "]</code>";
            parameterList.appendChild(tagRow);

            spec.attributes.forEach(function (attribute, index) {
                const row = document.createElement("div");
                row.className = "h4bs-shortcode-parameter-row";

                const key = document.createElement("input");
                key.type = "text";
                key.className = "h4bs-shortcode-parameter-key";
                key.value = String(attribute.key || "");
                key.setAttribute("aria-label", "Parameter name");
                key.addEventListener("input", function () {
                    const nextKey = String(key.value || "")
                        .trim()
                        .replace(/[^a-zA-Z0-9_-]/g, "");
                    attribute.key = nextKey;
                    key.classList.toggle("is-invalid", nextKey === "");
                    emit();
                });
                row.appendChild(key);

                const parameterValue = document.createElement("input");
                parameterValue.type = "text";
                parameterValue.className = "h4bs-shortcode-parameter-value";
                parameterValue.value = String(attribute.value || "");
                parameterValue.setAttribute(
                    "aria-label",
                    String(attribute.key || "Parameter") + " value"
                );
                parameterValue.addEventListener("input", function () {
                    attribute.value = String(parameterValue.value || "");
                    emit();
                });
                row.appendChild(parameterValue);

                const remove = document.createElement("button");
                remove.type = "button";
                remove.className = "button button-link-delete";
                remove.setAttribute("aria-label", "Remove parameter");
                remove.title = "Remove parameter";
                remove.innerHTML =
                    "<span class='dashicons dashicons-no-alt' aria-hidden='true'></span>";
                remove.addEventListener("click", function () {
                    spec.attributes.splice(index, 1);
                    emit();
                    renderParameters();
                });
                row.appendChild(remove);
                parameterList.appendChild(row);
            });

            const activeKeys = new Set(
                spec.attributes.map(function (attribute) {
                    return String(attribute && attribute.key ? attribute.key : "");
                })
            );
            const availableControls = controlDefinitions.filter(function (control) {
                return !activeKeys.has(String(control.key || ""));
            });
            if (availableControls.length) {
                const suggestions = document.createElement("details");
                suggestions.className = "h4bs-shortcode-suggestions";
                suggestions.open = availableControls.length <= 10;
                const suggestionsSummary = document.createElement("summary");
                suggestionsSummary.textContent =
                    "Available widget controls (" +
                    String(availableControls.length) +
                    ")";
                suggestions.appendChild(suggestionsSummary);

                const suggestionSearch = document.createElement("input");
                suggestionSearch.type = "search";
                suggestionSearch.placeholder = "Search widget controls...";
                suggestionSearch.className = "h4bs-shortcode-suggestion-search";
                suggestions.appendChild(suggestionSearch);

                const suggestionList = document.createElement("div");
                suggestionList.className = "h4bs-shortcode-suggestion-list";
                suggestions.appendChild(suggestionList);
                availableControls.forEach(function (control) {
                    const suggestion = document.createElement("div");
                    suggestion.className = "h4bs-shortcode-suggestion";
                    suggestion.dataset.search = (
                        control.label +
                        " " +
                        control.key
                    ).toLowerCase();

                    const suggestionLabel = document.createElement("label");
                    suggestionLabel.textContent = control.label;
                    const keyHint = document.createElement("code");
                    keyHint.textContent = control.key;
                    suggestionLabel.appendChild(keyHint);
                    suggestion.appendChild(suggestionLabel);

                    let suggestionInput;
                    if (control.type === "select") {
                        suggestionInput = document.createElement("select");
                        control.options.forEach(function (option) {
                            const opt = document.createElement("option");
                            opt.value = option.value;
                            opt.textContent = option.label;
                            if (option.value === control.default) {
                                opt.selected = true;
                            }
                            suggestionInput.appendChild(opt);
                        });
                    } else {
                        suggestionInput = document.createElement("input");
                        suggestionInput.type = control.type;
                        suggestionInput.value = control.default;
                    }
                    suggestionInput.setAttribute(
                        "aria-label",
                        control.label + " value"
                    );
                    suggestion.appendChild(suggestionInput);

                    const use = document.createElement("button");
                    use.type = "button";
                    use.className = "button button-small";
                    use.textContent = "Use";
                    use.addEventListener("click", function () {
                        spec.attributes.push({
                            key: control.key,
                            value: String(suggestionInput.value || ""),
                        });
                        emit();
                        renderParameters();
                    });
                    suggestion.appendChild(use);
                    suggestionList.appendChild(suggestion);
                });
                suggestionSearch.addEventListener("input", function () {
                    const query = String(suggestionSearch.value || "")
                        .trim()
                        .toLowerCase();
                    suggestionList
                        .querySelectorAll(".h4bs-shortcode-suggestion")
                        .forEach(function (suggestion) {
                            suggestion.hidden =
                                query !== "" &&
                                String(suggestion.dataset.search || "").indexOf(
                                    query
                                ) < 0;
                        });
                });
                parameterList.appendChild(suggestions);
            }

            const add = document.createElement("button");
            add.type = "button";
            add.className = "button h4bs-shortcode-add-parameter";
            add.innerHTML =
                "<span class='dashicons dashicons-plus-alt2' aria-hidden='true'></span> Add parameter";
            add.addEventListener("click", function () {
                spec.attributes.push({ key: "parameter", value: "" });
                emit();
                renderParameters();
                const keys = parameterList.querySelectorAll(
                    ".h4bs-shortcode-parameter-key"
                );
                const newest = keys.length ? keys[keys.length - 1] : null;
                if (newest instanceof HTMLInputElement) {
                    newest.focus();
                    newest.select();
                }
            });
            parameterList.appendChild(add);
        };

        rawInput.addEventListener("input", function () {
            markModalInputActive();
            onChange(String(rawInput.value || ""), null);
        });
        rawInput.addEventListener("blur", function () {
            const nextSpec = parseShortcodeEditorValue(rawInput.value);
            spec.tag = nextSpec.tag;
            spec.attributes = nextSpec.attributes;
            spec.suffix = nextSpec.suffix;
            renderParameters();
        });

        renderParameters();
        return wrapper;
    }

    function renderAdvancedElementSettings(modalBlock) {
        const wrap = document.createElement("section");
        wrap.className = "h4bs-advanced-element-settings";
        const heading = document.createElement("h4");
        heading.className = "h4bs-field-group-heading";
        heading.textContent = "Element Attributes";
        wrap.appendChild(heading);
        const settings =
            modalBlock.settings && typeof modalBlock.settings === "object"
                ? modalBlock.settings
                : {};
        advancedFieldsForType(modalBlock.type).forEach(function (field) {
            const value = Object.prototype.hasOwnProperty.call(settings, field.key)
                ? String(settings[field.key] || "")
                : String(field.default || "");
            wrap.appendChild(
                createField(field, value, function (nextValue) {
                    applyDraftBlockSettingChange(
                        modalBlock,
                        field.key,
                        nextValue
                    );
                    if (field.key === "advanced_admin_label") {
                        refreshBlockLabels();
                    }
                })
            );
        });
        return wrap;
    }

    function buildBlockContentFieldControl(field, settings, modalBlock) {
        if (!field || typeof field !== "object") {
            return null;
        }
        if (field.type === "collection_presets") {
            return createCollectionPresetField(modalBlock);
        }
        if (field.type === "collection_items") {
            field = { ...field, collectionFields: Array.isArray(settings.fields) ? settings.fields : [] };
        }
        const hasValue = Object.prototype.hasOwnProperty.call(settings, field.key);
        const rawValue = hasValue ? settings[field.key] : field.default;
        const structuredField = field.type === "collection_items" || field.type === "collection_filters";
        const current = structuredField
            ? (Array.isArray(rawValue) ? rawValue : [])
            : (rawValue === null || typeof rawValue === "undefined" ? "" : String(rawValue));

        if (field.type === "shortcode_builder") {
            return createShortcodeBuilderField(
                field,
                current,
                modalBlock,
                function (value) {
                    applyDraftBlockSettingChange(
                        modalBlock,
                        field.key,
                        value
                    );
                }
            );
        }

        if (field.type === "size") {
            const unitRaw = field.unit_key
                ? settings[field.unit_key]
                : field.unit_default;
            const unit =
                unitRaw === null || typeof unitRaw === "undefined"
                    ? String(field.unit_default || "px")
                    : String(unitRaw || field.unit_default || "px");
            return createSizeField(field, current, unit, function (
                nextValue,
                nextUnit
            ) {
                applyDraftBlockSettingChange(modalBlock, field.key, nextValue);
                if (field.unit_key) {
                    applyDraftBlockSettingChange(
                        modalBlock,
                        field.unit_key,
                        nextUnit
                    );
                }
            });
        }

        if (field.type === "box4") {
            return createBoxField(field, settings, function (key, value) {
                applyDraftBlockSettingChange(modalBlock, key, value);
            });
        }

        return createField(field, current, function (value, meta) {
            applyDraftBlockSettingChange(modalBlock, field.key, value);
            if (field.attachmentKey) {
                const attachmentId =
                    meta && Number(meta.attachmentId || 0) > 0
                        ? Number(meta.attachmentId || 0)
                        : 0;
                applyDraftBlockSettingChange(
                    modalBlock,
                    String(field.attachmentKey),
                    String(attachmentId)
                );
                if (
                    modalBlock.type === "image" &&
                    meta &&
                    meta.attachment &&
                    (!modalBlock.settings.alt ||
                        String(modalBlock.settings.alt).trim() === "")
                ) {
                    const altFromAttachment = String(meta.attachment.alt || "");
                    if (altFromAttachment !== "") {
                        applyDraftBlockSettingChange(
                            modalBlock,
                            "alt",
                            altFromAttachment
                        );
                    }
                }
                if (modalBlock.type === "image") {
                    const selectedAttachment = meta && meta.attachment
                        ? meta.attachment
                        : null;
                    applyDraftBlockSettingChange(
                        modalBlock,
                        "intrinsic_width",
                        selectedAttachment && Number(selectedAttachment.width || 0) > 0
                            ? String(Math.round(Number(selectedAttachment.width || 0)))
                            : ""
                    );
                    applyDraftBlockSettingChange(
                        modalBlock,
                        "intrinsic_height",
                        selectedAttachment && Number(selectedAttachment.height || 0) > 0
                            ? String(Math.round(Number(selectedAttachment.height || 0)))
                            : ""
                    );
                }
            }
        });
    }

    function buildContentGroupsForType(type, panel) {
        if (!(panel instanceof HTMLElement)) {
            return null;
        }
        const groups = [
            { key: "content", label: "Content", expanded: true },
            { key: "media", label: "Media", expanded: true },
            { key: "layout", label: "Layout", expanded: false },
            { key: "behavior", label: "Behavior", expanded: false },
            { key: "advanced", label: "Advanced", expanded: false },
        ];
        const map = {};
        groups.forEach(function (group) {
            const accordion = createContentDropdownGroup(
                group.label,
                group.expanded
            );
            panel.appendChild(accordion.root);
            map[group.key] = {
                key: group.key,
                root: accordion.root,
                body: accordion.body,
                used: false,
            };
        });
        return map;
    }

    function createContentDropdownGroup(label, expanded) {
        const root = document.createElement("section");
        root.className = "h4bs-content-group";

        const toggle = document.createElement("button");
        toggle.type = "button";
        toggle.className = "h4bs-content-group-toggle";
        toggle.setAttribute("aria-expanded", expanded ? "true" : "false");
        root.appendChild(toggle);

        const title = document.createElement("span");
        title.className = "h4bs-content-group-title";
        title.textContent = String(label || "Group");
        toggle.appendChild(title);

        const caret = document.createElement("span");
        caret.className = "h4bs-content-group-caret";
        caret.textContent = expanded ? "v" : ">";
        toggle.appendChild(caret);

        const body = document.createElement("div");
        body.className = "h4bs-content-group-body";
        body.hidden = !expanded;
        root.appendChild(body);

        toggle.addEventListener("click", function () {
            const nextExpanded = body.hidden;
            body.hidden = !nextExpanded;
            toggle.setAttribute("aria-expanded", nextExpanded ? "true" : "false");
            caret.textContent = nextExpanded ? "v" : ">";
        });

        return { root: root, body: body };
    }

    function contentGroupKeyForField(type, field) {
        const blockType = String(type || "");
        const key = String(field && field.key ? field.key : "");
        if (key === "") {
            return "content";
        }
        if (
            key === "src" ||
            key === "media_src" ||
            key === "hls_src" ||
            key === "fallback_src" ||
            key === "fallback_media_src" ||
            key === "poster_src" ||
            key === "poster_media_src" ||
            key === "fallback_image_src" ||
            key === "fallback_image_media_src" ||
            key === "images" ||
            key === "embed_url" ||
            key === "alt" ||
            key === "title" ||
            key === "caption" ||
            key === "attachment_id" ||
            key.indexOf("image") >= 0 ||
            key.indexOf("gallery") >= 0
        ) {
            return "media";
        }
        if (
            key === "provider" ||
            key === "preload" ||
            key === "autoplay" ||
            key === "controls" ||
            key === "loading" ||
            key === "muted" ||
            key === "loop" ||
            key === "lightbox" ||
            key === "open_first" ||
            key === "ordered" ||
            key === "show_form" ||
            key === "show_map" ||
            key === "show_reviews" ||
            key === "view"
        ) {
            return "behavior";
        }
        if (
            key === "columns" ||
            key === "gap" ||
            key === "min_height" ||
            key === "column_labels" ||
            key === "column_widths" ||
            key === "layout_mode" ||
            key === "content_width_mode" ||
            key === "content_width" ||
            key === "content_width_unit" ||
            key === "width" ||
            key === "width_unit" ||
            key === "max_width" ||
            key === "max_width_unit" ||
            key === "height" ||
            key === "height_unit" ||
            key === "location" ||
            key === "reviews" ||
            key === "object_fit" ||
            key === "border_radius" ||
            key === "border_radius_unit" ||
            key.indexOf("flex_") === 0 ||
            key.indexOf("align_") === 0 ||
            key.indexOf("justify_") === 0
        ) {
            return "layout";
        }
        if (
            key === "note" ||
            key === "slider_id" ||
            key === "shortcode" ||
            key === "html"
        ) {
            if (
                blockType === "shortcode" &&
                String(field && field.type ? field.type : "") ===
                    "shortcode_builder"
            ) {
                return "content";
            }
            return blockType === "shortcode" || blockType === "html"
                ? "advanced"
                : "content";
        }
        return "content";
    }

    function resolveContentTarget(contentGroups, fallbackPanel, type, field) {
        if (!contentGroups || typeof contentGroups !== "object") {
            return fallbackPanel;
        }
        const key = contentGroupKeyForField(type, field);
        if (
            contentGroups[key] &&
            contentGroups[key].body instanceof HTMLElement
        ) {
            contentGroups[key].used = true;
            return contentGroups[key].body;
        }
        if (
            contentGroups.content &&
            contentGroups.content.body instanceof HTMLElement
        ) {
            contentGroups.content.used = true;
            return contentGroups.content.body;
        }
        return fallbackPanel;
    }

    function resolveContentGroupByKey(contentGroups, fallbackPanel, key) {
        if (
            contentGroups &&
            typeof contentGroups === "object" &&
            contentGroups[key] &&
            contentGroups[key].body instanceof HTMLElement
        ) {
            contentGroups[key].used = true;
            return contentGroups[key].body;
        }
        return fallbackPanel;
    }

    function finalizeContentGroups(contentGroups) {
        if (!contentGroups || typeof contentGroups !== "object") {
            return;
        }
        Object.keys(contentGroups).forEach(function (key) {
            const entry = contentGroups[key];
            if (!entry || !(entry.root instanceof HTMLElement)) {
                return;
            }
            if (!entry.used || !(entry.body instanceof HTMLElement)) {
                entry.root.remove();
            }
        });
    }

    function buildStyleGroupsForType(type, stylePanel) {
        if (!(stylePanel instanceof HTMLElement)) {
            return null;
        }

        const groups = [
            { key: "presets", label: "Global Presets", expanded: true },
            { key: "typography", label: "Typography", expanded: true },
            { key: "colors", label: "Colors", expanded: false },
            { key: "backgrounds", label: "Backgrounds", expanded: false },
            { key: "borders", label: "Borders", expanded: false },
            { key: "layout", label: "Layout + Spacing", expanded: false },
            { key: "effects", label: "Effects", expanded: false },
        ];

        const map = {};
        groups.forEach(function (group) {
            const accordion = createStyleDropdownGroup(
                group.label,
                group.expanded
            );
            stylePanel.appendChild(accordion.root);
            map[group.key] = {
                key: group.key,
                root: accordion.root,
                body: accordion.body,
                used: false,
            };
        });
        return map;
    }

    function createStyleDropdownGroup(label, expanded) {
        const root = document.createElement("section");
        root.className = "h4bs-style-group";

        const toggle = document.createElement("button");
        toggle.type = "button";
        toggle.className = "h4bs-style-group-toggle";
        toggle.setAttribute("aria-expanded", expanded ? "true" : "false");
        root.appendChild(toggle);

        const title = document.createElement("span");
        title.className = "h4bs-style-group-title";
        title.textContent = String(label || "Group");
        toggle.appendChild(title);

        const caret = document.createElement("span");
        caret.className = "h4bs-style-group-caret";
        caret.textContent = expanded ? "v" : ">";
        toggle.appendChild(caret);

        const body = document.createElement("div");
        body.className = "h4bs-style-group-body";
        body.hidden = !expanded;
        root.appendChild(body);

        toggle.addEventListener("click", function () {
            const nextExpanded = body.hidden;
            body.hidden = !nextExpanded;
            toggle.setAttribute("aria-expanded", nextExpanded ? "true" : "false");
            caret.textContent = nextExpanded ? "v" : ">";
        });

        return { root: root, body: body };
    }

    function resolveStyleTarget(styleGroups, fallbackPanel, type, field) {
        if (!styleGroups || typeof styleGroups !== "object") {
            return fallbackPanel;
        }
        const key = styleGroupKeyForField(field);
        if (
            styleGroups[key] &&
            styleGroups[key].body instanceof HTMLElement
        ) {
            styleGroups[key].used = true;
            return styleGroups[key].body;
        }
        if (
            styleGroups.typography &&
            styleGroups.typography.body instanceof HTMLElement
        ) {
            styleGroups.typography.used = true;
            return styleGroups.typography.body;
        }
        const values = Object.values(styleGroups);
        for (let i = 0; i < values.length; i += 1) {
            if (values[i] && values[i].body instanceof HTMLElement) {
                values[i].used = true;
                return values[i].body;
            }
        }
        return fallbackPanel;
    }

    function finalizeStyleGroups(styleGroups) {
        if (!styleGroups || typeof styleGroups !== "object") {
            return;
        }
        Object.keys(styleGroups).forEach(function (key) {
            const entry = styleGroups[key];
            if (!entry || !(entry.root instanceof HTMLElement)) {
                return;
            }
            if (!entry.used || !(entry.body instanceof HTMLElement)) {
                entry.root.remove();
            }
        });
    }

    function styleGroupKeyForField(field) {
        const key = String(field && field.key ? field.key : "");
        const unitKey = String(field && field.unit_key ? field.unit_key : "");

        if (key === "design_style_preset") {
            return "presets";
        }

        if (
            key === "design_text_color" ||
            key === "design_text_color_global" ||
            key === "design_background_color" ||
            key === "design_background_color_global"
        ) {
            return "colors";
        }
        if (
            key.indexOf("design_background_") === 0 ||
            key.indexOf("design_overlay_") === 0
        ) {
            return "backgrounds";
        }
        if (
            key.indexOf("design_border_") === 0 ||
            key === "design_box_shadow"
        ) {
            return "borders";
        }
        if (
            key.indexOf("design_motion_") === 0 ||
            key === "design_opacity" ||
            key === "design_filter" ||
            key === "design_backdrop_filter" ||
            key === "design_transform" ||
            key === "design_transform_origin" ||
            key === "design_transition" ||
            key === "design_cursor"
        ) {
            return "effects";
        }
        if (
            key.indexOf("design_font_") === 0 ||
            key === "design_line_height" ||
            key === "design_line_height_unit" ||
            key === "design_letter_spacing" ||
            key === "design_letter_spacing_unit" ||
            key === "design_text_align" ||
            key === "design_text_transform" ||
            key === "design_text_shadow"
        ) {
            return "typography";
        }
        if (
            unitKey.indexOf("design_padding_") === 0 ||
            unitKey.indexOf("design_margin_") === 0
        ) {
            return "layout";
        }
        if (
            key === "design_width" ||
            key === "design_width_unit" ||
            key === "design_max_width" ||
            key === "design_max_width_unit" ||
            key === "design_min_height" ||
            key === "design_min_height_unit" ||
            key === "design_height" ||
            key === "design_height_unit" ||
            key === "design_max_height" ||
            key === "design_max_height_unit" ||
            key === "design_display" ||
            key === "design_position" ||
            key === "design_z_index" ||
            key === "design_overflow" ||
            key === "design_top" ||
            key === "design_top_unit" ||
            key === "design_right" ||
            key === "design_right_unit" ||
            key === "design_bottom" ||
            key === "design_bottom_unit" ||
            key === "design_left" ||
            key === "design_left_unit" ||
            key === "design_flex_direction" ||
            key === "design_justify_content" ||
            key === "design_align_items" ||
            key === "design_align_self"
        ) {
            return "layout";
        }
        return "typography";
    }

    function createModalTabs(tabItems) {
        if (typeof state.inspectorSettingFinderCleanup === "function") {
            state.inspectorSettingFinderCleanup();
            state.inspectorSettingFinderCleanup = null;
        }
        const rootNode = document.createElement("div");
        rootNode.className = "h4bs-inspector-tab-system";
        const finder = document.createElement("div");
        finder.className = "h4bs-setting-finder";
        const finderLabel = document.createElement("label");
        finderLabel.className = "h4bs-setting-finder-field";
        const finderLabelText = document.createElement("span");
        finderLabelText.className = "screen-reader-text";
        finderLabelText.textContent = "Find an inspector setting";
        const finderInput = document.createElement("input");
        finderInput.type = "search";
        finderInput.className = "h4bs-setting-finder-input";
        finderInput.placeholder = "Find a setting across every tab...";
        finderInput.autocomplete = "off";
        finderInput.setAttribute("aria-label", "Find a setting across every inspector tab");
        finderInput.setAttribute("aria-expanded", "false");
        finderLabel.appendChild(finderLabelText);
        finderLabel.appendChild(finderInput);
        finder.appendChild(finderLabel);
        const shortcut = document.createElement("kbd");
        shortcut.className = "h4bs-setting-finder-shortcut";
        shortcut.textContent = "/";
        shortcut.setAttribute("aria-hidden", "true");
        finder.appendChild(shortcut);
        const clearFinder = document.createElement("button");
        clearFinder.type = "button";
        clearFinder.className = "h4bs-setting-finder-clear";
        clearFinder.textContent = "\u00d7";
        clearFinder.title = "Clear setting search";
        clearFinder.setAttribute("aria-label", "Clear setting search");
        clearFinder.hidden = true;
        finder.appendChild(clearFinder);
        const finderResults = document.createElement("div");
        finderResults.className = "h4bs-setting-finder-results";
        finderResults.setAttribute("role", "listbox");
        finderResults.hidden = true;
        finder.appendChild(finderResults);
        const finderStatus = document.createElement("p");
        finderStatus.className = "h4bs-setting-finder-status screen-reader-text";
        finderStatus.setAttribute("aria-live", "polite");
        finder.appendChild(finderStatus);
        const tabsWrap = document.createElement("div");
        tabsWrap.className = "h4bs-inspector-tabs";
        const panelsWrap = document.createElement("div");
        panelsWrap.className = "h4bs-inspector-panels";
        rootNode.appendChild(finder);
        rootNode.appendChild(tabsWrap);
        rootNode.appendChild(panelsWrap);

        const panels = {};
        const buttons = {};
        const labels = {};
        let activeResultIndex = -1;
        let visibleResults = [];

        tabItems.forEach(function (item) {
            const key = String(item.key || "").trim();
            if (key === "") {
                return;
            }
            const button = document.createElement("button");
            button.type = "button";
            button.className = "button button-small";
            button.textContent = String(item.label || key);
            tabsWrap.appendChild(button);
            buttons[key] = button;
            labels[key] = String(item.label || key);

            const panel = document.createElement("section");
            panel.className = "h4bs-inspector-panel";
            panel.hidden = true;
            panelsWrap.appendChild(panel);
            panels[key] = panel;

            button.addEventListener("click", function () {
                activate(key);
            });
        });

        function activate(key) {
            if (state.modalMode === "block") {
                state.modalActiveTab = String(key || "content");
            } else if (state.modalMode === "page") {
                syncModalHelp(null, String(key || "layout"));
            }
            Object.keys(panels).forEach(function (name) {
                panels[name].hidden = name !== key;
                if (buttons[name]) {
                    buttons[name].classList.toggle("is-active", name === key);
                }
            });
        }

        function settingEntries() {
            const entries = [];
            Object.keys(panels).forEach(function (tabKey) {
                const panel = panels[tabKey];
                if (!(panel instanceof HTMLElement)) {
                    return;
                }
                panel.querySelectorAll(".h4bs-field").forEach(function (field) {
                    if (!(field instanceof HTMLElement)) {
                        return;
                    }
                    const directLabel = Array.from(field.children).find(function (child) {
                        return child instanceof HTMLLabelElement;
                    });
                    const label = String(
                        directLabel instanceof HTMLLabelElement
                            ? directLabel.textContent || ""
                            : field.getAttribute("data-h4bs-field-key") || "Setting"
                    ).trim();
                    if (label === "") {
                        return;
                    }
                    const group = field.closest(
                        ".h4bs-content-group, .h4bs-style-group"
                    );
                    const groupTitle = group instanceof HTMLElement
                        ? String(
                            (
                                group.querySelector(
                                    ".h4bs-content-group-title, .h4bs-style-group-title"
                                ) || {}
                            ).textContent || ""
                        ).trim()
                        : "";
                    const keyedControl = field.querySelector(
                        "[data-h4bs-setting-key]"
                    );
                    const key = String(
                        field.getAttribute("data-h4bs-field-key") ||
                        (keyedControl instanceof HTMLElement
                            ? keyedControl.getAttribute("data-h4bs-setting-key") || ""
                            : "")
                    );
                    entries.push({
                        field: field,
                        tabKey: tabKey,
                        tabLabel: labels[tabKey] || tabKey,
                        label: label,
                        group: groupTitle,
                        search: [
                            label,
                            key,
                            key.replace(/[_-]+/g, " "),
                            groupTitle,
                            labels[tabKey] || tabKey,
                        ]
                            .join(" ")
                            .toLowerCase(),
                    });
                });
            });
            return entries;
        }

        function expandSettingAncestors(field) {
            const group = field.closest(".h4bs-content-group, .h4bs-style-group");
            if (!(group instanceof HTMLElement)) {
                return;
            }
            const body = group.querySelector(
                ".h4bs-content-group-body, .h4bs-style-group-body"
            );
            const toggle = group.querySelector(
                ".h4bs-content-group-toggle, .h4bs-style-group-toggle"
            );
            const caret = group.querySelector(
                ".h4bs-content-group-caret, .h4bs-style-group-caret"
            );
            group.hidden = false;
            if (body instanceof HTMLElement) {
                body.hidden = false;
            }
            if (toggle instanceof HTMLElement) {
                toggle.setAttribute("aria-expanded", "true");
            }
            if (caret instanceof HTMLElement) {
                caret.textContent = "v";
            }
        }

        function dismissFinderResults(clearValue) {
            if (clearValue) {
                finderInput.value = "";
            }
            clearFinder.hidden = finderInput.value === "";
            finderResults.hidden = true;
            finderResults.innerHTML = "";
            finderInput.setAttribute("aria-expanded", "false");
            finderInput.removeAttribute("aria-activedescendant");
            activeResultIndex = -1;
            visibleResults = [];
        }

        function revealSetting(entry) {
            if (!entry || !(entry.field instanceof HTMLElement)) {
                return;
            }
            activate(entry.tabKey);
            entry.field.hidden = false;
            expandSettingAncestors(entry.field);
            dismissFinderResults(true);
            finderStatus.textContent =
                "Opened " + entry.label + " in " + entry.tabLabel + ".";
            window.requestAnimationFrame(function () {
                entry.field.scrollIntoView({ behavior: "smooth", block: "center" });
                entry.field.classList.add("is-setting-finder-target");
                const focusTarget = entry.field.querySelector(
                    "input:not([type='hidden']), select, textarea, button, [contenteditable='true']"
                );
                if (focusTarget instanceof HTMLElement) {
                    focusTarget.focus({ preventScroll: true });
                }
                window.setTimeout(function () {
                    entry.field.classList.remove("is-setting-finder-target");
                }, 1600);
            });
        }

        function selectFinderResult(nextIndex) {
            const resultButtons = Array.from(
                finderResults.querySelectorAll("[data-h4bs-setting-result]")
            );
            if (resultButtons.length < 1) {
                activeResultIndex = -1;
                finderInput.removeAttribute("aria-activedescendant");
                return;
            }
            activeResultIndex = Math.max(
                0,
                Math.min(resultButtons.length - 1, Number(nextIndex || 0))
            );
            resultButtons.forEach(function (button, index) {
                if (!(button instanceof HTMLElement)) {
                    return;
                }
                const active = index === activeResultIndex;
                button.classList.toggle("is-active", active);
                button.setAttribute("aria-selected", active ? "true" : "false");
                if (active) {
                    finderInput.setAttribute("aria-activedescendant", button.id);
                    button.scrollIntoView({ block: "nearest" });
                }
            });
        }

        function renderFinderResults() {
            const query = String(finderInput.value || "").trim().toLowerCase();
            clearFinder.hidden = query === "";
            finderResults.innerHTML = "";
            activeResultIndex = -1;
            if (query === "") {
                dismissFinderResults(false);
                finderStatus.textContent = "";
                return;
            }
            visibleResults = settingEntries()
                .filter(function (entry) {
                    return entry.search.indexOf(query) >= 0;
                })
                .slice(0, 12);
            if (visibleResults.length < 1) {
                const empty = document.createElement("p");
                empty.className = "h4bs-setting-finder-empty";
                empty.textContent = "No setting matches \u201c" + query + "\u201d.";
                finderResults.appendChild(empty);
            } else {
                visibleResults.forEach(function (entry, index) {
                    const result = document.createElement("button");
                    result.type = "button";
                    result.className = "h4bs-setting-finder-result";
                    result.id = "h4bs-setting-result-" + String(index) + "-" + String(Date.now());
                    result.setAttribute("role", "option");
                    result.setAttribute("aria-selected", "false");
                    result.setAttribute("data-h4bs-setting-result", String(index));
                    const resultLabel = document.createElement("strong");
                    resultLabel.textContent = entry.label;
                    const location = document.createElement("span");
                    location.textContent = [entry.tabLabel, entry.group]
                        .filter(Boolean)
                        .join(" / ");
                    result.appendChild(resultLabel);
                    result.appendChild(location);
                    result.addEventListener("click", function () {
                        revealSetting(entry);
                    });
                    finderResults.appendChild(result);
                });
            }
            finderResults.hidden = false;
            finderInput.setAttribute("aria-expanded", "true");
            finderStatus.textContent =
                visibleResults.length === 1
                    ? "1 setting found."
                    : String(visibleResults.length) + " settings found.";
        }

        finderInput.addEventListener("input", renderFinderResults);
        finderInput.addEventListener("keydown", function (event) {
            if (event.key === "ArrowDown" || event.key === "ArrowUp") {
                event.preventDefault();
                const direction = event.key === "ArrowDown" ? 1 : -1;
                const start = activeResultIndex < 0
                    ? direction > 0 ? 0 : visibleResults.length - 1
                    : activeResultIndex + direction;
                selectFinderResult(start);
                return;
            }
            if (event.key === "Enter" && activeResultIndex >= 0) {
                event.preventDefault();
                revealSetting(visibleResults[activeResultIndex]);
                return;
            }
            if (event.key === "Escape" && !finderResults.hidden) {
                event.preventDefault();
                dismissFinderResults(true);
            }
        });
        clearFinder.addEventListener("click", function () {
            dismissFinderResults(true);
            finderInput.focus();
        });

        const shortcutHandler = function (event) {
            if (
                event.key !== "/" ||
                !rootNode.isConnected ||
                !state.modalMode ||
                event.metaKey ||
                event.ctrlKey ||
                event.altKey
            ) {
                return;
            }
            const active = document.activeElement;
            if (
                active instanceof HTMLInputElement ||
                active instanceof HTMLTextAreaElement ||
                active instanceof HTMLSelectElement ||
                (active instanceof HTMLElement && active.isContentEditable)
            ) {
                return;
            }
            event.preventDefault();
            finderInput.focus();
        };
        document.addEventListener("keydown", shortcutHandler);
        state.inspectorSettingFinderCleanup = function () {
            document.removeEventListener("keydown", shortcutHandler);
        };

        return {
            root: rootNode,
            panels: panels,
            activate: activate,
        };
    }

    function renderBlockSpecActions(modalBlock) {
        const wrap = document.createElement("div");
        wrap.className = "h4bs-spec-actions";

        const copyBtn = document.createElement("button");
        copyBtn.type = "button";
        copyBtn.className = "button";
        copyBtn.textContent = "Copy Element Spec";
        copyBtn.addEventListener("click", function () {
            copyElementSpec(modalBlock);
        });
        wrap.appendChild(copyBtn);

        const pasteBtn = document.createElement("button");
        pasteBtn.type = "button";
        pasteBtn.className = "button";
        pasteBtn.textContent = "Paste Element Spec";
        pasteBtn.addEventListener("click", function () {
            pasteElementSpec(modalBlock);
        });
        wrap.appendChild(pasteBtn);

        const help = document.createElement("p");
        help.className = "h4bs-inspector-empty";
        help.textContent =
            "Copy this element as a reusable spec string, then paste into any page.";
        wrap.appendChild(help);

        return wrap;
    }

    function copyElementSpec(modalBlock) {
        const payload = {
            version: "1.0",
            type: String(modalBlock.type || "text"),
            settings:
                modalBlock.settings && typeof modalBlock.settings === "object"
                    ? deepClone(modalBlock.settings)
                    : {},
            visibility:
                modalBlock.visibility && typeof modalBlock.visibility === "object"
                    ? deepClone(modalBlock.visibility)
                    : {},
            parent_id: String(modalBlock.parent_id || ""),
            slot: Math.max(0, Number(modalBlock.slot || 0) || 0),
        };
        const spec = encodeSpecPayload(BLOCK_SPEC_PREFIX, payload);
        if (spec === "") {
            window.alert("Unable to build element spec.");
            return;
        }
        copyTextToClipboard(spec).then(function (ok) {
            if (ok) {
                updateDirtyText("Element spec copied to clipboard.");
                return;
            }
            window.prompt("Copy Element Spec", spec);
        });
    }

    function pasteElementSpec(modalBlock) {
        readTextFromClipboard().then(function (rawText) {
            let source = String(rawText || "").trim();
            if (source === "") {
                const manual = window.prompt("Paste Element Spec", "");
                source = String(manual || "").trim();
            }
            if (source === "") {
                return;
            }
            const parsed = decodeSpecPayload(BLOCK_SPEC_PREFIX, source);
            if (!parsed || typeof parsed !== "object") {
                window.alert("Element spec could not be parsed.");
                return;
            }
            const parsedType = String(parsed.type || "");
            if (parsedType !== "" && parsedType !== String(modalBlock.type || "")) {
                window.alert(
                    "Element type mismatch. This block stays a " +
                        String(modalBlock.type || "block") +
                        "."
                );
            }
            modalBlock.settings = {
                ...(modalBlock.settings && typeof modalBlock.settings === "object"
                    ? modalBlock.settings
                    : {}),
                ...(parsed.settings && typeof parsed.settings === "object"
                    ? parsed.settings
                    : {}),
            };
            modalBlock.visibility = {
                ...(modalBlock.visibility &&
                typeof modalBlock.visibility === "object"
                    ? modalBlock.visibility
                    : {}),
                ...(parsed.visibility && typeof parsed.visibility === "object"
                    ? parsed.visibility
                    : {}),
            };
            if (Object.prototype.hasOwnProperty.call(parsed, "parent_id")) {
                modalBlock.parent_id = String(parsed.parent_id || "");
            }
            if (Object.prototype.hasOwnProperty.call(parsed, "slot")) {
                modalBlock.slot = normalizedSlot(parsed.slot || 0);
            }
            markModalDirty(true);
            renderModalForBlock(modalBlock);
            requestModalPreviewRender();
        });
    }

    function renderPageSettingsModal() {
        if (!els.modalBody) {
            return;
        }
        if (!state.modalDraftPage || typeof state.modalDraftPage !== "object") {
            state.modalDraftPage = {
                pageLayout: String(state.pageLayout || "default"),
                pageTitleMode: normalizePageTitleMode(state.pageTitleMode),
                pageCss: String(state.pageCss || ""),
                templateConditions: deepClone(state.templateConditions || {}),
                globalDesignTokens: deepClone(state.globalDesignTokens || {}),
            };
        }

        const draft = state.modalDraftPage;
        if (
            !draft.templateConditions ||
            typeof draft.templateConditions !== "object"
        ) {
            draft.templateConditions = deepClone(state.templateConditions || {});
        }
        draft.pageLayout = normalizePageLayout(draft.pageLayout);
        draft.pageTitleMode = normalizePageTitleMode(draft.pageTitleMode);
        draft.globalDesignTokens = normalizeGlobalDesignTokens(
            draft.globalDesignTokens || {}
        );

        els.modalBody.innerHTML = "";
        const tabDefs = [
            { key: "layout", label: "Layout" },
            { key: "globals", label: "Globals" },
            { key: "history", label: "History" },
        ];
        if (state.isTemplate) {
            tabDefs.push({ key: "template", label: "Template" });
        }
        tabDefs.push({ key: "code", label: "Code" });
        const tabs = createModalTabs(tabDefs);
        els.modalBody.appendChild(tabs.root);

        tabs.panels.layout.appendChild(
            createField(
                {
                    label: "Page Layout Mode",
                    type: "select",
                    options: pageLayoutOptions(),
                },
                String(draft.pageLayout || "default"),
                function (value) {
                    draft.pageLayout = normalizePageLayout(value);
                    markModalDirty(true);
                }
            )
        );
        const layoutHelp = document.createElement("p");
        layoutHelp.className = "h4bs-inspector-empty";
        layoutHelp.textContent =
            "Theme Default keeps normal header/footer. Full Width expands content area. Canvas removes header/footer for pure landing pages.";
        tabs.panels.layout.appendChild(layoutHelp);
        tabs.panels.layout.appendChild(
            createField(
                {
                    label: "Page title",
                    type: "select",
                    options: pageTitleModeOptions(),
                },
                draft.pageTitleMode,
                function (value) {
                    draft.pageTitleMode = normalizePageTitleMode(value);
                    markModalDirty(true);
                }
            )
        );
        const titleHelp = document.createElement("p");
        titleHelp.className = "h4bs-inspector-empty";
        titleHelp.textContent =
            "Automatic prevents a duplicate title when this full-width design already contains its main H1. Show or Hide overrides that decision in both Studio and the public theme.";
        tabs.panels.layout.appendChild(titleHelp);
        renderLayoutRecoveryPanel(tabs.panels.history);

        tabs.panels.code.appendChild(
            createField(
                { label: "Page / Template Custom CSS", type: "textarea", rows: 14 },
                String(draft.pageCss || ""),
                function (value) {
                    draft.pageCss = String(value || "");
                    markModalDirty(true);
                }
            )
        );
        const cssHelp = document.createElement("p");
        cssHelp.className = "h4bs-inspector-empty";
        cssHelp.textContent =
            "Use :builder as this page/template root. Supports media queries, pseudo-elements, keyframes, and prefers-reduced-motion.";
        tabs.panels.code.appendChild(cssHelp);

        const appendGlobalHeading = function (label) {
            const heading = document.createElement("h4");
            heading.className = "h4bs-field-group-heading";
            heading.textContent = String(label || "Global Settings");
            tabs.panels.globals.appendChild(heading);
        };

        appendGlobalHeading("Semantic Color System");
        const colorKeys = [
            "primary",
            "primary_hover",
            "on_primary",
            "secondary",
            "secondary_hover",
            "on_secondary",
            "accent",
            "heading",
            "text",
            "muted",
            "link",
            "link_hover",
            "surface",
            "surface_alt",
            "border",
            "success",
            "warning",
            "danger",
            "info",
        ];
        colorKeys.forEach(function (key) {
            tabs.panels.globals.appendChild(
                createField(
                    {
                        label: "Global Color: " + labelizeTokenKey(key),
                        type: "color",
                        default: defaultGlobalDesignTokens().colors[key],
                    },
                    String(draft.globalDesignTokens.colors[key] || ""),
                    function (value) {
                        draft.globalDesignTokens.colors[key] = String(value || "");
                        markModalDirty(true);
                    }
                )
            );
        });
        const palettePreview = document.createElement("div");
        palettePreview.className = "h4bs-global-palette-preview";
        ["primary", "secondary", "accent", "surface", "surface_alt", "text"].forEach(
            function (key) {
                const swatch = document.createElement("span");
                swatch.style.backgroundColor = String(
                    draft.globalDesignTokens.colors[key] || "#ffffff"
                );
                swatch.title = labelizeTokenKey(key);
                swatch.setAttribute("aria-label", labelizeTokenKey(key));
                palettePreview.appendChild(swatch);
            }
        );
        tabs.panels.globals.appendChild(palettePreview);

        appendGlobalHeading("Typography Families + Scale");
        ["display", "heading", "body", "ui"].forEach(function (key) {
            tabs.panels.globals.appendChild(
                createField(
                    {
                        label: "Global Font: " + labelizeTokenKey(key),
                        type: "select",
                        options: fontFamilyCatalog(),
                    },
                    String(draft.globalDesignTokens.fonts[key] || ""),
                    function (value) {
                        draft.globalDesignTokens.fonts[key] = String(value || "");
                        markModalDirty(true);
                    }
                )
            );
        });
        tabs.panels.globals.appendChild(
            createField(
                { label: "Global Base Font Size (px)", type: "number" },
                String(draft.globalDesignTokens.fonts.base_size || "16"),
                function (value) {
                    draft.globalDesignTokens.fonts.base_size = String(value || "16");
                    markModalDirty(true);
                }
            )
        );

        const typographyLabels = {
            h1_size: "H1 Size (px)",
            h2_size: "H2 Size (px)",
            h3_size: "H3 Size (px)",
            h4_size: "H4 Size (px)",
            h5_size: "H5 Size (px)",
            h6_size: "H6 Size (px)",
            heading_weight: "Heading Weight",
            body_weight: "Body Weight",
            heading_line_height: "Heading Line Height",
            body_line_height: "Body Line Height",
        };
        Object.keys(typographyLabels).forEach(function (key) {
            tabs.panels.globals.appendChild(
                createField(
                    { label: typographyLabels[key], type: "number" },
                    String(draft.globalDesignTokens.typography[key] || ""),
                    function (value) {
                        draft.globalDesignTokens.typography[key] = String(value || "");
                        markModalDirty(true);
                    }
                )
            );
        });

        appendGlobalHeading("Spacing + Shape");
        const numericTokenGroups = [
            {
                key: "spacing",
                labels: {
                    page_gap: "Page Element Gap (px)",
                    section_x: "Default Section Side Padding (px)",
                    section_y: "Default Section Vertical Padding (px)",
                    card_gap: "Card Grid Gap (px)",
                },
            },
            {
                key: "shape",
                labels: {
                    radius_sm: "Small Radius (px)",
                    radius_md: "Medium Radius (px)",
                    radius_lg: "Large Radius (px)",
                },
            },
            {
                key: "components",
                labels: {
                    button_padding_x: "Button Horizontal Padding (px)",
                    button_padding_y: "Button Vertical Padding (px)",
                    button_radius: "Button Radius (px)",
                    button_weight: "Button Font Weight",
                    card_padding: "Card Padding (px)",
                    field_height: "Form Field Height (px)",
                    field_padding_x: "Form Field Horizontal Padding (px)",
                    field_radius: "Form Field Radius (px)",
                },
            },
        ];
        numericTokenGroups.forEach(function (group) {
            Object.keys(group.labels).forEach(function (key) {
                tabs.panels.globals.appendChild(
                    createField(
                        { label: group.labels[key], type: "number" },
                        String(draft.globalDesignTokens[group.key][key] || ""),
                        function (value) {
                            draft.globalDesignTokens[group.key][key] = String(value || "");
                            markModalDirty(true);
                        }
                    )
                );
            });
        });
        ["shadow_sm", "shadow_md"].forEach(function (key) {
            tabs.panels.globals.appendChild(
                createField(
                    { label: labelizeTokenKey(key) + " (CSS)", type: "text" },
                    String(draft.globalDesignTokens.shape[key] || ""),
                    function (value) {
                        draft.globalDesignTokens.shape[key] = String(value || "");
                        markModalDirty(true);
                    }
                )
            );
        });

        appendGlobalHeading("Layout System");
        tabs.panels.globals.appendChild(
            createSizeField(
                {
                    label: "Global Container Max Width",
                    unit_key: "container_max_width_unit",
                    unit_default: "px",
                    units: ["px", "%", "vw", "vh", "rem", "em"],
                },
                String(
                    draft.globalDesignTokens.layout &&
                        draft.globalDesignTokens.layout.container_max_width
                        ? draft.globalDesignTokens.layout.container_max_width
                        : "1200"
                ),
                String(
                    draft.globalDesignTokens.layout &&
                        draft.globalDesignTokens.layout.container_max_width_unit
                        ? draft.globalDesignTokens.layout.container_max_width_unit
                        : "px"
                ),
                function (value, unitValue) {
                    if (
                        !draft.globalDesignTokens.layout ||
                        typeof draft.globalDesignTokens.layout !== "object"
                    ) {
                        draft.globalDesignTokens.layout = {};
                    }
                    draft.globalDesignTokens.layout.container_max_width = String(
                        value || "1200"
                    );
                    draft.globalDesignTokens.layout.container_max_width_unit =
                        String(unitValue || "px");
                    markModalDirty(true);
                }
            )
        );
        const containerWidthHelp = document.createElement("p");
        containerWidthHelp.className = "h4bs-inspector-empty";
        containerWidthHelp.textContent =
            "Sections and containers inherit this width by default. Set a section to Custom or Full to override.";
        tabs.panels.globals.appendChild(containerWidthHelp);

        const structureDefaults = structureLayoutDefaults();
        const structureHeading = document.createElement("h4");
        structureHeading.className = "h4bs-field-group-heading";
        structureHeading.textContent = "Global Section/Container Defaults";
        tabs.panels.globals.appendChild(structureHeading);

        tabs.panels.globals.appendChild(
            createField(
                { label: "Default Columns", type: "number" },
                String(structureDefaults.columns),
                function (value) {
                    if (
                        !draft.globalDesignTokens.layout ||
                        typeof draft.globalDesignTokens.layout !== "object"
                    ) {
                        draft.globalDesignTokens.layout = {};
                    }
                    draft.globalDesignTokens.layout.structure_columns = String(value || "2");
                    markModalDirty(true);
                }
            )
        );
        tabs.panels.globals.appendChild(
            createField(
                { label: "Default Column Gap (px)", type: "number" },
                String(structureDefaults.gap),
                function (value) {
                    if (
                        !draft.globalDesignTokens.layout ||
                        typeof draft.globalDesignTokens.layout !== "object"
                    ) {
                        draft.globalDesignTokens.layout = {};
                    }
                    draft.globalDesignTokens.layout.structure_gap = String(value || "18");
                    markModalDirty(true);
                }
            )
        );
        tabs.panels.globals.appendChild(
            createField(
                { label: "Default Min Height (px)", type: "number" },
                String(structureDefaults.min_height),
                function (value) {
                    if (
                        !draft.globalDesignTokens.layout ||
                        typeof draft.globalDesignTokens.layout !== "object"
                    ) {
                        draft.globalDesignTokens.layout = {};
                    }
                    draft.globalDesignTokens.layout.structure_min_height = String(
                        value || "140"
                    );
                    markModalDirty(true);
                }
            )
        );
        tabs.panels.globals.appendChild(
            createField(
                {
                    label: "Default Layout Mode",
                    type: "select",
                    options: [
                        { value: "grid", label: "Grid (columns)" },
                        { value: "flex", label: "Flex (free flow)" },
                    ],
                },
                String(structureDefaults.layout_mode),
                function (value) {
                    if (
                        !draft.globalDesignTokens.layout ||
                        typeof draft.globalDesignTokens.layout !== "object"
                    ) {
                        draft.globalDesignTokens.layout = {};
                    }
                    draft.globalDesignTokens.layout.structure_layout_mode = String(
                        value || "grid"
                    );
                    markModalDirty(true);
                }
            )
        );
        tabs.panels.globals.appendChild(
            createField(
                {
                    label: "Default Container Width Mode",
                    type: "select",
                    options: [
                        { value: "inherit", label: "Use global container width" },
                        { value: "custom", label: "Use custom per section/container" },
                        { value: "full", label: "Full width (100%)" },
                    ],
                },
                String(structureDefaults.content_width_mode),
                function (value) {
                    if (
                        !draft.globalDesignTokens.layout ||
                        typeof draft.globalDesignTokens.layout !== "object"
                    ) {
                        draft.globalDesignTokens.layout = {};
                    }
                    draft.globalDesignTokens.layout.structure_content_width_mode = String(
                        value || "inherit"
                    );
                    markModalDirty(true);
                }
            )
        );
        tabs.panels.globals.appendChild(
            createField(
                {
                    label: "Default Flex Direction",
                    type: "select",
                    options: ["row", "row-reverse", "column", "column-reverse"],
                },
                String(structureDefaults.flex_direction),
                function (value) {
                    if (
                        !draft.globalDesignTokens.layout ||
                        typeof draft.globalDesignTokens.layout !== "object"
                    ) {
                        draft.globalDesignTokens.layout = {};
                    }
                    draft.globalDesignTokens.layout.structure_flex_direction = String(
                        value || "row"
                    );
                    markModalDirty(true);
                }
            )
        );
        tabs.panels.globals.appendChild(
            createField(
                {
                    label: "Default Flex Wrap",
                    type: "select",
                    options: ["nowrap", "wrap", "wrap-reverse"],
                },
                String(structureDefaults.flex_wrap),
                function (value) {
                    if (
                        !draft.globalDesignTokens.layout ||
                        typeof draft.globalDesignTokens.layout !== "object"
                    ) {
                        draft.globalDesignTokens.layout = {};
                    }
                    draft.globalDesignTokens.layout.structure_flex_wrap = String(
                        value || "wrap"
                    );
                    markModalDirty(true);
                }
            )
        );
        tabs.panels.globals.appendChild(
            createField(
                {
                    label: "Default Justify Content",
                    type: "select",
                    options: [
                        "flex-start",
                        "center",
                        "flex-end",
                        "space-between",
                        "space-around",
                        "space-evenly",
                    ],
                },
                String(structureDefaults.justify_content),
                function (value) {
                    if (
                        !draft.globalDesignTokens.layout ||
                        typeof draft.globalDesignTokens.layout !== "object"
                    ) {
                        draft.globalDesignTokens.layout = {};
                    }
                    draft.globalDesignTokens.layout.structure_justify_content = String(
                        value || "flex-start"
                    );
                    markModalDirty(true);
                }
            )
        );
        tabs.panels.globals.appendChild(
            createField(
                {
                    label: "Default Align Items",
                    type: "select",
                    options: ["stretch", "flex-start", "center", "flex-end", "baseline"],
                },
                String(structureDefaults.align_items),
                function (value) {
                    if (
                        !draft.globalDesignTokens.layout ||
                        typeof draft.globalDesignTokens.layout !== "object"
                    ) {
                        draft.globalDesignTokens.layout = {};
                    }
                    draft.globalDesignTokens.layout.structure_align_items = String(
                        value || "stretch"
                    );
                    markModalDirty(true);
                }
            )
        );
        tabs.panels.globals.appendChild(
            createField(
                {
                    label: "Default Align Content",
                    type: "select",
                    options: [
                        "stretch",
                        "flex-start",
                        "center",
                        "flex-end",
                        "space-between",
                        "space-around",
                        "space-evenly",
                    ],
                },
                String(structureDefaults.align_content),
                function (value) {
                    if (
                        !draft.globalDesignTokens.layout ||
                        typeof draft.globalDesignTokens.layout !== "object"
                    ) {
                        draft.globalDesignTokens.layout = {};
                    }
                    draft.globalDesignTokens.layout.structure_align_content = String(
                        value || "stretch"
                    );
                    markModalDirty(true);
                }
            )
        );
        const structureHelp = document.createElement("p");
        structureHelp.className = "h4bs-inspector-empty";
        structureHelp.textContent =
            "These defaults apply to new Section/Container/Inner Section blocks and as fallback for legacy blocks with missing layout values.";
        tabs.panels.globals.appendChild(structureHelp);

        if (state.isTemplate && tabs.panels.template) {
            const intro = document.createElement("p");
            intro.className = "h4bs-inspector-empty";
            intro.textContent =
                "Template display conditions: control where this header/footer/popup appears across the site.";
            tabs.panels.template.appendChild(intro);

            tabs.panels.template.appendChild(
                createField(
                    {
                        label: "Template Role",
                        type: "select",
                        options: data.templateRoles || {},
                    },
                    String(draft.templateConditions.role || "general"),
                    function (value) {
                        draft.templateConditions.role = value;
                        markModalDirty(true);
                    }
                )
            );

            tabs.panels.template.appendChild(
                createField(
                    {
                        label: "Display Scope",
                        type: "select",
                        options: data.templateScopes || {},
                    },
                    String(draft.templateConditions.scope || "entire_site"),
                    function (value) {
                        draft.templateConditions.scope = value;
                        markModalDirty(true);
                    }
                )
            );
            tabs.panels.template.appendChild(
                createField(
                    { label: "Include IDs (comma separated)", type: "text" },
                    String(draft.templateConditions.include_ids || ""),
                    function (value) {
                        draft.templateConditions.include_ids = value;
                        markModalDirty(true);
                    }
                )
            );
            tabs.panels.template.appendChild(
                createField(
                    { label: "Exclude IDs (comma separated)", type: "text" },
                    String(draft.templateConditions.exclude_ids || ""),
                    function (value) {
                        draft.templateConditions.exclude_ids = value;
                        markModalDirty(true);
                    }
                )
            );
            tabs.panels.template.appendChild(
                createField(
                    { label: "Include Post Types (optional)", type: "text" },
                    String(draft.templateConditions.include_types || ""),
                    function (value) {
                        draft.templateConditions.include_types = value;
                        markModalDirty(true);
                    }
                )
            );
            tabs.panels.template.appendChild(
                createField(
                    { label: "Exclude Post Types (optional)", type: "text" },
                    String(draft.templateConditions.exclude_types || ""),
                    function (value) {
                        draft.templateConditions.exclude_types = value;
                        markModalDirty(true);
                    }
                )
            );
            tabs.panels.template.appendChild(
                createField(
                    {
                        label: "Audience Roles (guest,logged_in,subscriber...)",
                        type: "text",
                    },
                    String(draft.templateConditions.user_roles || ""),
                    function (value) {
                        draft.templateConditions.user_roles = value;
                        markModalDirty(true);
                    }
                )
            );
            tabs.panels.template.appendChild(
                createField(
                    { label: "Priority", type: "number" },
                    String(draft.templateConditions.priority || "10"),
                    function (value) {
                        draft.templateConditions.priority = value;
                        markModalDirty(true);
                    }
                )
            );
        }

        tabs.panels.code.appendChild(renderPageSpecActions());
        tabs.activate("layout");
    }

    function renderLayoutRecoveryPanel(panel) {
        if (!(panel instanceof HTMLElement)) {
            return;
        }
        panel.innerHTML = "";
        const heading = document.createElement("h4");
        heading.className = "h4bs-field-group-heading";
        heading.textContent = "Page recovery points";
        panel.appendChild(heading);

        const help = document.createElement("p");
        help.className = "h4bs-inspector-empty";
        help.textContent =
            "Builder keeps the five most recent page layouts from before a changed layout was published. Loading one creates an unsaved draft for review; it does not change the public page until you publish.";
        panel.appendChild(help);

        const status = document.createElement("p");
        status.className = "h4bs-inspector-empty";
        status.textContent = "Loading page history...";
        panel.appendChild(status);

        $.post(data.ajaxUrl, {
            action: "h4bs_builder_layout_recovery",
            nonce: data.nonce,
            post_id: data.postId,
        })
            .done(function (response) {
                if (!response || !response.success) {
                    status.textContent = "Page history could not be loaded.";
                    return;
                }
                const entries = Array.isArray(response.data && response.data.entries)
                    ? response.data.entries
                    : [];
                status.textContent = entries.length
                    ? String(entries.length) + " recovery point" + (entries.length === 1 ? "" : "s")
                    : "No recovery points yet. A recovery point is created before the next changed layout is published.";
                entries.forEach(function (entry, index) {
                    const card = document.createElement("section");
                    card.className = "h4bs-content-group h4bs-layout-recovery-card";

                    const title = document.createElement("strong");
                    const createdAt = String(entry.created_at || "Unknown time");
                    title.textContent = createdAt + " - " + String(entry.element_count || 0) + " elements";
                    card.appendChild(title);

                    const meta = document.createElement("p");
                    meta.className = "h4bs-inspector-empty";
                    meta.textContent =
                        "Saved before a change by " +
                        String(entry.user_name || "Unknown editor") +
                        " | " +
                        String(entry.hash || "").slice(0, 12);
                    card.appendChild(meta);

                    const load = document.createElement("button");
                    load.type = "button";
                    load.className = "button";
                    load.textContent = "Load as draft";
                    load.addEventListener("click", function () {
                        const layout = normalizeLayout(entry.layout || []);
                        if (!layout.length) {
                            window.alert("This recovery point has no usable elements.");
                            return;
                        }
                        if (
                            state.pageDirty &&
                            !window.confirm("Replace your current unsaved page edits with this recovery point?")
                        ) {
                            return;
                        }
                        captureHistoryBeforeMutation();
                        state.layout = layout;
                        state.selectedId = layout[0] ? String(layout[0].id || "") : null;
                        setDirty(true);
                        closeBuilderModal(true);
                        renderAll();
                        updateDirtyText(
                            "Recovery point " +
                            String(index + 1) +
                            " loaded as an unsaved draft. Review it, then publish to make it live."
                        );
                    });
                    card.appendChild(load);
                    panel.appendChild(card);
                });
            })
            .fail(function () {
                status.textContent = "Page history could not be loaded.";
            });
    }

    function renderPageSpecActions() {
        const wrap = document.createElement("div");
        wrap.className = "h4bs-spec-actions";

        const copyBtn = document.createElement("button");
        copyBtn.type = "button";
        copyBtn.className = "button";
        copyBtn.textContent = "Copy Page Spec";
        copyBtn.addEventListener("click", function () {
            copyPageSpec();
        });
        wrap.appendChild(copyBtn);

        const pasteBtn = document.createElement("button");
        pasteBtn.type = "button";
        pasteBtn.className = "button";
        pasteBtn.textContent = "Paste Page Spec";
        pasteBtn.addEventListener("click", function () {
            pastePageSpec();
        });
        wrap.appendChild(pasteBtn);

        const help = document.createElement("p");
        help.className = "h4bs-inspector-empty";
        help.textContent =
            "Use this WoW-style spec string to move whole pages/templates across installs.";
        wrap.appendChild(help);

        return wrap;
    }

    function currentPageSpecPayload() {
        const draftPage =
            state.modalMode === "page" &&
            state.modalDraftPage &&
            typeof state.modalDraftPage === "object"
                ? state.modalDraftPage
                : null;
        return {
            version: "1.0",
            post_type: String(data.postType || ""),
            page_layout: String(
                draftPage ? draftPage.pageLayout || state.pageLayout : state.pageLayout
            ),
            template_conditions: deepClone(
                draftPage
                    ? draftPage.templateConditions || state.templateConditions
                    : state.templateConditions
            ),
            global_design_tokens: deepClone(
                draftPage && draftPage.globalDesignTokens
                    ? draftPage.globalDesignTokens
                    : state.globalDesignTokens
            ),
            layout: deepClone(state.layout || []),
        };
    }

    function copyPageSpec() {
        const spec = encodeSpecPayload(PAGE_SPEC_PREFIX, currentPageSpecPayload());
        if (spec === "") {
            window.alert("Unable to build page spec.");
            return;
        }
        copyTextToClipboard(spec).then(function (ok) {
            if (ok) {
                updateDirtyText("Page spec copied to clipboard.");
                return;
            }
            window.prompt("Copy Page Spec", spec);
        });
    }

    function pastePageSpec() {
        readTextFromClipboard().then(function (rawText) {
            let source = String(rawText || "").trim();
            if (source === "") {
                source = String(window.prompt("Paste Page Spec", "") || "").trim();
            }
            if (source === "") {
                return;
            }
            const parsed = decodeSpecPayload(PAGE_SPEC_PREFIX, source);
            if (!parsed || typeof parsed !== "object") {
                window.alert("Page spec could not be parsed.");
                return;
            }
            const nextLayout = normalizeLayout(parsed.layout || []);
            if (nextLayout.length < 1) {
                window.alert("Page spec has no layout blocks.");
                return;
            }
            captureHistoryBeforeMutation();
            state.layout = nextLayout;
            state.pageLayout = normalizePageLayout(
                String(parsed.page_layout || state.pageLayout)
            );
            state.globalDesignTokens = normalizeGlobalDesignTokens(
                parsed.global_design_tokens || state.globalDesignTokens
            );
            state.globalDesignDirty = true;
            state.templateConditions = normalizeTemplateConditions(
                parsed.template_conditions || state.templateConditions
            );
            state.selectedId = String(
                state.layout[0] && state.layout[0].id ? state.layout[0].id : ""
            );
            if (
                state.modalMode === "page" &&
                state.modalDraftPage &&
                typeof state.modalDraftPage === "object"
            ) {
                state.modalDraftPage.pageLayout = state.pageLayout;
                state.modalDraftPage.globalDesignTokens = deepClone(
                    state.globalDesignTokens
                );
                state.modalDraftPage.templateConditions = deepClone(
                    state.templateConditions
                );
                renderPageSettingsModal();
            }
            setDirty(true);
            renderAll();
            updateDirtyText("Page spec pasted. Save layout to publish it.");
        });
    }

    function renderVisibilityEditor(block) {
        const wrapper = document.createElement("section");
        wrapper.className = "h4bs-visibility-editor";

        const title = document.createElement("h4");
        title.textContent = "Display Rules";
        wrapper.appendChild(title);

        if (!block.visibility || typeof block.visibility !== "object") {
            block.visibility = {
                scope: "all",
                include_ids: "",
                exclude_ids: "",
                user_roles: "",
                viewport: "all",
            };
        }

        wrapper.appendChild(
            createField(
                {
                    label: "Viewport Visibility",
                    type: "select",
                    options: viewportVisibilityOptions(),
                },
                String(block.visibility.viewport || "all"),
                function (value) {
                    block.visibility.viewport = value;
                    markModalDirty(true);
                    requestModalPreviewRender();
                }
            )
        );

        if (!state.isTemplate) {
            const help = document.createElement("p");
            help.className = "h4bs-inspector-empty";
            help.textContent =
                "Element visibility is device-first. Template-wide assignments are handled in template display conditions.";
            wrapper.appendChild(help);
            return wrapper;
        }

        wrapper.appendChild(
            createField(
                {
                    label: "Scope",
                    type: "select",
                    options: [
                        "all",
                        "front_page",
                        "home",
                        "singular",
                        "archive",
                        "search",
                        "404",
                        "product_archive",
                        "product_single",
                    ],
                },
                String(block.visibility.scope || "all"),
                function (value) {
                    block.visibility.scope = value;
                    markModalDirty(true);
                    requestModalPreviewRender();
                }
            )
        );

        wrapper.appendChild(
            createField(
                { label: "Include IDs (optional)", type: "text" },
                String(block.visibility.include_ids || ""),
                function (value) {
                    block.visibility.include_ids = value;
                    markModalDirty(true);
                    requestModalPreviewRender();
                }
            )
        );

        wrapper.appendChild(
            createField(
                { label: "Exclude IDs (optional)", type: "text" },
                String(block.visibility.exclude_ids || ""),
                function (value) {
                    block.visibility.exclude_ids = value;
                    markModalDirty(true);
                    requestModalPreviewRender();
                }
            )
        );

        wrapper.appendChild(
            createField(
                { label: "User Roles (comma separated)", type: "text" },
                String(block.visibility.user_roles || ""),
                function (value) {
                    block.visibility.user_roles = value;
                    markModalDirty(true);
                    requestModalPreviewRender();
                }
            )
        );

        return wrapper;
    }

    function blockWithDraft(block) {
        if (
            state.modalMode === "block" &&
            state.modalDraftBlock &&
            String(state.modalDraftBlock.id || "") === String(block && block.id ? block.id : "")
        ) {
            return state.modalDraftBlock;
        }
        return block;
    }

    function topLevelBlocks() {
        const containerIds = new Set();
        state.layout.forEach(function (block) {
            if (
                block &&
                typeof block === "object" &&
                isContainerType(block.type)
            ) {
                containerIds.add(String(block.id || ""));
            }
        });
        return state.layout.filter(function (block) {
            const parentId = String(block && block.parent_id ? block.parent_id : "");
            return parentId === "" || !containerIds.has(parentId);
        });
    }

    function childrenForSection(sectionId, slot) {
        const parentId = String(sectionId || "");
        const targetSlot = Math.max(0, Number(slot || 0) || 0);
        return state.layout.filter(function (block) {
            return (
                String(block && block.parent_id ? block.parent_id : "") === parentId &&
                Math.max(0, Number(block && block.slot ? block.slot : 0) || 0) === targetSlot
            );
        });
    }

    function viewportRuleForBlock(block) {
        if (!block || typeof block !== "object") {
            return "all";
        }
        const visibility =
            block.visibility && typeof block.visibility === "object"
                ? block.visibility
                : {};
        return String(visibility.viewport || "all");
    }

    function blockVisibleInActiveViewport(block) {
        const group = String(state.viewportGroup || "monitor");
        const rule = viewportRuleForBlock(block);
        if (rule === "all" || rule === "") {
            return true;
        }
        if (rule === "monitor_only") {
            return group === "monitor";
        }
        if (rule === "tablet_only") {
            return group === "tablet";
        }
        if (rule === "mobile_only") {
            return group === "mobile";
        }
        if (rule === "tv_only") {
            return group === "tv";
        }
        if (rule === "hide_monitor") {
            return group !== "monitor";
        }
        if (rule === "hide_tablet") {
            return group !== "tablet";
        }
        if (rule === "hide_mobile") {
            return group !== "mobile";
        }
        if (rule === "hide_tv") {
            return group !== "tv";
        }
        return true;
    }

    function cssSafeToken(raw) {
        return String(raw || "")
            .replace(/[{}<>;]/g, "")
            .trim();
    }

    function cssSafeLength(raw, fallback) {
        const text = String(raw || "").trim();
        if (text === "") {
            return String(fallback || "");
        }
        if (/^-?\d+(\.\d+)?$/.test(text)) {
            return text + "px";
        }
        if (
            /^-?\d+(\.\d+)?(px|rem|em|%|vh|vw|vmin|vmax|ch|ex|pt|pc)$/.test(
                text
            )
        ) {
            return text;
        }
        return String(fallback || "");
    }

    function cssSafeUnit(raw, fallback) {
        const unit = String(raw || "").trim().toLowerCase();
        const allowed = [
            "",
            "px",
            "rem",
            "em",
            "%",
            "vw",
            "vh",
            "vmin",
            "vmax",
            "ch",
            "ex",
            "pt",
            "pc",
        ];
        if (allowed.includes(unit)) {
            return unit;
        }
        if (typeof fallback === "string") {
            return fallback.toLowerCase();
        }
        return "px";
    }

    function cssDimension(raw, unit, fallback) {
        const text = String(raw || "").trim();
        if (text === "") {
            return String(fallback || "");
        }
        if (/^-?\d+(\.\d+)?$/.test(text)) {
            const safeUnit = cssSafeUnit(unit, "px");
            return safeUnit === "" ? text : text + safeUnit;
        }
        return cssSafeLength(text, fallback);
    }

    function clampOpacity(raw) {
        const n = Number(raw);
        if (!Number.isFinite(n)) {
            return 0;
        }
        return Math.max(0, Math.min(1, n));
    }

    function hexToRgb(hex) {
        const clean = String(hex || "").replace("#", "").trim();
        if (!/^[0-9a-f]{3,8}$/i.test(clean)) {
            return null;
        }
        if (clean.length === 3) {
            return {
                r: parseInt(clean.charAt(0) + clean.charAt(0), 16),
                g: parseInt(clean.charAt(1) + clean.charAt(1), 16),
                b: parseInt(clean.charAt(2) + clean.charAt(2), 16),
            };
        }
        return {
            r: parseInt(clean.substring(0, 2), 16),
            g: parseInt(clean.substring(2, 4), 16),
            b: parseInt(clean.substring(4, 6), 16),
        };
    }

    function overlayColorLayer(color, opacity) {
        const rgb = hexToRgb(color);
        if (!rgb || opacity <= 0) {
            return "";
        }
        const a = clampOpacity(opacity).toFixed(3);
        return (
            "linear-gradient(rgba(" +
            String(rgb.r) +
            "," +
            String(rgb.g) +
            "," +
            String(rgb.b) +
            "," +
            a +
            "), rgba(" +
            String(rgb.r) +
            "," +
            String(rgb.g) +
            "," +
            String(rgb.b) +
            "," +
            a +
            "))"
        );
    }

    function expandBackgroundValue(raw, layersCount) {
        const value = String(raw || "").trim();
        if (value === "" || layersCount <= 1) {
            return value;
        }
        const parts = value
            .split(",")
            .map(function (part) {
                return part.trim();
            })
            .filter(function (part) {
                return part !== "";
            });
        if (parts.length === 0) {
            return value;
        }
        if (parts.length >= layersCount) {
            return parts.slice(0, layersCount).join(",");
        }
        const expanded = [];
        for (let i = 0; i < layersCount; i += 1) {
            expanded.push(parts[Math.min(i, parts.length - 1)]);
        }
        return expanded.join(",");
    }

    function normalizeBackgroundRepeatKeyword(raw) {
        const value = String(raw || "")
            .trim()
            .toLowerCase()
            .replace(/\s+/g, " ");
        if (value === "") {
            return "";
        }
        if (value === "none" || value === "no repeat") {
            return "no-repeat";
        }
        const allowedSingle = [
            "repeat",
            "repeat-x",
            "repeat-y",
            "no-repeat",
            "space",
            "round",
        ];
        if (allowedSingle.includes(value)) {
            return value;
        }
        const parts = value.split(" ");
        const allowedPair = ["repeat", "no-repeat", "space", "round"];
        if (
            parts.length === 2 &&
            allowedPair.includes(parts[0]) &&
            allowedPair.includes(parts[1])
        ) {
            return parts[0] + " " + parts[1];
        }
        return "";
    }

    function normalizeBackgroundRepeatValue(raw, layersCount) {
        const value = String(raw || "").trim();
        if (value === "") {
            return "";
        }
        const parts = value
            .split(",")
            .map(function (part) {
                return normalizeBackgroundRepeatKeyword(part);
            })
            .filter(function (part) {
                return part !== "";
            });
        if (parts.length === 0) {
            return "";
        }
        if (layersCount <= 1) {
            return parts[0];
        }
        if (parts.length >= layersCount) {
            return parts.slice(0, layersCount).join(",");
        }
        const expanded = [];
        for (let i = 0; i < layersCount; i += 1) {
            expanded.push(parts[Math.min(i, parts.length - 1)]);
        }
        return expanded.join(",");
    }

    function globalColorTokenValue(key) {
        const token = String(key || "").trim();
        if (token === "") {
            return "";
        }
        const colors =
            state.globalDesignTokens &&
            state.globalDesignTokens.colors &&
            typeof state.globalDesignTokens.colors === "object"
                ? state.globalDesignTokens.colors
                : {};
        return String(colors[token] || "");
    }

    function globalFontTokenValue(key) {
        const token = String(key || "").trim();
        if (token === "") {
            return "";
        }
        const fonts =
            state.globalDesignTokens &&
            state.globalDesignTokens.fonts &&
            typeof state.globalDesignTokens.fonts === "object"
                ? state.globalDesignTokens.fonts
                : {};
        return String(fonts[token] || "");
    }

    function buttonWrapperDesignSettings(settings) {
        const output = {};
        [
            "design_margin_unit",
            "design_margin_top",
            "design_margin_right",
            "design_margin_bottom",
            "design_margin_left",
            "design_text_align",
            "design_align_self",
        ].forEach(function (key) {
            if (settings && Object.prototype.hasOwnProperty.call(settings, key)) {
                output[key] = settings[key];
            }
        });
        return output;
    }

    function buttonElementDesignSettings(settings) {
        const output = { ...(settings || {}) };
        [
            "design_margin_unit",
            "design_margin_top",
            "design_margin_right",
            "design_margin_bottom",
            "design_margin_left",
            "design_align_self",
        ].forEach(function (key) {
            delete output[key];
        });
        return output;
    }

    function previewDesignSettingsForBlock(block, settings) {
        const blockId = String(block && block.id ? block.id : "");
        const isActiveDraft =
            state.modalMode === "block" &&
            state.modalDraftBlock &&
            String(state.modalDraftBlock.id || "") === blockId;
        const interactionState = isActiveDraft
            ? normalizeDesignState(state.modalDesignState)
            : "normal";
        return designSettingsForContext(
            settings,
            designDeviceFromViewportGroup(state.viewportGroup),
            interactionState,
            false
        );
    }

    function previewGlobalPresetDeclarations(settings) {
        const preset = String(settings && settings.design_style_preset ? settings.design_style_preset : "")
            .trim()
            .toLowerCase();
        const buttonBase = [
            "padding:var(--h4bs-button-padding-y,12px) var(--h4bs-button-padding-x,20px)",
            "border-radius:var(--h4bs-button-radius,8px)",
            "font-weight:var(--h4bs-button-weight,700)",
        ];
        if (preset === "button_primary" || preset === "button_secondary") {
            return [
                "background-color:var(--h4bs-color-" + (preset === "button_primary" ? "primary" : "secondary") + ")",
                "color:var(--h4bs-color-on-" + (preset === "button_primary" ? "primary" : "secondary") + ",#fff)",
                "border:1px solid transparent",
            ].concat(buttonBase);
        }
        if (preset === "button_outline" || preset === "button_ghost") {
            return [
                "background-color:" + (preset === "button_ghost" ? "var(--h4bs-color-surface-alt,#f4f7fb)" : "transparent"),
                "color:var(--h4bs-color-primary,#0f6cbf)",
                "border:" + (preset === "button_outline" ? "2px solid var(--h4bs-color-primary,#0f6cbf)" : "1px solid var(--h4bs-color-border,#d8e2ec)"),
            ].concat(buttonBase);
        }
        if (preset === "callout") {
            return [
                "background-color:var(--h4bs-color-surface-alt,#f4f7fb)",
                "color:var(--h4bs-color-text,#1f2937)",
                "padding:var(--h4bs-card-padding,28px)",
                "border-left:4px solid var(--h4bs-color-accent,#ff7a33)",
                "border-radius:var(--h4bs-radius-md,8px)",
            ];
        }
        if (["card", "card_elevated", "card_soft"].indexOf(preset) >= 0) {
            return [
                "background-color:" + (preset === "card_soft" ? "var(--h4bs-color-surface-alt,#f4f7fb)" : "var(--h4bs-color-surface,#fff)"),
                "color:var(--h4bs-color-text,#1f2937)",
                "padding:var(--h4bs-card-padding,28px)",
                "border:1px solid var(--h4bs-color-border,#d8e2ec)",
                "border-radius:var(--h4bs-radius-md,8px)",
                "box-shadow:" + (preset === "card_elevated" ? "var(--h4bs-shadow-md,0 16px 40px rgba(21,34,56,.14))" : (preset === "card" ? "var(--h4bs-shadow-sm,0 2px 8px rgba(21,34,56,.08))" : "none")),
            ];
        }
        return [];
    }

    function previewDesignStyle(settings) {
        if (!settings || typeof settings !== "object") {
            return "";
        }
        const styles = previewGlobalPresetDeclarations(settings);
        const textColor = cssSafeToken(
            globalColorTokenValue(settings.design_text_color_global || "") ||
                settings.design_text_color ||
                ""
        );
        const bgColor = cssSafeToken(
            globalColorTokenValue(settings.design_background_color_global || "") ||
                settings.design_background_color ||
                ""
        );
        const bgImage = cssSafeToken(settings.design_background_image || "");
        const bgGradient = cssSafeToken(settings.design_background_gradient || "");
        const bgSizeRaw = cssSafeToken(settings.design_background_size || "");
        const bgPositionRaw = cssSafeToken(settings.design_background_position || "");
        const bgRepeatRaw = cssSafeToken(settings.design_background_repeat || "");
        let bgSize = bgSizeRaw;
        let bgPosition = bgPositionRaw;
        let bgRepeat = normalizeBackgroundRepeatValue(bgRepeatRaw, 1);
        const overlayColor = cssSafeToken(settings.design_overlay_color || "");
        const overlayOpacity = clampOpacity(settings.design_overlay_opacity || 0);
        const borderWidthUnit = cssSafeUnit(
            settings.design_border_width_unit || "px",
            "px"
        );
        const borderWidth = cssDimension(
            settings.design_border_width || "",
            borderWidthUnit,
            ""
        );
        const borderStyle = cssSafeToken(settings.design_border_style || "");
        const borderColor = cssSafeToken(settings.design_border_color || "");
        const borderRadiusUnit = cssSafeUnit(
            settings.design_border_radius_unit || "px",
            "px"
        );
        const borderRadius = cssDimension(
            settings.design_border_radius || "",
            borderRadiusUnit,
            ""
        );
        const boxShadow = cssSafeToken(settings.design_box_shadow || "");
        const textShadow = cssSafeToken(settings.design_text_shadow || "");
        const opacity = cssSafeToken(settings.design_opacity || "");
        const filter = cssSafeToken(settings.design_filter || "");
        const backdrop = cssSafeToken(settings.design_backdrop_filter || "");
        const transform = cssSafeToken(settings.design_transform || "");
        const transformOrigin = cssSafeToken(settings.design_transform_origin || "");
        const transition = cssSafeToken(settings.design_transition || "");
        const cursor = cssSafeToken(settings.design_cursor || "");
        const align = cssSafeToken(settings.design_text_align || "");
        const fontFamily = cssSafeToken(
            globalFontTokenValue(settings.design_font_family_global || "") ||
                settings.design_font_family ||
                ""
        );
        const fontSize = cssDimension(
            settings.design_font_size || "",
            settings.design_font_size_unit || "px",
            ""
        );
        const fontWeight = cssSafeToken(settings.design_font_weight || "");
        const lineHeight = cssDimension(
            settings.design_line_height || "",
            settings.design_line_height_unit || "",
            ""
        );
        const letterSpacing = cssDimension(
            settings.design_letter_spacing || "",
            settings.design_letter_spacing_unit || "px",
            ""
        );
        const width = cssDimension(
            settings.design_width || "",
            settings.design_width_unit || "%",
            ""
        );
        const maxWidth = cssDimension(
            settings.design_max_width || "",
            settings.design_max_width_unit || "px",
            ""
        );
        const minHeight = cssDimension(
            settings.design_min_height || "",
            settings.design_min_height_unit || "px",
            ""
        );
        const height = cssDimension(
            settings.design_height || "",
            settings.design_height_unit || "px",
            ""
        );
        const maxHeight = cssDimension(
            settings.design_max_height || "",
            settings.design_max_height_unit || "px",
            ""
        );
        const display = cssSafeToken(settings.design_display || "");
        const position = cssSafeToken(settings.design_position || "");
        const zIndex = cssSafeToken(settings.design_z_index || "");
        const overflow = cssSafeToken(settings.design_overflow || "");
        const textTransform = cssSafeToken(settings.design_text_transform || "");
        const topOffset = cssDimension(
            settings.design_top || "",
            settings.design_top_unit || "px",
            ""
        );
        const rightOffset = cssDimension(
            settings.design_right || "",
            settings.design_right_unit || "px",
            ""
        );
        const bottomOffset = cssDimension(
            settings.design_bottom || "",
            settings.design_bottom_unit || "px",
            ""
        );
        const leftOffset = cssDimension(
            settings.design_left || "",
            settings.design_left_unit || "px",
            ""
        );
        const flexDirection = cssSafeToken(settings.design_flex_direction || "");
        const justifyContent = cssSafeToken(settings.design_justify_content || "");
        const alignItems = cssSafeToken(settings.design_align_items || "");
        const alignSelf = cssSafeToken(settings.design_align_self || "");
        const marginUnit = cssSafeUnit(settings.design_margin_unit || "px", "px");
        const marginTop = cssDimension(settings.design_margin_top || "", marginUnit, "");
        const marginRight = cssDimension(
            settings.design_margin_right || "",
            marginUnit,
            ""
        );
        const marginBottom = cssDimension(
            settings.design_margin_bottom || "",
            marginUnit,
            ""
        );
        const marginLeft = cssDimension(settings.design_margin_left || "", marginUnit, "");
        const paddingUnit = cssSafeUnit(settings.design_padding_unit || "px", "px");
        const paddingTop = cssDimension(
            settings.design_padding_top || "",
            paddingUnit,
            ""
        );
        const paddingRight = cssDimension(
            settings.design_padding_right || "",
            paddingUnit,
            ""
        );
        const paddingBottom = cssDimension(
            settings.design_padding_bottom || "",
            paddingUnit,
            ""
        );
        const paddingLeft = cssDimension(
            settings.design_padding_left || "",
            paddingUnit,
            ""
        );

        if (textColor) {
            styles.push("color:" + textColor);
        }
        if (bgColor) {
            styles.push("background-color:" + bgColor);
        }

        const layers = [];
        if (bgGradient) {
            layers.push(bgGradient);
        }
        const overlayLayer = overlayColorLayer(overlayColor, overlayOpacity);
        if (overlayLayer) {
            layers.push(overlayLayer);
        }
        if (bgImage) {
            layers.push("url('" + bgImage.replace(/'/g, "%27") + "')");
        }
        if (layers.length > 0) {
            styles.push("background-image:" + layers.join(","));
        }
        const hasVisualBackground = layers.length > 0;
        if (bgSize === "" && hasVisualBackground) {
            bgSize = "cover";
        }
        if (bgPosition === "" && hasVisualBackground) {
            bgPosition = "center center";
        }
        if (bgRepeat === "" && hasVisualBackground) {
            bgRepeat = normalizeBackgroundRepeatValue("no-repeat", layers.length);
        }
        if (bgSize) {
            styles.push(
                "background-size:" + expandBackgroundValue(bgSize, layers.length)
            );
        }
        if (bgPosition) {
            styles.push(
                "background-position:" + expandBackgroundValue(bgPosition, layers.length)
            );
        }
        if (bgRepeat) {
            styles.push("background-repeat:" + normalizeBackgroundRepeatValue(bgRepeat, layers.length));
        }

        if (paddingTop || paddingRight || paddingBottom || paddingLeft) {
            styles.push(
                "padding:" +
                    (paddingTop || "0px") +
                    " " +
                    (paddingRight || "0px") +
                    " " +
                    (paddingBottom || "0px") +
                    " " +
                    (paddingLeft || "0px")
            );
        }
        if (marginTop || marginRight || marginBottom || marginLeft) {
            styles.push(
                "margin:" +
                    (marginTop || "0px") +
                    " " +
                    (marginRight || "0px") +
                    " " +
                    (marginBottom || "0px") +
                    " " +
                    (marginLeft || "0px")
            );
        }
        if (borderWidth) {
            styles.push(
                "border:" +
                    borderWidth +
                    " " +
                    (borderStyle || "solid") +
                    " " +
                    (borderColor || "#dbe7f3")
            );
        }
        if (borderRadius) {
            styles.push("border-radius:" + borderRadius);
        }
        if (boxShadow) {
            styles.push("box-shadow:" + boxShadow);
        }
        if (textShadow) {
            styles.push("text-shadow:" + textShadow);
        }
        if (opacity) {
            styles.push("opacity:" + opacity);
        }
        if (filter) {
            styles.push("filter:" + filter);
        }
        if (backdrop) {
            styles.push("backdrop-filter:" + backdrop);
        }
        if (transform) {
            styles.push("transform:" + transform);
        }
        if (transformOrigin) {
            styles.push("transform-origin:" + transformOrigin);
        }
        if (transition) {
            styles.push("transition:" + transition);
        }
        const motionDuration = Math.max(
            80,
            Math.min(60000, Number(settings.design_motion_duration || 600) || 600)
        );
        const motionDelay = Math.max(
            0,
            Math.min(60000, Number(settings.design_motion_delay || 0) || 0)
        );
        const motionEasing = ["ease", "linear", "ease-in", "ease-out", "ease-in-out"].indexOf(
            String(settings.design_motion_easing || "ease-out")
        ) >= 0
            ? String(settings.design_motion_easing || "ease-out")
            : "ease-out";
        const motionIteration = ["1", "2", "3", "infinite"].indexOf(
            String(settings.design_motion_iteration || "1")
        ) >= 0
            ? String(settings.design_motion_iteration || "1")
            : "1";
        if (
            String(settings.design_motion_entrance || "").trim() !== "" ||
            String(settings.design_motion_background || "").trim() !== "" ||
            String(settings.design_motion_hover || "").trim() !== ""
        ) {
            styles.push("--h4bs-motion-duration:" + String(Math.round(motionDuration)) + "ms");
            styles.push("--h4bs-motion-delay:" + String(Math.round(motionDelay)) + "ms");
            styles.push("--h4bs-motion-easing:" + motionEasing);
            styles.push("--h4bs-motion-iteration:" + motionIteration);
        }
        if (cursor) {
            styles.push("cursor:" + cursor);
        }
        if (align) {
            styles.push("text-align:" + align);
        }
        if (fontFamily) {
            styles.push("font-family:'" + fontFamily.replace(/'/g, "") + "', sans-serif");
        }
        if (fontSize) {
            styles.push("--h4bs-font-size:" + fontSize);
            styles.push("font-size:" + fontSize);
        }
        if (fontWeight) {
            styles.push("font-weight:" + fontWeight);
        }
        if (lineHeight) {
            styles.push("line-height:" + lineHeight);
        }
        if (letterSpacing) {
            styles.push("letter-spacing:" + letterSpacing);
        }
        if (textTransform) {
            styles.push("text-transform:" + textTransform);
        }
        if (width) {
            styles.push("width:" + width);
        }
        if (maxWidth) {
            styles.push("max-width:" + maxWidth);
        }
        if (minHeight) {
            styles.push("min-height:" + minHeight);
        }
        if (height) {
            styles.push("height:" + height);
        }
        if (maxHeight) {
            styles.push("max-height:" + maxHeight);
        }
        if (display) {
            styles.push("display:" + display);
        }
        if (position) {
            styles.push("position:" + position);
        }
        if (zIndex) {
            styles.push("z-index:" + zIndex);
        }
        if (overflow) {
            styles.push("overflow:" + overflow);
        }
        if (topOffset) {
            styles.push("top:" + topOffset);
        }
        if (rightOffset) {
            styles.push("right:" + rightOffset);
        }
        if (bottomOffset) {
            styles.push("bottom:" + bottomOffset);
        }
        if (leftOffset) {
            styles.push("left:" + leftOffset);
        }
        if (flexDirection) {
            styles.push("flex-direction:" + flexDirection);
        }
        if (justifyContent) {
            styles.push("justify-content:" + justifyContent);
        }
        if (alignItems) {
            styles.push("align-items:" + alignItems);
        }
        if (alignSelf) {
            styles.push("align-self:" + alignSelf);
        }
        return styles.join(";");
    }

    function renderPreview() {
        if (!els.previewCanvas) {
            return;
        }
        requestServerPreviewRender(0);
    }

    function requestServerPreviewRender(delayMs) {
        if (!els.previewCanvas) {
            return;
        }
        state.previewRenderRevision = Number(state.previewRenderRevision || 0) + 1;
        renderPreviewFallbackClient();
        applyImmediateDraftPreview();
        scheduleServerPreviewRender(state.previewRenderRevision, delayMs);
    }

    function scheduleServerPreviewRender(revision, delayMs) {
        const delay = Math.max(0, Number(delayMs || 0));
        if (state.previewRenderTimer) {
            window.clearTimeout(state.previewRenderTimer);
            state.previewRenderTimer = null;
        }
        state.previewRenderTimer = window.setTimeout(function () {
            state.previewRenderTimer = null;
            runServerPreviewRender(revision);
        }, delay);
    }

    function runServerPreviewRender(revision) {
        if (!els.previewCanvas) {
            return;
        }
        const renderRevision = Number(revision || 0);
        if (renderRevision !== Number(state.previewRenderRevision || 0)) {
            return;
        }
        if (state.previewRenderInFlight) {
            state.previewRenderQueued = true;
            return;
        }

        const payload = previewRequestPayload();
        const payloadKey = stableSerialize(payload);
        const existingFrame = els.previewShell
            ? els.previewShell.querySelector("[data-h4bs-draft-frame]")
            : null;
        if (
            payloadKey === state.previewLastSubmittedKey &&
            existingFrame instanceof HTMLIFrameElement
        ) {
            applyImmediateDraftPreview(existingFrame);
            syncInspectorPreviewStatus("ready");
            return;
        }
        syncInspectorPreviewStatus("updating");
        state.previewRenderInFlight = true;
        state.previewRenderRequestId = Number(state.previewRenderRequestId || 0) + 1;
        const requestId = state.previewRenderRequestId;
        state.previewRenderLayout = deepClone(payload.layout || []);
        state.previewRenderPageLayout = normalizePageLayout(payload.pageLayout);

        $.post(data.ajaxUrl, {
            action: "h4bs_builder_store_draft_preview",
            nonce: data.nonce,
            post_id: data.postId,
            layout: JSON.stringify(payload.layout || []),
            page_layout: payload.pageLayout,
            page_title_mode: payload.pageTitleMode,
            page_css: payload.pageCss,
            global_design_tokens: JSON.stringify(payload.globalDesignTokens || {}),
        })
            .done(function (response) {
                if (
                    requestId !== state.previewRenderRequestId ||
                    renderRevision !== Number(state.previewRenderRevision || 0)
                ) {
                    return;
                }
                if (!response || !response.success || !response.data) {
                    renderPreviewFallbackClient();
                    failCurrentDraftPreview();
                    return;
                }
                // A store response must identify the exact revision it just wrote. Falling
                // back to a previously localized URL would mislabel stale content as the
                // current draft when the server returns a malformed/empty success payload.
                const draftUrl = String(response.data.url || "").trim();
                const draftFingerprint = String(response.data.fingerprint || "").trim();
                if (draftUrl === "" || draftFingerprint === "") {
                    renderPreviewFallbackClient();
                    failCurrentDraftPreview();
                    return;
                }
                state.previewLastSubmittedKey = payloadKey;
                let revisionUrl = draftUrl;
                try {
                    const parsed = new URL(draftUrl, window.location.origin);
                    parsed.searchParams.set(
                        "h4bs_draft_revision",
                        draftFingerprint
                    );
                    revisionUrl = parsed.toString();
                } catch (error) {
                    revisionUrl = draftUrl;
                }
                state.draftPreviewUrl = revisionUrl;
                state.draftPreviewFingerprint = draftFingerprint;
                const draftFrame = ensureDraftPreviewFrame(revisionUrl, true);
                if (draftFrame instanceof HTMLIFrameElement) {
                    draftFrame.setAttribute("data-h4bs-payload-key", payloadKey);
                }
                if (state.parityPendingOpen) {
                    state.parityPendingOpen = false;
                    state.parityMode = true;
                    persistParityMode();
                    applyParityMode();
                } else if (state.parityMode) {
                    ensureParityPreviewFrame(true);
                }
            })
            .fail(function () {
                if (
                    requestId !== state.previewRenderRequestId ||
                    renderRevision !== Number(state.previewRenderRevision || 0)
                ) {
                    return;
                }
                renderPreviewFallbackClient();
                failCurrentDraftPreview();
            })
            .always(function () {
                state.previewRenderInFlight = false;
                if (
                    state.previewRenderQueued ||
                    renderRevision !== Number(state.previewRenderRevision || 0)
                ) {
                    state.previewRenderQueued = false;
                    scheduleServerPreviewRender(state.previewRenderRevision, 40);
                }
            });
    }

    function failCurrentDraftPreview() {
        state.parityPendingOpen = false;
        root.removeAttribute("data-h4bs-parity-selected-block");
        updateParitySelectionHelp("error");
        if (state.parityMode) {
            state.parityMode = false;
            persistParityMode();
            applyParityMode();
        }
        if (els.previewAssetStatus) {
            els.previewAssetStatus.hidden = false;
            els.previewAssetStatus.textContent =
                "Current draft preview is unavailable. Retry after the page finishes loading.";
        }
        syncInspectorPreviewStatus("fallback");
    }

    function previewRequestPayload() {
        const renderLayout = deepClone(state.layout);
        if (state.modalMode === "block" && state.modalDraftBlock) {
            const targetId = String(state.modalDraftBlock.id || "");
            if (targetId !== "") {
                const existingIndex = renderLayout.findIndex(function (block) {
                    return String(block && block.id ? block.id : "") === targetId;
                });
                if (existingIndex >= 0) {
                    renderLayout[existingIndex] = deepClone(state.modalDraftBlock);
                }
            }
        }

        const pageSource =
            state.modalMode === "page" && state.modalDraftPage && typeof state.modalDraftPage === "object"
                ? state.modalDraftPage
                : null;

        return {
            layout: renderLayout,
            pageLayout: normalizePageLayout(pageSource ? pageSource.pageLayout : state.pageLayout),
            pageTitleMode: normalizePageTitleMode(
                pageSource ? pageSource.pageTitleMode : state.pageTitleMode
            ),
            pageCss: String(pageSource ? pageSource.pageCss || "" : state.pageCss || ""),
            globalDesignTokens: normalizeGlobalDesignTokens(
                pageSource ? pageSource.globalDesignTokens || {} : state.globalDesignTokens || {}
            ),
        };
    }

    function applyServerPreviewHtml(html, renderLayout) {
        const markup = String(html || "").trim();
        if (markup === "") {
            renderPreviewFallbackClient();
            return;
        }
        els.previewCanvas.innerHTML = markup;
        els.previewCanvas
            .querySelectorAll("style.h4bs-design-variant-style")
            .forEach(function (styleNode) {
                styleNode.remove();
            });
        syncPreviewCanvasLayoutClass(state.previewRenderPageLayout || state.pageLayout);
        runPreviewRuntimeInitializers();
        decorateServerPreviewDom(renderLayout);
        bindPreviewInteractions();
        wirePreviewSortable();
        wireSectionSortables();
        syncSelectedPreviewBlockVisual();
        scheduleMiniPreviewSync(true);
    }

    function syncPreviewCanvasLayoutClass(layoutRaw) {
        if (!els.previewCanvas) {
            return;
        }
        const layout = normalizePageLayout(layoutRaw);
        const targets = [els.previewCanvas];
        els.previewCanvas
            .querySelectorAll(".h4bs-builder-page")
            .forEach(function (node) {
                if (node instanceof HTMLElement) {
                    targets.push(node);
                }
            });
        targets.forEach(function (target) {
            target.classList.add("h4bs-builder-page");
            ["default", "full_width", "canvas"].forEach(function (name) {
                target.classList.remove("h4bs-builder-page-layout-" + name);
                target.classList.remove("h4bs-page-layout-" + name);
            });
            target.classList.add("h4bs-builder-page-layout-" + layout);
            target.classList.add("h4bs-page-layout-" + layout);
        });
    }

    function runPreviewRuntimeInitializers() {
        if (typeof window.h4bsInitSliders === "function") {
            try {
                window.h4bsInitSliders(els.previewCanvas || document);
            } catch (error) {
                // no-op: preview should never hard-fail if a runtime helper throws.
            }
        }
        if (typeof window.h4bsInitSearch === "function") {
            try {
                window.h4bsInitSearch(els.previewCanvas || document);
            } catch (error) {
                // no-op
            }
        }
        if (typeof window.h4bsInitVideoPlayers === "function") {
            try {
                window.h4bsInitVideoPlayers(els.previewCanvas || document);
            } catch (error) {
                // no-op
            }
        }
    }

    function decorateServerPreviewDom(renderLayout) {
        if (!els.previewCanvas) {
            return;
        }
        const layoutIndex = {};
        (Array.isArray(renderLayout) ? renderLayout : []).forEach(function (block) {
            const key = String(block && block.id ? block.id : "");
            if (key !== "") {
                layoutIndex[key] = block;
            }
        });

        const blockNodes = els.previewCanvas.querySelectorAll(".h4bs-block[id]");
        blockNodes.forEach(function (node) {
            if (!(node instanceof HTMLElement)) {
                return;
            }
            const blockId = String(node.getAttribute("id") || "");
            if (blockId === "") {
                return;
            }
            const blockData = layoutIndex[blockId] || null;
            if (!blockData || typeof blockData !== "object") {
                return;
            }
            const blockType = blockData && blockData.type ? String(blockData.type) : inferBlockTypeFromNode(node);
            if (blockType !== "") {
                node.classList.add("h4bs-preview-block-" + blockType);
            }
            node.classList.add("h4bs-preview-block");
            node.setAttribute("data-h4bs-preview-block", blockId);
            applyPreviewDesignContext(node, blockData);

            if (blockData && !blockVisibleInActiveViewport(blockData)) {
                node.classList.add("is-hidden-viewport");
            } else {
                node.classList.remove("is-hidden-viewport");
            }

            ensureBlockToolbar(node, blockData);
            ensureInlineEditingTargets(node, blockType, blockId);
            ensureSectionDropzones(node, blockType);
        });
        ensureEmptyPreviewState();
    }

    function applyPreviewDesignContext(node, blockData) {
        if (!(node instanceof HTMLElement) || !blockData || typeof blockData !== "object") {
            return;
        }
        const settings =
            blockData.settings && typeof blockData.settings === "object"
                ? blockData.settings
                : {};
        const activeSettings = previewDesignSettingsForBlock(blockData, settings);
        const blockType = String(blockData.type || "");
        const wrapperSettings =
            blockType === "button"
                ? buttonWrapperDesignSettings(activeSettings)
                : activeSettings;
        const wrapperStyle = previewDesignStyle(wrapperSettings);
        if (wrapperStyle !== "") {
            node.setAttribute("style", wrapperStyle);
        } else {
            node.removeAttribute("style");
        }
        if (blockType === "button") {
            const button = node.querySelector(".h4bs-builder-button, .h4bs-preview-button, a");
            if (button instanceof HTMLElement) {
                const buttonStyle = previewDesignStyle(
                    buttonElementDesignSettings(activeSettings)
                );
                if (buttonStyle !== "") {
                    button.setAttribute("style", buttonStyle);
                } else {
                    button.removeAttribute("style");
                }
            }
        }
    }

    function inferBlockTypeFromNode(node) {
        if (!(node instanceof HTMLElement)) {
            return "";
        }
        const classList = String(node.className || "").split(/\s+/);
        for (let i = 0; i < classList.length; i += 1) {
            const cls = String(classList[i] || "");
            if (cls.indexOf("h4bs-block-") !== 0) {
                continue;
            }
            return cls.replace("h4bs-block-", "");
        }
        return "";
    }

    function ensureBlockToolbar(node, blockData) {
        if (!(node instanceof HTMLElement)) {
            return;
        }
        if (state.parityMode) {
            node
                .querySelectorAll(":scope > .h4bs-preview-block-tools")
                .forEach(function (toolsNode) {
                    if (toolsNode instanceof HTMLElement) {
                        toolsNode.remove();
                    }
                });
            return;
        }
        if (node.querySelector(":scope > .h4bs-preview-block-tools")) {
            return;
        }
        const hiddenForViewport = blockData && !blockVisibleInActiveViewport(blockData);
        const tools = document.createElement("div");
        tools.className = "h4bs-preview-block-tools";
        tools.innerHTML =
            "<button type='button' class='h4bs-preview-tool h4bs-preview-tool-edit' data-h4bs-preview-action='edit' title='Edit element' aria-label='Edit element'><span class='dashicons dashicons-edit' aria-hidden='true'></span></button>" +
            "<button type='button' class='h4bs-preview-tool h4bs-preview-tool-duplicate' data-h4bs-preview-action='duplicate' title='Duplicate element' aria-label='Duplicate element'><span class='dashicons dashicons-admin-page' aria-hidden='true'></span></button>" +
            "<span class='h4bs-preview-drag' title='Drag to move' aria-label='Drag to move'>||</span>" +
            "<button type='button' class='h4bs-preview-tool h4bs-preview-tool-delete' data-h4bs-preview-action='delete' title='Remove element' aria-label='Remove element'><span class='dashicons dashicons-trash' aria-hidden='true'></span></button>" +
            (hiddenForViewport ? "<span class='h4bs-preview-viewport-note'>Hidden on this viewport</span>" : "");
        node.insertBefore(tools, node.firstChild);
    }

    function ensureInlineEditingTargets(node, blockType, blockId) {
        if (!(node instanceof HTMLElement)) {
            return;
        }
        if (state.parityMode) {
            node
                .querySelectorAll(
                    "[data-h4bs-inline-edit], [data-h4bs-inline-key], [data-h4bs-inline-block]"
                )
                .forEach(function (editNode) {
                    if (!(editNode instanceof HTMLElement)) {
                        return;
                    }
                    editNode.removeAttribute("data-h4bs-inline-edit");
                    editNode.removeAttribute("data-h4bs-inline-key");
                    editNode.removeAttribute("data-h4bs-inline-block");
                    editNode.removeAttribute("contenteditable");
                });
            return;
        }
        if (blockType === "heading") {
            const heading = node.querySelector("h1,h2,h3,h4,h5,h6");
            if (heading instanceof HTMLElement) {
                heading.setAttribute("data-h4bs-inline-edit", "1");
                heading.setAttribute("data-h4bs-inline-key", "text");
                heading.setAttribute("data-h4bs-inline-block", blockId);
            }
            return;
        }
        if (blockType === "text") {
            const paragraph = node.querySelector("p");
            if (paragraph instanceof HTMLElement) {
                paragraph.setAttribute("data-h4bs-inline-edit", "1");
                paragraph.setAttribute("data-h4bs-inline-key", "text");
                paragraph.setAttribute("data-h4bs-inline-block", blockId);
            }
            return;
        }
        if (blockType === "button") {
            const link = node.querySelector(".h4bs-builder-button, a");
            if (link instanceof HTMLElement) {
                link.setAttribute("data-h4bs-inline-edit", "1");
                link.setAttribute("data-h4bs-inline-key", "label");
                link.setAttribute("data-h4bs-inline-block", blockId);
            }
        }
    }

    function describeHtmlQuickEditTarget(blockNode, clickedNode) {
        const isElementNode = function (node) {
            return Boolean(
                node &&
                node.nodeType === 1 &&
                typeof node.closest === "function"
            );
        };
        if (!isElementNode(blockNode) || !isElementNode(clickedNode)) {
            return null;
        }
        const blockId = String(
            blockNode.getAttribute("id") ||
                blockNode.getAttribute("data-h4bs-preview-block") ||
                ""
        );
        const block = findBlockById(blockId);
        if (!block || String(block.type || "") !== "html") {
            return null;
        }

        let target = clickedNode.closest("img");
        if (!isElementNode(target) || !blockNode.contains(target)) {
            target = clickedNode.closest("a,button");
        }
        if (!isElementNode(target) || !blockNode.contains(target)) {
            target = clickedNode.closest("h1,h2,h3,h4,h5,h6,p,li,label,figcaption");
        }
        if (!isElementNode(target) || !blockNode.contains(target)) {
            const span = clickedNode.closest("span");
            target =
                isElementNode(span) &&
                blockNode.contains(span) &&
                span.childElementCount === 0 &&
                String(span.textContent || "").trim() !== ""
                    ? span
                    : null;
        }
        if (!isElementNode(target) || !blockNode.contains(target)) {
            return null;
        }

        const tag = String(target.tagName || "").toLowerCase();
        const allowedTags = [
            "img", "a", "button", "h1", "h2", "h3", "h4", "h5", "h6",
            "p", "li", "label", "figcaption", "span",
        ];
        if (allowedTags.indexOf(tag) < 0) {
            return null;
        }
        const matching = Array.from(blockNode.querySelectorAll(tag));
        const index = matching.indexOf(target);
        if (index < 0) {
            return null;
        }

        const anchor = target.closest("a[href]");
        const anchors = Array.from(blockNode.querySelectorAll("a"));
        const anchorIndex =
            isElementNode(anchor) && blockNode.contains(anchor)
                ? anchors.indexOf(anchor)
                : -1;

        return {
            kind: tag === "img" ? "image" : "text",
            tag: tag,
            index: index,
            anchorIndex: anchorIndex,
        };
    }

    function htmlQuickEditSnapshot(source, descriptor) {
        if (!descriptor || typeof descriptor !== "object") {
            return null;
        }
        const tag = String(descriptor.tag || "").toLowerCase();
        const index = Math.max(0, Number(descriptor.index || 0));
        if (!/^(?:img|a|button|h[1-6]|p|li|label|figcaption|span)$/.test(tag)) {
            return null;
        }
        try {
            const parsed = new DOMParser().parseFromString(
                "<div data-h4bs-html-source-root>" + String(source || "") + "</div>",
                "text/html"
            );
            const sourceRoot = parsed.querySelector("[data-h4bs-html-source-root]");
            if (!(sourceRoot instanceof Element)) {
                return null;
            }
            const nodes = Array.from(sourceRoot.querySelectorAll(tag));
            const node = nodes[index] || null;
            if (!(node instanceof Element)) {
                return null;
            }
            const innerHtml = String(node.innerHTML || "");
            const markupWithoutBreaks = innerHtml
                .replace(/<br\s*\/?\s*>/gi, "")
                .replace(/<!--(?:.|\n|\r)*?-->/g, "");
            const anchorIndex = Number(descriptor.anchorIndex);
            const anchors = Array.from(sourceRoot.querySelectorAll("a"));
            const anchor =
                Number.isFinite(anchorIndex) && anchorIndex >= 0
                    ? anchors[anchorIndex] || null
                    : null;
            return {
                tag: tag,
                index: index,
                text: String(node.textContent || "").trim(),
                simpleText: !/<[a-z][\s\S]*>/i.test(markupWithoutBreaks),
                simpleHtml: innerHtml,
                src: tag === "img" ? String(node.getAttribute("src") || "") : "",
                alt: tag === "img" ? String(node.getAttribute("alt") || "") : "",
                href:
                    anchor instanceof Element
                        ? String(anchor.getAttribute("href") || "")
                        : tag === "a"
                          ? String(node.getAttribute("href") || "")
                          : "",
                anchorIndex:
                    anchor instanceof Element
                        ? anchorIndex
                        : tag === "a"
                          ? index
                          : -1,
            };
        } catch (error) {
            return null;
        }
    }

    function htmlOpeningTagRange(source, tag, targetIndex) {
        const safeTag = String(tag || "").toLowerCase();
        if (!/^(?:img|a|button|h[1-6]|p|li|label|figcaption|span)$/.test(safeTag)) {
            return null;
        }
        const expression = new RegExp("<" + safeTag + "\\b[^>]*>", "gi");
        let match = null;
        let index = 0;
        while ((match = expression.exec(String(source || "")))) {
            if (index === targetIndex) {
                return {
                    start: match.index,
                    end: expression.lastIndex,
                    value: match[0],
                };
            }
            index += 1;
        }
        return null;
    }

    function escapeHtmlAttributeValue(value) {
        return String(value || "")
            .replace(/&/g, "&amp;")
            .replace(/"/g, "&quot;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;");
    }

    function replaceHtmlAttributeAtIndex(source, tag, targetIndex, attribute, value) {
        const attr = String(attribute || "").toLowerCase();
        if (["src", "alt", "href", "title"].indexOf(attr) < 0) {
            return null;
        }
        const range = htmlOpeningTagRange(source, tag, targetIndex);
        if (!range) {
            return null;
        }
        const nextAttribute = attr + '=\"' + escapeHtmlAttributeValue(value) + '\"';
        const attributePattern = new RegExp(
            "\\s+" + attr + "\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s>]+)",
            "i"
        );
        let nextTag = String(range.value || "");
        if (attributePattern.test(nextTag)) {
            nextTag = nextTag.replace(attributePattern, " " + nextAttribute);
        } else {
            const insertionPoint = /\/>$/.test(nextTag)
                ? nextTag.length - 2
                : nextTag.length - 1;
            nextTag =
                nextTag.slice(0, insertionPoint) +
                " " +
                nextAttribute +
                nextTag.slice(insertionPoint);
        }
        return (
            String(source || "").slice(0, range.start) +
            nextTag +
            String(source || "").slice(range.end)
        );
    }

    function htmlElementRange(source, tag, targetIndex) {
        const safeTag = String(tag || "").toLowerCase();
        if (!/^(?:a|button|h[1-6]|p|li|label|figcaption|span)$/.test(safeTag)) {
            return null;
        }
        const expression = new RegExp(
            "(<" + safeTag + "\\b[^>]*>)([\\s\\S]*?)(<\\/" + safeTag + "\\s*>)",
            "gi"
        );
        let match = null;
        let index = 0;
        while ((match = expression.exec(String(source || "")))) {
            if (index === targetIndex) {
                return {
                    start: match.index,
                    end: expression.lastIndex,
                    open: match[1],
                    inner: match[2],
                    close: match[3],
                };
            }
            index += 1;
        }
        return null;
    }

    function replaceHtmlTextAtIndex(source, tag, targetIndex, value) {
        const range = htmlElementRange(source, tag, targetIndex);
        if (!range) {
            return null;
        }
        const markupWithoutBreaks = String(range.inner || "")
            .replace(/<br\s*\/?\s*>/gi, "")
            .replace(/<!--(?:.|\n|\r)*?-->/g, "");
        if (/<[a-z][\s\S]*>/i.test(markupWithoutBreaks)) {
            return null;
        }
        const nextText = escHtml(String(value || "")).replace(/\r\n|\r|\n/g, "<br>");
        return (
            String(source || "").slice(0, range.start) +
            range.open +
            nextText +
            range.close +
            String(source || "").slice(range.end)
        );
    }

    function safeHtmlQuickEditUrl(value, allowEmpty) {
        const candidate = String(value || "").trim();
        if (candidate === "") {
            return allowEmpty ? "" : null;
        }
        const protocol = candidate.match(/^([a-z][a-z0-9+.-]*):/i);
        if (
            protocol &&
            ["http", "https", "mailto", "tel"].indexOf(
                String(protocol[1] || "").toLowerCase()
            ) < 0
        ) {
            return null;
        }
        return candidate;
    }

    function syncHtmlSourceField(value) {
        if (!(els.modalBody instanceof HTMLElement)) {
            return;
        }
        const textarea = els.modalBody.querySelector(
            '[data-h4bs-field-key="html"] textarea'
        );
        if (textarea instanceof HTMLTextAreaElement) {
            textarea.value = String(value || "");
        }
    }

    function applyHtmlQuickEditSource(modalBlock, nextSource, status, message) {
        if (typeof nextSource !== "string") {
            if (status instanceof HTMLElement) {
                status.textContent =
                    "That item contains nested markup. Use HTML source under Advanced for this one.";
                status.classList.add("is-error");
            }
            return false;
        }
        applyDraftBlockSettingChange(modalBlock, "html", nextSource);
        syncHtmlSourceField(nextSource);
        if (status instanceof HTMLElement) {
            status.textContent = String(message || "Preview updated. Save when it looks right.");
            status.classList.remove("is-error");
        }
        return true;
    }

    function htmlQuickEditTargetLabel(snapshot) {
        if (!snapshot || typeof snapshot !== "object") {
            return "selected item";
        }
        if (snapshot.tag === "img") {
            return "image";
        }
        if (/^h[1-6]$/.test(String(snapshot.tag || ""))) {
            return "heading";
        }
        if (snapshot.tag === "a") {
            return "link";
        }
        if (snapshot.tag === "button") {
            return "button";
        }
        return "text";
    }

    function buildHtmlQuickEditor(modalBlock, descriptor) {
        const wrapper = document.createElement("section");
        wrapper.className = "h4bs-html-quick-edit";

        const heading = document.createElement("h4");
        heading.textContent = "Quick edit what you clicked";
        wrapper.appendChild(heading);

        const source = String(
            modalBlock && modalBlock.settings ? modalBlock.settings.html || "" : ""
        );
        const snapshot = htmlQuickEditSnapshot(source, descriptor);
        const intro = document.createElement("p");
        intro.className = "h4bs-html-quick-edit-intro";
        if (!descriptor) {
            intro.textContent =
                "This migrated page is stored as one HTML element. Click a visible image, heading, paragraph, button, or link in Live Preview to edit only that item.";
            wrapper.appendChild(intro);
            return wrapper;
        }
        if (!snapshot) {
            intro.textContent =
                "Studio could not map that item safely. Click it again, or use HTML source under Advanced.";
            wrapper.appendChild(intro);
            return wrapper;
        }
        intro.textContent =
            "Selected " +
            htmlQuickEditTargetLabel(snapshot) +
            ". These controls update only this item inside the migrated HTML element.";
        wrapper.appendChild(intro);

        const status = document.createElement("p");
        status.className = "h4bs-html-quick-edit-status";
        status.setAttribute("role", "status");
        status.setAttribute("aria-live", "polite");

        const applyAttribute = function (tag, index, attribute, value, allowEmpty) {
            const safeValue =
                attribute === "src" || attribute === "href"
                    ? safeHtmlQuickEditUrl(value, !!allowEmpty)
                    : String(value || "");
            if (safeValue === null) {
                status.textContent = "Use a valid web, email, phone, relative, or anchor URL.";
                status.classList.add("is-error");
                return false;
            }
            const currentSource = String(modalBlock.settings.html || "");
            const nextSource = replaceHtmlAttributeAtIndex(
                currentSource,
                tag,
                index,
                attribute,
                safeValue
            );
            return applyHtmlQuickEditSource(
                modalBlock,
                nextSource,
                status,
                "Preview updated. Save Element Changes when it looks right."
            );
        };

        if (snapshot.tag === "img") {
            wrapper.appendChild(
                createField(
                    {
                        key: "html_quick_image",
                        label: "Selected image",
                        type: "media",
                        mediaType: "image",
                        imageProfile: "content",
                        allowManualInput: true,
                    },
                    snapshot.src,
                    function (value, meta) {
                        if (!applyAttribute("img", snapshot.index, "src", value, false)) {
                            return;
                        }
                        const attachmentAlt = String(
                            meta && meta.attachment ? meta.attachment.alt || "" : ""
                        ).trim();
                        if (snapshot.alt === "" && attachmentAlt !== "") {
                            applyAttribute(
                                "img",
                                snapshot.index,
                                "alt",
                                attachmentAlt,
                                true
                            );
                        }
                    }
                )
            );
            wrapper.appendChild(
                createField(
                    {
                        key: "html_quick_alt",
                        label: "Image description (alt text)",
                        type: "text",
                    },
                    snapshot.alt,
                    function (value) {
                        applyAttribute("img", snapshot.index, "alt", value, true);
                    }
                )
            );
        } else if (snapshot.simpleText) {
            wrapper.appendChild(
                createField(
                    {
                        key: "html_quick_text",
                        label: "Selected " + htmlQuickEditTargetLabel(snapshot) + " text",
                        type: "textarea",
                        rows: 3,
                    },
                    snapshot.text,
                    function (value) {
                        const currentSource = String(modalBlock.settings.html || "");
                        const nextSource = replaceHtmlTextAtIndex(
                            currentSource,
                            snapshot.tag,
                            snapshot.index,
                            value
                        );
                        applyHtmlQuickEditSource(
                            modalBlock,
                            nextSource,
                            status,
                            "Text updated in preview. Save Element Changes when it looks right."
                        );
                    }
                )
            );
        } else {
            const nested = document.createElement("p");
            nested.className = "h4bs-html-quick-edit-warning";
            nested.textContent =
                "This item contains nested formatting, so Studio left it untouched. Use HTML source under Advanced for this item.";
            wrapper.appendChild(nested);
        }

        if (snapshot.anchorIndex >= 0) {
            wrapper.appendChild(
                createField(
                    {
                        key: "html_quick_link",
                        label: "Link destination",
                        type: "text",
                        placeholder: "https://example.com/page/",
                    },
                    snapshot.href,
                    function (value) {
                        applyAttribute("a", snapshot.anchorIndex, "href", value, true);
                    }
                )
            );
        }

        status.textContent = "Changes appear in Live Preview before you save.";
        wrapper.appendChild(status);
        return wrapper;
    }

    function ensureSectionDropzones(node, blockType) {
        if (!(node instanceof HTMLElement)) {
            return;
        }
        if (state.parityMode) {
            node.querySelectorAll(":scope .h4bs-section-empty").forEach(function (emptyNode) {
                if (emptyNode instanceof HTMLElement) {
                    emptyNode.remove();
                }
            });
            node.querySelectorAll(":scope [data-h4bs-section-dropzone]").forEach(function (dropNode) {
                if (!(dropNode instanceof HTMLElement)) {
                    return;
                }
                dropNode.removeAttribute("data-h4bs-section-dropzone");
                dropNode.removeAttribute("data-h4bs-parent");
                dropNode.removeAttribute("data-h4bs-slot");
                dropNode.classList.remove("h4bs-section-dropzone", "h4bs-inner-section-dropzone");
            });
            return;
        }
        if (
            blockType !== "section" &&
            blockType !== "container" &&
            blockType !== "inner_section"
        ) {
            return;
        }
        const parentId = String(node.getAttribute("id") || "");
        let slotSelector =
            ":scope > .h4bs-builder-section-grid > .h4bs-builder-section-col > .h4bs-builder-section-slot";
        if (blockType === "inner_section") {
            slotSelector =
                ":scope > .h4bs-builder-inner-section > .h4bs-builder-inner-col > .h4bs-builder-section-slot";
        } else if (blockType === "container") {
            slotSelector =
                ":scope > .h4bs-builder-container > .h4bs-builder-section-col > .h4bs-builder-section-slot";
        }
        const slotNodes = node.querySelectorAll(
            slotSelector
        );
        slotNodes.forEach(function (slotNode, index) {
            if (!(slotNode instanceof HTMLElement)) {
                return;
            }
            slotNode.classList.add("h4bs-section-dropzone");
            if (blockType === "inner_section") {
                slotNode.classList.add("h4bs-inner-section-dropzone");
            }
            slotNode.setAttribute("data-h4bs-section-dropzone", "1");
            slotNode.setAttribute("data-h4bs-parent", parentId);
            slotNode.setAttribute("data-h4bs-slot", String(index));

            const hasBlock = !!slotNode.querySelector(":scope > .h4bs-preview-block[data-h4bs-preview-block]");
            if (hasBlock) {
                slotNode.querySelectorAll(":scope > .h4bs-section-empty").forEach(function (emptyNode) {
                    if (emptyNode instanceof HTMLElement) {
                        emptyNode.remove();
                    }
                });
                return;
            }

            if (!slotNode.querySelector(":scope > .h4bs-section-empty")) {
                const empty = document.createElement("div");
                empty.className = "h4bs-section-empty";
                empty.textContent =
                    blockType === "inner_section"
                        ? "Drop elements in this inner column"
                        : "Drop elements in this column";
                slotNode.appendChild(empty);
            }
        });
    }

    function ensureEmptyPreviewState() {
        if (!els.previewCanvas) {
            return;
        }
        const hasBlocks = !!els.previewCanvas.querySelector(
            ".h4bs-preview-block[data-h4bs-preview-block]"
        );
        const emptyNode = els.previewCanvas.querySelector(":scope > .h4bs-preview-empty");
        if (hasBlocks) {
            if (emptyNode instanceof HTMLElement) {
                emptyNode.remove();
            }
            return;
        }
        if (!(emptyNode instanceof HTMLElement)) {
            const empty = document.createElement("div");
            empty.className = "h4bs-preview-empty";
            empty.textContent = "Drop elements, widgets, or templates here to build the page.";
            els.previewCanvas.appendChild(empty);
        }
    }

    function renderPreviewFallbackClient() {
        if (!els.previewCanvas) {
            return;
        }
        const contentHtml = topLevelBlocks()
            .map(function (block) {
                return previewBlock(blockWithDraft(block));
            })
            .join("");
        const resolvedContent =
            contentHtml ||
            "<div class='h4bs-preview-empty'>Drop elements, widgets, or templates here to build the page.</div>";
        const layout = normalizePageLayout(state.pageLayout || "default");
        const canShowTemplateSlots = !state.isTemplate && layout !== "canvas";
        const slots =
            state.previewTemplateSlots &&
            typeof state.previewTemplateSlots === "object"
                ? state.previewTemplateSlots
                : normalizePreviewTemplateSlots({});
        let shellHtml = "";
        if (canShowTemplateSlots && String(slots.header_html || "") !== "") {
            shellHtml +=
                "<div class='h4bs-preview-site-slot h4bs-preview-site-slot-header' data-h4bs-preview-site-slot='header'>" +
                String(slots.header_html || "") +
                "</div>";
        }
        shellHtml +=
            "<div class='h4bs-builder-page' data-h4bs-preview-page='1'>" +
            resolvedContent +
            "</div>";
        if (canShowTemplateSlots && String(slots.footer_html || "") !== "") {
            shellHtml +=
                "<div class='h4bs-preview-site-slot h4bs-preview-site-slot-footer' data-h4bs-preview-site-slot='footer'>" +
                String(slots.footer_html || "") +
                "</div>";
        }
        els.previewCanvas.innerHTML = shellHtml;
        syncPreviewCanvasLayoutClass(layout);
        runPreviewRuntimeInitializers();
        bindPreviewInteractions();
        wirePreviewSortable();
        wireSectionSortables();
        syncSelectedPreviewBlockVisual();
        scheduleMiniPreviewSync(true);
    }

    function safeSelectToken(raw, allowed, fallback) {
        const candidate = String(raw || "").trim().toLowerCase();
        if (allowed.indexOf(candidate) >= 0) {
            return candidate;
        }
        return String(fallback || "");
    }

    function globalContainerMaxWidthCssValue() {
        const tokens =
            state.globalDesignTokens && typeof state.globalDesignTokens === "object"
                ? state.globalDesignTokens
                : {};
        const layout =
            tokens.layout && typeof tokens.layout === "object" ? tokens.layout : {};
        return (
            cssDimension(
                layout.container_max_width || "1200",
                layout.container_max_width_unit || "px",
                "1200px"
            ) || "1200px"
        );
    }

    function parseColumnWidthTokens(raw) {
        const source = String(raw || "").trim();
        if (source === "") {
            return [];
        }
        return source
            .split(/[|,]/)
            .map(function (part) {
                const value = Number(String(part || "").trim());
                if (!Number.isFinite(value)) {
                    return 0;
                }
                return Math.max(0, value);
            })
            .filter(function (value) {
                return value > 0;
            });
    }

    function normalizeColumnWidthPercentages(raw, columns) {
        const count = Math.max(1, Math.min(MAX_COLUMNS, Number(columns || 1)));
        const parsed = parseColumnWidthTokens(raw);
        if (!parsed.length) {
            return [];
        }
        const values = parsed.slice(0, count);
        while (values.length < count) {
            values.push(1);
        }
        const total = values.reduce(function (sum, value) {
            return sum + value;
        }, 0);
        if (!Number.isFinite(total) || total <= 0) {
            return [];
        }
        return values.map(function (value) {
            return (value / total) * 100;
        });
    }

    function cssPercent(value) {
        const parsed = Number(value);
        if (!Number.isFinite(parsed) || parsed <= 0) {
            return "";
        }
        const normalized = normalizeDecimalValue(parsed, 2);
        if (normalized === "") {
            return "";
        }
        return normalized + "%";
    }

    function columnStyleForLayoutMode(layoutMode, columnWidths, index) {
        const mode = String(layoutMode || "grid");
        if (mode !== "flex" || !Array.isArray(columnWidths) || !columnWidths.length) {
            return "";
        }
        const slot = Math.max(0, Number(index || 0));
        const percent = cssPercent(
            slot < columnWidths.length ? columnWidths[slot] : columnWidths[0]
        );
        if (percent === "") {
            return "";
        }
        return "flex:0 0 " + percent + ";max-width:" + percent + ";";
    }

    function sectionLayoutContext(settings, defaults) {
        const base = settings && typeof settings === "object" ? settings : {};
        const fallback = defaults && typeof defaults === "object" ? defaults : {};
        const structureDefaults = structureLayoutDefaults();
        const deviceSuffix =
            state.viewportGroup === "mobile"
                ? "_mobile"
                : state.viewportGroup === "tablet"
                  ? "_tablet"
                  : "";
        const responsiveValue = function (key, fallbackValue) {
            if (deviceSuffix !== "") {
                const candidate = base[key + deviceSuffix];
                if (
                    candidate !== null &&
                    typeof candidate !== "undefined" &&
                    String(candidate).trim() !== ""
                ) {
                    return candidate;
                }
            }
            return Object.prototype.hasOwnProperty.call(base, key)
                ? base[key]
                : fallbackValue;
        };
        const columns = Math.max(
            1,
            Math.min(
                MAX_COLUMNS,
                Number(
                    responsiveValue(
                        "columns",
                        deviceSuffix === "_mobile"
                            ? 1
                            : deviceSuffix === "_tablet"
                              ? Math.min(
                                    2,
                                    Number(base.columns || fallback.columns || 2)
                                )
                              : fallback.columns || structureDefaults.columns || 2
                    )
                )
            )
        );
        const gap = Math.max(
            0,
            Math.min(
                120,
                Number(
                    responsiveValue(
                        "gap",
                        fallback.gap || structureDefaults.gap || 18
                    )
                )
            )
        );
        const minHeight = Math.max(
            Number(fallback.minHeightMin || 80),
            Math.min(
                Number(fallback.minHeightMax || 1400),
                Number(
                    responsiveValue("min_height", "") ||
                        fallback.minHeight ||
                        structureDefaults.min_height ||
                        140
                )
            )
        );
        const mode = safeSelectToken(
            responsiveValue("layout_mode", "") || fallback.layoutMode || structureDefaults.layout_mode || "grid",
            ["grid", "flex"],
            "grid"
        );
        const widthMode = safeSelectToken(
            responsiveValue("content_width_mode", "") ||
                fallback.contentWidthMode ||
                structureDefaults.content_width_mode ||
                "inherit",
            ["inherit", "custom", "full"],
            "inherit"
        );
        const customWidth = cssDimension(
            responsiveValue("content_width", "") || "",
            (deviceSuffix !== "" &&
            String(base["content_width" + deviceSuffix + "_unit"] || "").trim() !== ""
                ? base["content_width" + deviceSuffix + "_unit"]
                : base.content_width_unit || "px"),
            ""
        );
        const columnWidths = normalizeColumnWidthPercentages(
            responsiveValue("column_widths", "") || "",
            columns
        );
        const resolvedWidth =
            widthMode === "custom" && customWidth !== ""
                ? customWidth
                : globalContainerMaxWidthCssValue();

        const styleParts = [
            "--h4bs-col:" + String(columns),
            "--h4bs-gap:" + String(gap) + "px",
            "min-height:" + String(minHeight) + "px",
        ];

        if (widthMode === "full") {
            styleParts.push("width:100%", "max-width:none");
        } else if (resolvedWidth !== "") {
            styleParts.push(
                "width:100%",
                "max-width:" + resolvedWidth,
                "margin-left:auto",
                "margin-right:auto"
            );
        }

        if (mode === "flex") {
            const flexDirection = safeSelectToken(
                responsiveValue("flex_direction", "") ||
                    fallback.flexDirection ||
                    structureDefaults.flex_direction ||
                    "row",
                ["row", "row-reverse", "column", "column-reverse"],
                "row"
            );
            const flexWrap = safeSelectToken(
                responsiveValue("flex_wrap", "") ||
                    fallback.flexWrap ||
                    structureDefaults.flex_wrap ||
                    "wrap",
                ["nowrap", "wrap", "wrap-reverse"],
                "wrap"
            );
            const justifyContent = safeSelectToken(
                responsiveValue("justify_content", "") ||
                    fallback.justifyContent ||
                    structureDefaults.justify_content ||
                    "flex-start",
                [
                    "flex-start",
                    "center",
                    "flex-end",
                    "space-between",
                    "space-around",
                    "space-evenly",
                ],
                "flex-start"
            );
            const alignItems = safeSelectToken(
                responsiveValue("align_items", "") ||
                    fallback.alignItems ||
                    structureDefaults.align_items ||
                    "stretch",
                ["stretch", "flex-start", "center", "flex-end", "baseline"],
                "stretch"
            );
            const alignContent = safeSelectToken(
                responsiveValue("align_content", "") ||
                    fallback.alignContent ||
                    structureDefaults.align_content ||
                    "stretch",
                [
                    "stretch",
                    "flex-start",
                    "center",
                    "flex-end",
                    "space-between",
                    "space-around",
                    "space-evenly",
                ],
                "stretch"
            );
            styleParts.push(
                "display:flex",
                "flex-direction:" + flexDirection,
                "flex-wrap:" + flexWrap,
                "justify-content:" + justifyContent,
                "align-items:" + alignItems,
                "align-content:" + alignContent
            );
        }
        if (mode === "grid" && columnWidths.length === columns) {
            const template = columnWidths
                .map(function (value) {
                    return cssPercent(value);
                })
                .filter(function (value) {
                    return value !== "";
                })
                .join(" ");
            if (template !== "") {
                styleParts.push("grid-template-columns:" + template);
            }
        }

        return {
            columns: columns,
            style: styleParts.join(";"),
            modeClass: mode,
            columnWidths: columnWidths,
        };
    }

    function backgroundVideoPreview(settings) {
        if (!toBool(settings.background_video_enabled, false)) {
            return "";
        }
        const hls = String(settings.background_video_hls || "");
        const primary = String(settings.background_video_src || settings.background_video_media_src || "");
        const fallback = String(settings.background_video_fallback_src || settings.background_video_fallback_media_src || "");
        const poster = String(settings.background_video_poster || settings.background_video_poster_media_src || "");
        const failureImage = String(settings.background_video_failure_image || settings.background_video_failure_image_media_src || poster);
        if (!hls && !primary && !fallback) {
            return "";
        }
        const autoplay = toBool(settings.background_video_autoplay, true);
        const decorative = toBool(settings.background_video_decorative, true);
        const controls = !decorative && toBool(settings.background_video_controls, false);
        const attrs = [
            "class='h4bs-background-video'",
            "data-h4bs-video-player",
            "playsinline",
            "preload='" + escAttr(String(settings.background_video_preload || "metadata")) + "'",
            hls ? "data-h4bs-hls='" + escAttr(hls) + "'" : "",
            primary ? "data-h4bs-primary-video='" + escAttr(primary) + "'" : "",
            fallback ? "data-h4bs-fallback-video='" + escAttr(fallback) + "'" : "",
            failureImage ? "data-h4bs-fallback-image='" + escAttr(failureImage) + "'" : "",
            poster ? "poster='" + escAttr(poster) + "'" : "",
            autoplay ? "autoplay" : "",
            autoplay || toBool(settings.background_video_muted, true) ? "muted" : "",
            toBool(settings.background_video_loop, true) ? "loop" : "",
            controls ? "controls" : "",
            decorative
                ? "aria-hidden='true' tabindex='-1'"
                : "aria-label='" + escAttr(String(settings.background_video_title || "Background video")) + "'",
        ].filter(Boolean).join(" ");
        const sourceMime = function (url) {
            const path = String(url || "").split(/[?#]/)[0].toLowerCase();
            if (path.endsWith(".webm")) return "video/webm";
            if (path.endsWith(".ogg") || path.endsWith(".ogv")) return "video/ogg";
            if (path.endsWith(".m4v")) return "video/x-m4v";
            return "video/mp4";
        };
        const sources =
            (hls ? "<source src='" + escAttr(hls) + "' type='application/vnd.apple.mpegurl'>" : "") +
            (primary ? "<source src='" + escAttr(primary) + "' type='" + sourceMime(primary) + "'>" : "") +
            (fallback && fallback !== primary ? "<source src='" + escAttr(fallback) + "' type='" + sourceMime(fallback) + "'>" : "");
        const fit = ["cover", "contain"].includes(String(settings.background_video_fit || "cover"))
            ? String(settings.background_video_fit || "cover")
            : "cover";
        const overflow = ["hidden", "clip"].includes(String(settings.background_video_overflow || "hidden"))
            ? String(settings.background_video_overflow || "hidden")
            : "hidden";
        const opacity = Math.max(0, Math.min(1, Number(settings.background_video_overlay_opacity || 0)));
        const style = [
            "--h4bs-background-video-fit:" + fit,
            "--h4bs-background-video-position:" + String(settings.background_video_position || "center center"),
            "--h4bs-background-video-position-tablet:" + String(settings.background_video_position_tablet || settings.background_video_position || "center center"),
            "--h4bs-background-video-position-mobile:" + String(settings.background_video_position_mobile || settings.background_video_position_tablet || settings.background_video_position || "center center"),
            "--h4bs-background-video-overflow:" + overflow,
            "--h4bs-background-video-overlay-color:" + String(settings.background_video_overlay_color || "#000000"),
            "--h4bs-background-video-overlay-gradient:" + String(settings.background_video_overlay_gradient || "none"),
            "--h4bs-background-video-overlay-opacity:" + String(opacity),
        ].join(";");
        return (
            "<div class='h4bs-background-video-layer" + (controls ? " has-controls" : "") + "' data-h4bs-background-video style='" + escAttr(style) + "'>" +
            "<video " + attrs + ">" + sources + "</video>" +
            "<div class='h4bs-background-video-fallback' data-h4bs-video-fallback hidden>" +
            (failureImage ? "<img src='" + escAttr(failureImage) + "' alt=''>" : "") +
            "</div><span class='h4bs-background-video-overlay' aria-hidden='true'></span></div>"
        );
    }

    function previewBlock(block) {
        const settings =
            block && block.settings && typeof block.settings === "object"
                ? block.settings
                : {};
        const blockId = String(block && block.id ? block.id : "");
        const activeDesignSettings = previewDesignSettingsForBlock(block, settings);
        const previewSettings = block.type === "button"
            ? buttonWrapperDesignSettings(activeDesignSettings)
            : activeDesignSettings;
        const inlineStyle = previewDesignStyle(previewSettings);
        const styleAttr =
            inlineStyle !== "" ? " style='" + escAttr(inlineStyle) + "'" : "";
        const hiddenForViewport = !blockVisibleInActiveViewport(block);
        const previewClasses = [
            "h4bs-preview-block",
            "h4bs-preview-block-" + String(block.type || "text"),
            "h4bs-block",
            "h4bs-block-" + String(block.type || "text"),
        ];
        String(settings.advanced_css_classes || "")
            .split(/\s+/)
            .map(function (className) {
                return String(className || "").replace(/[^a-zA-Z0-9_-]/g, "");
            })
            .filter(function (className) {
                return className !== "";
            })
            .forEach(function (className) {
                previewClasses.push(className);
            });
        const preset = String(settings.design_style_preset || "").trim().toLowerCase();
        if (preset !== "") {
            previewClasses.push("h4bs-style-preset-" + preset.replace(/_/g, "-"));
        }
        [
            ["design_motion_entrance", "h4bs-motion-entrance-"],
            ["design_motion_hover", "h4bs-motion-hover-"],
            ["design_motion_background", "h4bs-motion-background-"],
        ].forEach(function (entry) {
            const value = String(settings[entry[0]] || "").trim().toLowerCase();
            if (value !== "") {
                previewClasses.push(entry[1] + value.replace(/_/g, "-"));
            }
        });
        if (
            String(settings.design_motion_entrance || "").trim() !== "" ||
            String(settings.design_motion_background || "").trim() !== ""
        ) {
            previewClasses.push("h4bs-has-motion");
            previewClasses.push(
                "h4bs-motion-trigger-" +
                    (["page_load", "in_view", "interaction"].indexOf(String(settings.design_motion_trigger || "page_load")) >= 0
                        ? String(settings.design_motion_trigger || "page_load")
                        : "page_load").replace(/_/g, "-")
            );
        }
        previewClasses.push(
            "h4bs-motion-reduced-" +
                (["respect", "disable", "allow"].indexOf(String(settings.design_motion_reduced || "respect")) >= 0
                    ? String(settings.design_motion_reduced || "respect")
                    : "respect")
        );
        if (String(block.type || "") === "heading") {
            const tag = ["h1", "h2", "h3", "h4", "h5", "h6"].indexOf(String(settings.tag || "h2")) >= 0
                ? String(settings.tag || "h2")
                : "h2";
            previewClasses.push("h4bs-heading-" + tag);
        }
        if (
            ["section", "container"].includes(String(block.type || ""))
            && toBool(settings.background_video_enabled, false)
        ) {
            previewClasses.push("has-h4bs-background-video");
        }
        if (hiddenForViewport) {
            previewClasses.push("is-hidden-viewport");
        }
        const open =
            "<section class='" +
            escAttr(previewClasses.join(" ")) +
            "' data-h4bs-preview-block='" +
            escAttr(blockId) +
            "'" +
            (String(settings.advanced_html_title || "").trim() !== ""
                ? " title='" +
                  escAttr(String(settings.advanced_html_title || "")) +
                  "'"
                : "") +
            (String(settings.advanced_aria_label || "").trim() !== ""
                ? " aria-label='" +
                  escAttr(String(settings.advanced_aria_label || "")) +
                  "'"
                : "") +
            (["region", "navigation", "main", "banner", "contentinfo", "complementary", "article", "form", "search", "group"].includes(
                String(settings.advanced_role || "")
            )
                ? " role='" + escAttr(String(settings.advanced_role)) + "'"
                : "") +
            (["0", "-1"].includes(String(settings.advanced_tabindex || ""))
                ? " tabindex='" +
                  escAttr(String(settings.advanced_tabindex)) +
                  "'"
                : "") +
            (toBool(settings.advanced_aria_hidden, false)
                ? " aria-hidden='true'"
                : "") +
            styleAttr +
            ">";
        const toolbar =
            "<div class='h4bs-preview-block-tools'>" +
            "<button type='button' class='h4bs-preview-tool h4bs-preview-tool-edit' data-h4bs-preview-action='edit' title='Edit element' aria-label='Edit element'><span class='dashicons dashicons-edit' aria-hidden='true'></span></button>" +
            "<button type='button' class='h4bs-preview-tool h4bs-preview-tool-duplicate' data-h4bs-preview-action='duplicate' title='Duplicate element' aria-label='Duplicate element'><span class='dashicons dashicons-admin-page' aria-hidden='true'></span></button>" +
            "<span class='h4bs-preview-drag' title='Drag to move' aria-label='Drag to move'>||</span>" +
            "<button type='button' class='h4bs-preview-tool h4bs-preview-tool-delete' data-h4bs-preview-action='delete' title='Remove element' aria-label='Remove element'><span class='dashicons dashicons-trash' aria-hidden='true'></span></button>" +
            (hiddenForViewport
                ? "<span class='h4bs-preview-viewport-note'>Hidden on this viewport</span>"
                : "") +
            "</div>";
        const close = "</section>";

        if (block.type === "section") {
            const structureDefaults = structureLayoutDefaults();
            const sectionCtx = sectionLayoutContext(settings, {
                columns: structureDefaults.columns,
                gap: structureDefaults.gap,
                minHeight: structureDefaults.min_height,
                minHeightMin: 80,
                minHeightMax: 1800,
                layoutMode: structureDefaults.layout_mode,
                contentWidthMode: structureDefaults.content_width_mode,
                flexDirection: structureDefaults.flex_direction,
                flexWrap: structureDefaults.flex_wrap,
                justifyContent: structureDefaults.justify_content,
                alignItems: structureDefaults.align_items,
                alignContent: structureDefaults.align_content,
            });
            const columns = sectionCtx.columns;
            const labels = splitTextItems(String(settings.column_labels || "Column 1|Column 2"));
            const columnsHtml = [];
            for (let i = 0; i < columns; i += 1) {
                const label = labels[i] || ("Column " + String(i + 1));
                const columnStyle = columnStyleForLayoutMode(
                    sectionCtx.modeClass,
                    sectionCtx.columnWidths,
                    i
                );
                const columnStyleAttr =
                    columnStyle !== ""
                        ? " style='" + escAttr(columnStyle) + "'"
                        : "";
                const childHtml = childrenForSection(blockId, i)
                    .map(function (child) {
                        return previewBlock(blockWithDraft(child));
                    })
                    .join("");
                columnsHtml.push(
                    "<div class='h4bs-preview-section-col'" + columnStyleAttr + ">" +
                        "<div class='h4bs-section-col-label'>" +
                        escHtml(label) +
                        "</div>" +
                        "<div class='h4bs-section-dropzone' data-h4bs-section-dropzone='1' data-h4bs-parent='" +
                        escAttr(blockId) +
                        "' data-h4bs-slot='" +
                        escAttr(String(i)) +
                        "'>" +
                        (childHtml ||
                            "<div class='h4bs-section-empty'>Drop elements in this column</div>") +
                        "</div>" +
                    "</div>"
                );
            }
            return (
                open +
                toolbar +
                backgroundVideoPreview(settings) +
                "<div class='h4bs-preview-section-grid is-" +
                escAttr(sectionCtx.modeClass) +
                "' style='" +
                escAttr(sectionCtx.style) +
                "'>" +
                columnsHtml.join("") +
                "</div>" +
                close
            );
        }

        if (block.type === "heading") {
            const tag = sanitizeHeadingTag(String(settings.tag || "h2"));
            return (
                open +
                toolbar +
                "<" +
                tag +
                " class='h4bs-preview-heading' data-h4bs-inline-edit='1' data-h4bs-inline-key='text' data-h4bs-inline-block='" +
                escAttr(blockId) +
                "'>" +
                escHtml(String(settings.text || "Heading")) +
                "</" +
                tag +
                ">" +
                close
            );
        }
        if (block.type === "text") {
            return (
                open +
                toolbar +
                "<p data-h4bs-inline-edit='1' data-h4bs-inline-key='text' data-h4bs-inline-block='" +
                escAttr(blockId) +
                "'>" +
                escHtml(String(settings.text || "")) +
                "</p>" +
                close
            );
        }
        if (block.type === "image") {
            const src = String(settings.src || settings.url || "");
            const alt = escAttr(String(settings.alt || ""));
            const title = escAttr(String(settings.title || ""));
            const caption = String(settings.caption || "");
            const align = String(settings.align || "none");
            const objectFit = cssSafeToken(settings.object_fit || "cover");
            const imgWidth = cssDimension(
                settings.width || "",
                settings.width_unit || "%",
                ""
            );
            const imgMaxWidth = cssDimension(
                settings.max_width || "",
                settings.max_width_unit || "px",
                ""
            );
            const imgHeight = cssDimension(
                settings.height || "",
                settings.height_unit || "px",
                ""
            );
            const imgRadius = cssDimension(
                settings.border_radius || "",
                settings.border_radius_unit || "px",
                ""
            );
            const imgShadow = cssSafeToken(settings.box_shadow || "");
            const hoverScale = cssSafeToken(settings.hover_scale || "");
            const overlayGradient = overlayColorLayer(
                String(settings.overlay_color || ""),
                clampOpacity(settings.overlay_opacity || 0)
            );
            const enableLightbox = toBool(settings.lightbox || "0", false);
            const intrinsicWidth = Math.max(0, Math.round(Number(settings.intrinsic_width || 0)));
            const intrinsicHeight = Math.max(0, Math.round(Number(settings.intrinsic_height || 0)));
            let loading = String(settings.loading || "auto").toLowerCase();
            if (["auto", "eager", "lazy"].indexOf(loading) < 0) {
                loading = "auto";
            }
            const firstImage = state.layout.find(function (candidate) {
                return candidate && candidate.type === "image";
            });
            const automaticHeaderPriority =
                loading === "auto" &&
                state.isTemplate &&
                String((state.templateConditions || {}).role || "") === "header" &&
                firstImage &&
                String(firstImage.id || "") === blockId;
            const effectiveLoading = loading === "auto"
                ? (automaticHeaderPriority ? "eager" : "lazy")
                : loading;
            const imgStyles = [];
            if (imgHeight) {
                imgStyles.push("height:100%");
            }
            if (objectFit) {
                imgStyles.push("object-fit:" + objectFit);
            }
            if (imgRadius) {
                imgStyles.push("border-radius:" + imgRadius);
            }
            if (imgShadow) {
                imgStyles.push("box-shadow:" + imgShadow);
            }
            if (hoverScale) {
                imgStyles.push("--h4bs-image-hover-scale:" + hoverScale);
            }
            const innerStyles = [];
            if (imgWidth) {
                innerStyles.push("width:" + imgWidth);
            } else if (intrinsicWidth > 0) {
                innerStyles.push("width:min(100%," + intrinsicWidth + "px)");
            }
            innerStyles.push("max-width:" + (imgMaxWidth || "100%"));
            if (imgHeight) {
                innerStyles.push("height:" + imgHeight);
            } else if (intrinsicWidth > 0 && intrinsicHeight > 0) {
                innerStyles.push("aspect-ratio:" + intrinsicWidth + " / " + intrinsicHeight);
            }
            const figureStyles = [];
            if (align === "left") {
                figureStyles.push("text-align:left");
            } else if (align === "center") {
                figureStyles.push("text-align:center");
            } else if (align === "right") {
                figureStyles.push("text-align:right");
            }
            if (!src) {
                return open + toolbar + "<div class='h4bs-preview-shortcode'>Image block (set URL in popup settings)</div>" + close;
            }
            const imageTag =
                "<img class='h4bs-preview-image' src='" +
                escAttr(src) +
                "' alt='" +
                alt +
                "' title='" +
                title +
                "'" +
                " loading='" + escAttr(effectiveLoading) + "' decoding='async'" +
                (effectiveLoading === "eager" ? " fetchpriority='high'" : "") +
                (intrinsicWidth > 0 && intrinsicHeight > 0
                    ? " width='" + intrinsicWidth + "' height='" + intrinsicHeight + "'"
                    : "") +
                (imgStyles.length ? " style='" + escAttr(imgStyles.join(";")) + "'" : "") +
                ">";
            const imageInner = enableLightbox
                ? "<a class='h4bs-preview-image-link' href='" +
                  escAttr(src) +
                  "' target='_blank' rel='noopener'>" +
                  imageTag +
                  "</a>"
                : imageTag;
            const overlayTag =
                overlayGradient !== ""
                    ? "<span class='h4bs-preview-image-overlay' style='background-image:" +
                      escAttr(overlayGradient) +
                      ";'></span>"
                    : "";
            const captionTag =
                caption !== ""
                    ? "<figcaption class='h4bs-preview-image-caption'>" +
                      escHtml(caption) +
                      "</figcaption>"
                    : "";
            return (
                open +
                toolbar +
                "<figure class='h4bs-preview-image-wrap'" +
                (figureStyles.length
                    ? " style='" + escAttr(figureStyles.join(";")) + "'"
                    : "") +
                ">" +
                "<span class='h4bs-preview-image-inner'" +
                (innerStyles.length ? " style='" + escAttr(innerStyles.join(";")) + "'" : "") +
                (intrinsicWidth > 0 && intrinsicHeight > 0
                    ? " data-h4bs-image-reserved='" + intrinsicWidth + "x" + intrinsicHeight + "'"
                    : "") +
                " data-h4bs-image-loading='" + (automaticHeaderPriority ? "header-auto" : effectiveLoading) + "'>" +
                imageInner +
                overlayTag +
                "</span>" +
                captionTag +
                "</figure>" +
                close
            );
        }
        if (block.type === "button") {
            const buttonStyle = previewDesignStyle(
                buttonElementDesignSettings(activeDesignSettings)
            );
            return (
                open +
                toolbar +
                "<a class='h4bs-preview-button' href='" +
                escAttr(String(settings.url || "#")) +
                "'" +
                (String(settings.target || "same") === "new"
                    ? " target='_blank' rel='noopener noreferrer'"
                    : String(settings.rel || "").trim() !== ""
                    ? " rel='" + escAttr(String(settings.rel || "")) + "'"
                    : "") +
                (buttonStyle !== ""
                    ? " style='" + escAttr(buttonStyle) + "'"
                    : "") +
                ">" +
                "<span data-h4bs-inline-edit='1' data-h4bs-inline-key='label' data-h4bs-inline-block='" +
                escAttr(blockId) +
                "'>" +
                escHtml(String(settings.label || "Button")) +
                "</span>" +
                "</a>" +
                close
            );
        }
        if (block.type === "shortcode") {
            return (
                open +
                toolbar +
                "<div class='h4bs-preview-shortcode'>Shortcode: " +
                escHtml(String(settings.shortcode || "")) +
                "</div>" +
                close
            );
        }
        if (block.type === "product_reviews") {
            const productId = Math.max(0, Number(settings.product_id || 0) || 0);
            const limit = Math.max(1, Math.min(20, Number(settings.limit || 5) || 5));
            const showForm = toBool(settings.show_form, true);
            const showSummary = toBool(settings.show_summary, true);
            const title = String(settings.title || "").trim();
            const emptyText = String(settings.empty_text || "").trim();
            return (
                open +
                toolbar +
                "<div class='h4bs-preview-widget-card h4bs-preview-widget-reviews'>" +
                "<h4>Product Reviews Widget</h4>" +
                "<p><strong>Product ID:</strong> " +
                escHtml(String(Math.round(productId))) +
                " | <strong>Items:</strong> " +
                escHtml(String(Math.round(limit))) +
                "</p>" +
                "<p><strong>Title:</strong> " +
                escHtml(title !== "" ? title : "(none)") +
                " | <strong>Summary:</strong> " +
                escHtml(showSummary ? "Shown" : "Hidden") +
                "</p>" +
                "<p><strong>Submit Form:</strong> " +
                escHtml(showForm ? "Enabled" : "Hidden") +
                "</p>" +
                "<p><strong>Empty Message:</strong> " +
                escHtml(emptyText !== "" ? emptyText : "No reviews yet.") +
                "</p>" +
                "<small>Uses verified customer review pipeline.</small>" +
                "</div>" +
                close
            );
        }
        if (block.type === "google_business") {
            const view = String(settings.view || "business").toLowerCase();
            const domain = String(settings.domain || "").trim() || "(current site domain)";
            const reviews = Math.max(1, Math.min(10, Number(settings.reviews || 5) || 5));
            const location = Math.max(1, Number(settings.location || 1) || 1);
            const mapHeight = Math.max(220, Math.min(900, Number(settings.height || 360) || 360));
            const showMap = toBool(settings.show_map, true);
            const showReviews = toBool(settings.show_reviews, true);
            const showHeader = toBool(settings.show_header, true);
            const showAggregate = toBool(settings.show_aggregate, true);
            const showServiceAreas = toBool(settings.show_service_areas, true);
            const emptyText = String(settings.empty_text || "").trim();
            return (
                open +
                toolbar +
                "<div class='h4bs-preview-widget-card h4bs-preview-widget-gmb'>" +
                "<h4>Google Business Widget</h4>" +
                "<p><strong>Domain:</strong> " +
                escHtml(domain) +
                "</p>" +
                "<p><strong>Mode:</strong> " +
                escHtml(view) +
                " | <strong>Reviews:</strong> " +
                escHtml(String(Math.round(reviews))) +
                "</p>" +
                "<p><strong>Location:</strong> #" +
                escHtml(String(Math.round(location))) +
                " | <strong>Map Height:</strong> " +
                escHtml(String(Math.round(mapHeight))) +
                "px</p>" +
                "<p><strong>Map:</strong> " +
                escHtml(showMap ? "On" : "Off") +
                " | <strong>Reviews:</strong> " +
                escHtml(showReviews ? "On" : "Off") +
                "</p>" +
                "<p><strong>Header:</strong> " +
                escHtml(showHeader ? "On" : "Off") +
                " | <strong>Aggregate:</strong> " +
                escHtml(showAggregate ? "On" : "Off") +
                "</p>" +
                "<p><strong>Service Areas:</strong> " +
                escHtml(showServiceAreas ? "On" : "Off") +
                "</p>" +
                "<p><strong>Empty Message:</strong> " +
                escHtml(
                    emptyText !== ""
                        ? emptyText
                        : "Google Business profile not configured for this domain yet."
                ) +
                "</p>" +
                "<small>Domain-based Google profile mapping (shared-host safe).</small>" +
                "</div>" +
                close
            );
        }
        if (block.type === "slider") {
            const fit = String(settings.fit || "contain");
            const snapshotFit = String(settings.snapshot_fit || settings.siteshot_fit || "contain");
            const bg = String(settings.bg || "#0b1118");
            const heightMode = String(settings.height_mode || "fixed");
            const heightPx = Math.max(120, Math.min(2160, Number(settings.height_px || 540) || 540));
            const transition = String(settings.transition || "slide");
            const motion = String(settings.motion || "none");
            const motionForce = toBool(settings.motion_force, false);
            const autoplay = Math.max(0, Math.min(60000, Number(settings.autoplay || 4500) || 4500));
            return (
                open +
                toolbar +
                "<div class='h4bs-preview-slider'>Slider #" +
                escHtml(String(settings.slider_id || "0")) +
                "<br><small>Fit: " +
                escHtml(fit) +
                " | Height: " +
                escHtml(heightMode === "auto" ? "Auto" : String(heightPx) + "px") +
                " | Transition: " +
                escHtml(transition) +
                " | Motion: " +
                escHtml(motion) +
                " (" +
                escHtml(motionForce ? "forced" : "safe") +
                ")" +
                " | Snapshot Fit: " +
                escHtml(snapshotFit) +
                " | Fill: " +
                escHtml(bg) +
                " | Autoplay: " +
                escHtml(String(autoplay)) +
                "ms</small>" +
                "</div>" +
                close
            );
        }
        if (block.type === "html") {
            const safeHtml = sanitizeHtmlPreview(String(settings.html || ""));
            const htmlOutput =
                safeHtml !== ""
                    ? safeHtml
                    : "<em>Add HTML markup in element settings.</em>";
            return (
                open +
                toolbar +
                "<div class='h4bs-preview-html'>" +
                htmlOutput +
                "</div>" +
                close
            );
        }
        if (block.type === "spacer") {
            const px = Math.max(4, Math.min(320, Number(settings.height || 24)));
            return open + toolbar + "<div style='height:" + String(px) + "px'></div>" + close;
        }
        if (block.type === "divider") {
            const thickness = Math.max(1, Math.min(24, Number(settings.thickness || 1)));
            const style = String(settings.style || "solid");
            const color = String(settings.color || "#dbe7f3");
            return (
                open +
                toolbar +
                "<hr class='h4bs-preview-divider' style='border:0;border-top:" +
                escAttr(String(thickness)) +
                "px " +
                escAttr(style) +
                " " +
                escAttr(color) +
                ";'>" +
                close
            );
        }
        if (block.type === "video") {
            const src = String(settings.src || settings.media_src || "");
            const provider = String(settings.provider || "youtube");
            const height = Math.max(180, Math.min(1080, Number(settings.height || 360)));
            const hlsSrc = String(settings.hls_src || (provider === "hls" ? src : ""));
            const primarySrc = provider === "hls" ? "" : src;
            const fallbackVideo = String(
                settings.fallback_src ||
                    settings.fallback_media_src ||
                    (provider === "hls" ? settings.media_src || "" : "")
            );
            const poster = String(settings.poster_src || settings.poster_media_src || settings.poster || "");
            const fallbackImage = String(
                settings.fallback_image_src || settings.fallback_image_media_src || poster
            );
            if (!src && !hlsSrc) {
                return open + toolbar + "<div class='h4bs-preview-shortcode'>Video block (set URL in popup settings)</div>" + close;
            }
            if (provider === "youtube") {
                const embed = youtubeEmbedUrl(
                    src,
                    toBool(settings.autoplay, false),
                    toBool(settings.controls, true),
                    toBool(settings.muted, false),
                    toBool(settings.loop, false)
                );
                if (!embed) {
                    return open + toolbar + "<div class='h4bs-preview-shortcode'>Invalid YouTube URL/ID.</div>" + close;
                }
                return (
                    open +
                    toolbar +
                    "<iframe class='h4bs-preview-video-embed' src='" +
                    escAttr(embed) +
                    "' style='width:100%;height:" +
                    escAttr(String(height)) +
                    "px;' loading='lazy' allowfullscreen></iframe>" +
                    close
                );
            }
            if (provider === "vimeo") {
                const embed = vimeoEmbedUrl(
                    src,
                    toBool(settings.autoplay, false),
                    toBool(settings.controls, true),
                    toBool(settings.muted, false),
                    toBool(settings.loop, false)
                );
                if (!embed) {
                    return open + toolbar + "<div class='h4bs-preview-shortcode'>Invalid Vimeo URL/ID.</div>" + close;
                }
                return (
                    open +
                    toolbar +
                    "<iframe class='h4bs-preview-video-embed' src='" +
                    escAttr(embed) +
                    "' style='width:100%;height:" +
                    escAttr(String(height)) +
                    "px;' loading='lazy' allowfullscreen></iframe>" +
                    close
                );
            }
            if (provider === "embed") {
                return (
                    open +
                    toolbar +
                    "<iframe class='h4bs-preview-video-embed' src='" +
                    escAttr(src) +
                    "' style='width:100%;height:" +
                    escAttr(String(height)) +
                    "px;' loading='lazy' allowfullscreen></iframe>" +
                    close
                );
            }
            const attrs = [
                toBool(settings.controls, true) ? "controls" : "",
                toBool(settings.autoplay, false) ? "autoplay" : "",
                toBool(settings.autoplay, false) || toBool(settings.muted, false) ? "muted" : "",
                toBool(settings.loop, false) ? "loop" : "",
                "playsinline",
                "preload='" + escAttr(String(settings.preload || "metadata")) + "'",
                "aria-label='" + escAttr(String(settings.title || "Video player")) + "'",
                "data-h4bs-video-player",
                hlsSrc ? "data-h4bs-hls='" + escAttr(hlsSrc) + "'" : "",
                primarySrc ? "data-h4bs-primary-video='" + escAttr(primarySrc) + "'" : "",
                fallbackVideo
                    ? "data-h4bs-fallback-video='" + escAttr(fallbackVideo) + "'"
                    : "",
                fallbackImage
                    ? "data-h4bs-fallback-image='" + escAttr(fallbackImage) + "'"
                    : "",
                poster ? "poster='" + escAttr(poster) + "'" : "",
            ]
                .filter(Boolean)
                .join(" ");
            const ratioMap = {
                "16:9": "16 / 9",
                "4:3": "4 / 3",
                "1:1": "1 / 1",
                "9:16": "9 / 16",
                "21:9": "21 / 9",
            };
            const ratio = ratioMap[String(settings.aspect_ratio || "16:9")] || ratioMap["16:9"];
            const previewVideoMime = function (url) {
                const path = String(url || "")
                    .split(/[?#]/)[0]
                    .toLowerCase();
                if (path.endsWith(".webm")) {
                    return "video/webm";
                }
                if (path.endsWith(".ogv") || path.endsWith(".ogg")) {
                    return "video/ogg";
                }
                if (path.endsWith(".m4v")) {
                    return "video/x-m4v";
                }
                return "video/mp4";
            };
            const sources =
                (hlsSrc
                    ? "<source src='" +
                      escAttr(hlsSrc) +
                      "' type='application/vnd.apple.mpegurl'>"
                    : "") +
                (primarySrc
                    ? "<source src='" +
                      escAttr(primarySrc) +
                      "' type='" +
                      previewVideoMime(primarySrc) +
                      "'>"
                    : "") +
                (fallbackVideo && fallbackVideo !== primarySrc
                    ? "<source src='" +
                      escAttr(fallbackVideo) +
                      "' type='" +
                      previewVideoMime(fallbackVideo) +
                      "'>"
                    : "");
            return (
                open +
                toolbar +
                "<div class='h4bs-video-player-shell' data-h4bs-module='video' data-h4bs-skin='surface' style='--h4bs-video-aspect:" +
                escAttr(ratio) +
                ";--h4bs-video-max-height:" +
                escAttr(String(height)) +
                "px'><video class='h4bs-preview-video' " +
                attrs +
                ">" +
                sources +
                "Your browser cannot play this video.</video>" +
                "<div class='h4bs-video-player-fallback' data-h4bs-video-fallback hidden>" +
                (fallbackImage
                    ? "<img src='" + escAttr(fallbackImage) + "' alt='' loading='lazy'>"
                    : "") +
                "<p role='status'>Video playback is unavailable.</p>" +
                (fallbackVideo || primarySrc || hlsSrc
                    ? "<a href='" +
                      escAttr(fallbackVideo || primarySrc || hlsSrc) +
                      "' target='_blank' rel='noopener'>Open the fallback video</a>"
                    : "") +
                "</div></div>" +
                close
            );
        }
        if (block.type === "icon") {
            const iconSet = String(settings.icon_set || "dashicons");
            const iconClass = String(settings.icon || "dashicons-star-filled");
            const faClass = String(settings.fa_class || "fa-solid fa-star");
            const color = String(settings.color || "#0f6cbf");
            const size = Math.max(12, Math.min(160, Number(settings.size || 28)));
            const label = String(settings.label || "");
            const iconHtml =
                iconSet === "fontawesome"
                    ? "<i class='" +
                      escAttr(faClass) +
                      " h4bs-preview-icon' style='color:" +
                      escAttr(color) +
                      ";font-size:" +
                      escAttr(String(size)) +
                      "px;'></i>"
                    : "<span class='dashicons " +
                      escAttr(iconClass) +
                      " h4bs-preview-icon' style='color:" +
                      escAttr(color) +
                      ";font-size:" +
                      escAttr(String(size)) +
                      "px;width:" +
                      escAttr(String(size)) +
                      "px;height:" +
                      escAttr(String(size)) +
                      "px;'></span>";
            return (
                open +
                toolbar +
                "<div class='h4bs-preview-icon-wrap'>" +
                iconHtml +
                (label ? "<span class='h4bs-preview-icon-label'>" + escHtml(label) + "</span>" : "") +
                "</div>" +
                close
            );
        }
        if (block.type === "list") {
            const items = splitTextItems(String(settings.items || ""));
            const ordered = toBool(settings.ordered, false);
            if (!items.length) {
                return open + toolbar + "<div class='h4bs-preview-shortcode'>List block (add items in popup settings)</div>" + close;
            }
            const tag = ordered ? "ol" : "ul";
            const itemsHtml = items
                .map(function (item) {
                    return "<li>" + escHtml(item) + "</li>";
                })
                .join("");
            return open + toolbar + "<" + tag + " class='h4bs-preview-list'>" + itemsHtml + "</" + tag + ">" + close;
        }
        if (block.type === "quote") {
            const quoteText = String(settings.text || "");
            const cite = String(settings.cite || "");
            return (
                open +
                toolbar +
                "<blockquote class='h4bs-preview-quote'>" +
                "<p>" +
                escHtml(quoteText || "Quote text") +
                "</p>" +
                (cite ? "<cite>" + escHtml(cite) + "</cite>" : "") +
                "</blockquote>" +
                close
            );
        }
        if (block.type === "cta") {
            const headingTag = sanitizeCtaHeadingTag(String(settings.heading_tag || "h3"));
            return (
                open +
                toolbar +
                "<div class='h4bs-preview-cta'>" +
                "<" + headingTag + ">" +
                escHtml(String(settings.title || "Call To Action")) +
                "</" + headingTag + ">" +
                "<p>" +
                escHtml(String(settings.text || "")) +
                "</p>" +
                "<a class='h4bs-preview-button' href='" +
                escAttr(String(settings.button_url || "#")) +
                "'" +
                (String(settings.button_target || "same") === "new"
                    ? " target='_blank' rel='noopener noreferrer'"
                    : String(settings.button_rel || "").trim() !== ""
                    ? " rel='" + escAttr(String(settings.button_rel || "")) + "'"
                    : "") +
                ">" +
                escHtml(String(settings.button_label || "Learn More")) +
                "</a>" +
                "</div>" +
                close
            );
        }
        if (block.type === "gallery") {
            const urls = splitCsvItems(String(settings.images || ""));
            const columns = Math.max(
                1,
                Math.min(MAX_COLUMNS, Number(settings.columns || 3))
            );
            if (!urls.length) {
                return open + toolbar + "<div class='h4bs-preview-shortcode'>Gallery block (add image URLs in popup settings)</div>" + close;
            }
            const cells = urls
                .map(function (url) {
                    return (
                        "<figure><img src='" +
                        escAttr(url) +
                        "' alt='" +
                        escAttr(galleryAltFromUrl(url)) +
                        "' loading='lazy'></figure>"
                    );
                })
                .join("");
            return (
                open +
                toolbar +
                "<div class='h4bs-preview-gallery' style='grid-template-columns:repeat(" +
                escAttr(String(columns)) +
                ",minmax(0,1fr));'>" +
                cells +
                "</div>" +
                close
            );
        }
        if (block.type === "map") {
            const embedUrl = String(settings.embed_url || "").replace(/%2C/gi, ",");
            const height = Math.max(180, Math.min(1080, Number(settings.height || 360)));
            if (!embedUrl) {
                return open + toolbar + "<div class='h4bs-preview-shortcode'>Map block (set embed URL in popup settings)</div>" + close;
            }
            return (
                open +
                toolbar +
                "<iframe class='h4bs-preview-map' src='" +
                escAttr(embedUrl) +
                "' style='width:100%;height:" +
                escAttr(String(height)) +
                "px;' loading='lazy' allowfullscreen></iframe>" +
                close
            );
        }
        if (block.type === "faq") {
            const items = parseFaqItems(String(settings.items || ""));
            const openFirst = toBool(settings.open_first, false);
            if (!items.length) {
                return open + toolbar + "<div class='h4bs-preview-shortcode'>FAQ block (add Question::Answer lines in popup settings)</div>" + close;
            }
            const faqHtml = items
                .map(function (item, index) {
                    return (
                        "<details " +
                        (openFirst && index === 0 ? "open" : "") +
                        "><summary>" +
                        escHtml(item.q) +
                        "</summary><p>" +
                        escHtml(item.a) +
                        "</p></details>"
                    );
                })
                .join("");
            return open + toolbar + "<div class='h4bs-preview-faq'>" + faqHtml + "</div>" + close;
        }
        if (block.type === "collection") {
            const items = Array.isArray(settings.items) ? settings.items : [];
            const columns = Math.max(1, Math.min(6, Number(settings.columns || 3)));
            const cards = items.map(function (item) {
                if (!item || typeof item !== "object" || !String(item.title || "").trim()) return "";
                return "<article class='h4bs-collection-item'>" +
                    (item.badge ? "<span class='h4bs-collection-badge'>" + escHtml(String(item.badge)) + "</span>" : "") +
                    "<h3>" + escHtml(String(item.title)) + "</h3>" +
                    (item.description ? "<p>" + escHtml(String(item.description)) + "</p>" : "") + "</article>";
            }).join("");
            return open + toolbar + "<div class='h4bs-collection is-" + escAttr(String(settings.default_view || "grid")) + "' style='--h4bs-collection-columns:" + columns + "'><div class='h4bs-collection-view-switch'><button type='button' aria-pressed='true'>" + escHtml(String(settings.grid_label || "Grid by group")) + "</button><button type='button' aria-pressed='false'>" + escHtml(String(settings.list_label || "Filterable list")) + "</button></div><div class='h4bs-collection-results'>" + cards + "</div></div>" + close;
        }
        if (block.type === "calendar") {
            return open + toolbar + "<div class='h4bs-calendar-view is-" + escAttr(String(settings.presentation || "calendar")) + "'><div class='h4bs-preview-shortcode'>Calendar preview loads the saved source and local event workspace.</div></div>" + close;
        }
        if (block.type === "staff_directory") {
            return open + toolbar + "<div class='h4bs-staff-directory'><div class='h4bs-preview-shortcode'>Staff Directory preview loads published profiles, hierarchy, portraits, and responsive priorities from the staff workspace.</div></div>" + close;
        }
        if (block.type === "counter") {
            const value = Number(settings.value || 0);
            const counterText =
                String(settings.prefix || "") +
                String(Number.isFinite(value) ? Math.round(value) : 0) +
                String(settings.suffix || "");
            return (
                open +
                toolbar +
                "<div class='h4bs-preview-counter'>" +
                "<strong>" +
                escHtml(counterText) +
                "</strong>" +
                "<span>" +
                escHtml(String(settings.label || "")) +
                "</span>" +
                "</div>" +
                close
            );
        }
        if (block.type === "progress") {
            const max = Math.max(1, Number(settings.max || 100));
            const value = Math.max(0, Math.min(max, Number(settings.value || 0)));
            const percent = Math.max(0, Math.min(100, Math.round((value / max) * 100)));
            return (
                open +
                toolbar +
                "<div class='h4bs-preview-progress'>" +
                "<div class='h4bs-preview-progress-head'>" +
                "<span>" +
                escHtml(String(settings.label || "Progress")) +
                "</span>" +
                "<span>" +
                escHtml(String(percent)) +
                "%</span>" +
                "</div>" +
                "<div class='h4bs-preview-progress-track'><i style='width:" +
                escAttr(String(percent)) +
                "%;'></i></div>" +
                "</div>" +
                close
            );
        }
        if (block.type === "menu") {
            const orientation = String(settings.orientation || "horizontal");
            const slug = String(settings.menu_slug || "");
            const dropdown = String(settings.dropdown_mode || "hover");
            const hamburger = toBool(settings.mobile_hamburger, true);
            const label = String(settings.menu_label || "Site Menu");
            return (
                open +
                toolbar +
                "<nav class='h4bs-preview-menu h4bs-builder-menu is-" +
                escAttr(orientation) +
                " has-dropdown-" +
                escAttr(dropdown) +
                (hamburger ? " has-mobile-hamburger" : "") +
                "'>" +
                (hamburger
                    ? "<button type='button' class='h4bs-builder-menu-toggle'><span class='h4bs-builder-menu-toggle-icon'><i></i><i></i><i></i></span><span class='h4bs-builder-menu-toggle-label'>" +
                      escHtml(label) +
                      "</span></button>"
                    : "") +
                (slug
                    ? "<span>WP menu slug: " + escHtml(slug) + "</span>"
                    : "<span>Set a WordPress menu slug in popup settings.</span>") +
                "</nav>" +
                close
            );
        }
        if (block.type === "container") {
            const structureDefaults = structureLayoutDefaults();
            const containerCtx = sectionLayoutContext(settings, {
                columns: structureDefaults.columns,
                gap: structureDefaults.gap,
                minHeight: structureDefaults.min_height,
                minHeightMin: 60,
                minHeightMax: 1800,
                layoutMode: structureDefaults.layout_mode,
                contentWidthMode: structureDefaults.content_width_mode,
                flexDirection: structureDefaults.flex_direction,
                flexWrap: structureDefaults.flex_wrap,
                justifyContent: structureDefaults.justify_content,
                alignItems: structureDefaults.align_items,
                alignContent: structureDefaults.align_content,
            });
            const columns = containerCtx.columns;
            const labels = splitTextItems(
                String(settings.column_labels || "Column 1|Column 2")
            );
            const note = String(settings.note || "").trim();
            const cells = [];
            for (let i = 0; i < columns; i += 1) {
                const label = labels[i] || "Column " + String(i + 1);
                const columnStyle = columnStyleForLayoutMode(
                    containerCtx.modeClass,
                    containerCtx.columnWidths,
                    i
                );
                const columnStyleAttr =
                    columnStyle !== ""
                        ? " style='" + escAttr(columnStyle) + "'"
                        : "";
                const childHtml = childrenForSection(blockId, i)
                    .map(function (child) {
                        return previewBlock(blockWithDraft(child));
                    })
                    .join("");
                cells.push(
                    "<div class='h4bs-preview-section-col'" + columnStyleAttr + ">" +
                        "<div class='h4bs-section-col-label'>" +
                        escHtml(label) +
                        "</div>" +
                        "<div class='h4bs-section-dropzone' data-h4bs-section-dropzone='1' data-h4bs-parent='" +
                        escAttr(blockId) +
                        "' data-h4bs-slot='" +
                        escAttr(String(i)) +
                        "'>" +
                        (childHtml ||
                            "<div class='h4bs-section-empty'>Drop elements in this column</div>") +
                        "</div>" +
                    "</div>"
                );
            }
            return (
                open +
                toolbar +
                backgroundVideoPreview(settings) +
                "<div class='h4bs-preview-container is-" +
                escAttr(containerCtx.modeClass) +
                "' style='" +
                escAttr(containerCtx.style) +
                "'>" +
                (note !== ""
                    ? "<div class='h4bs-preview-container-note'>" +
                      escHtml(note) +
                      "</div>"
                    : "") +
                cells.join("") +
                "</div>" +
                close
            );
        }
        if (block.type === "inner_section") {
            const structureDefaults = structureLayoutDefaults();
            const innerCtx = sectionLayoutContext(settings, {
                columns: structureDefaults.columns,
                gap: structureDefaults.gap,
                minHeight: structureDefaults.min_height,
                minHeightMin: 60,
                minHeightMax: 1800,
                layoutMode: structureDefaults.layout_mode,
                contentWidthMode: structureDefaults.content_width_mode,
                flexDirection: structureDefaults.flex_direction,
                flexWrap: structureDefaults.flex_wrap,
                justifyContent: structureDefaults.justify_content,
                alignItems: structureDefaults.align_items,
                alignContent: structureDefaults.align_content,
            });
            const columns = innerCtx.columns;
            const labels = splitTextItems(String(settings.column_labels || "Column 1|Column 2"));
            const cells = [];
            for (let i = 0; i < columns; i += 1) {
                const label = labels[i] || ("Column " + String(i + 1));
                const columnStyle = columnStyleForLayoutMode(
                    innerCtx.modeClass,
                    innerCtx.columnWidths,
                    i
                );
                const columnStyleAttr =
                    columnStyle !== ""
                        ? " style='" + escAttr(columnStyle) + "'"
                        : "";
                const childHtml = childrenForSection(blockId, i)
                    .map(function (child) {
                        return previewBlock(blockWithDraft(child));
                    })
                    .join("");
                cells.push(
                    "<div class='h4bs-preview-inner-col'" + columnStyleAttr + ">" +
                        "<div class='h4bs-section-col-label'>" +
                        escHtml(label) +
                        "</div>" +
                        "<div class='h4bs-section-dropzone h4bs-inner-section-dropzone' data-h4bs-section-dropzone='1' data-h4bs-parent='" +
                        escAttr(blockId) +
                        "' data-h4bs-slot='" +
                        escAttr(String(i)) +
                        "'>" +
                        (childHtml ||
                            "<div class='h4bs-section-empty'>Drop elements in this inner column</div>") +
                        "</div>" +
                    "</div>"
                );
            }
            return (
                open +
                toolbar +
                "<div class='h4bs-preview-inner-section is-" +
                escAttr(innerCtx.modeClass) +
                "' style='" +
                escAttr(innerCtx.style) +
                "'>" +
                cells.join("") +
                "</div>" +
                close
            );
        }
        return "";
    }

    function bindPreviewInteractions() {
        if (!els.previewCanvas) {
            return;
        }
        if (!els.previewCanvas.dataset.h4bsInteractionsBound) {
            els.previewCanvas.addEventListener("click", function (event) {
                const target = event.target;
                if (!(target instanceof HTMLElement)) {
                    return;
                }
                const actionNode = target.closest("[data-h4bs-preview-action]");
                if (state.previewDragging && !(actionNode instanceof HTMLElement)) {
                    return;
                }
                if (state.parityMode) {
                    return;
                }
                if (target.closest(".h4bs-preview-drag")) {
                    return;
                }

                const action = actionNode
                    ? String(actionNode.getAttribute("data-h4bs-preview-action") || "")
                    : "";
                let blockNode = resolvePreviewBlockFromTarget(target, event);
                if (
                    actionNode instanceof HTMLElement &&
                    action !== ""
                ) {
                    const actionBlockNode = actionNode.closest(
                        "[data-h4bs-preview-block]"
                    );
                    if (
                        actionBlockNode instanceof HTMLElement &&
                        els.previewCanvas.contains(actionBlockNode)
                    ) {
                        blockNode = actionBlockNode;
                    }
                }
                if (
                    !(blockNode instanceof HTMLElement) ||
                    !els.previewCanvas.contains(blockNode)
                ) {
                    return;
                }
                const blockId = String(
                    blockNode.getAttribute("data-h4bs-preview-block") || ""
                );
                if (blockId === "") {
                    return;
                }
                const htmlQuickEditTarget = describeHtmlQuickEditTarget(
                    blockNode,
                    target
                );
                if (action === "delete") {
                    event.preventDefault();
                    if (state.previewClickTimer) {
                        window.clearTimeout(state.previewClickTimer);
                        state.previewClickTimer = null;
                    }
                    deleteBlock(blockId);
                    return;
                }
                if (action === "duplicate") {
                    event.preventDefault();
                    if (state.previewClickTimer) {
                        window.clearTimeout(state.previewClickTimer);
                        state.previewClickTimer = null;
                    }
                    duplicateBlock(blockId);
                    return;
                }
                if (action === "edit") {
                    event.preventDefault();
                    if (state.previewClickTimer) {
                        window.clearTimeout(state.previewClickTimer);
                        state.previewClickTimer = null;
                    }
                    state.selectedId = blockId;
                    renderBlockList();
                    openBlockModal(blockId);
                    return;
                }

                event.preventDefault();
                if (state.previewClickTimer) {
                    window.clearTimeout(state.previewClickTimer);
                    state.previewClickTimer = null;
                }
                if (event.detail > 1) {
                    return;
                }
                state.previewClickTimer = window.setTimeout(function () {
                    state.selectedId = blockId;
                    renderBlockList();
                    openBlockModal(blockId, {
                        htmlQuickEditTarget: htmlQuickEditTarget,
                    });
                    state.previewClickTimer = null;
                }, 180);
            });

            els.previewCanvas.addEventListener("dblclick", function (event) {
                if (state.parityMode) {
                    return;
                }
                const target = event.target;
                if (!(target instanceof HTMLElement)) {
                    return;
                }
                const editable = target.closest("[data-h4bs-inline-edit]");
                if (
                    !(editable instanceof HTMLElement) ||
                    !els.previewCanvas.contains(editable)
                ) {
                    return;
                }
                event.preventDefault();
                event.stopPropagation();
                if (state.previewClickTimer) {
                    window.clearTimeout(state.previewClickTimer);
                    state.previewClickTimer = null;
                }
                beginInlineEdit(editable);
            });

            els.previewCanvas.addEventListener("contextmenu", function (event) {
                if (state.parityMode) {
                    closeContextMenu();
                    return;
                }
                const target = event.target;
                if (!(target instanceof HTMLElement)) {
                    return;
                }
                const blockNode = resolvePreviewBlockFromTarget(target, event);
                if (
                    !(blockNode instanceof HTMLElement) ||
                    !els.previewCanvas.contains(blockNode)
                ) {
                    closeContextMenu();
                    return;
                }
                const blockId = String(
                    blockNode.getAttribute("data-h4bs-preview-block") || ""
                );
                if (blockId === "") {
                    closeContextMenu();
                    return;
                }
                event.preventDefault();
                state.selectedId = blockId;
                renderBlockList();
                openContextMenu(
                    blockId,
                    Number(event.clientX || 0),
                    Number(event.clientY || 0)
                );
            });
            els.previewCanvas.dataset.h4bsInteractionsBound = "1";
        }
    }

    function resolvePreviewBlockFromTarget(target, event) {
        if (!(target instanceof HTMLElement) || !(els.previewCanvas instanceof HTMLElement)) {
            return null;
        }
        const actionNode = target.closest("[data-h4bs-preview-action]");
        if (actionNode instanceof HTMLElement) {
            const actionBlock = actionNode.closest("[data-h4bs-preview-block]");
            if (
                actionBlock instanceof HTMLElement &&
                els.previewCanvas.contains(actionBlock)
            ) {
                return actionBlock;
            }
        }
        const inlineNode = target.closest("[data-h4bs-inline-block]");
        if (inlineNode instanceof HTMLElement) {
            const inlineBlockId = String(
                inlineNode.getAttribute("data-h4bs-inline-block") || ""
            );
            if (inlineBlockId !== "") {
                const inlineBlockNode = findPreviewBlockNodeById(inlineBlockId);
                if (inlineBlockNode instanceof HTMLElement) {
                    return inlineBlockNode;
                }
            }
        }
        const candidates = [];
        const seen = new Set();
        const pushCandidate = function (node) {
            if (!(node instanceof HTMLElement)) {
                return;
            }
            const blockNode = node.closest("[data-h4bs-preview-block]");
            if (
                !(blockNode instanceof HTMLElement) ||
                !els.previewCanvas.contains(blockNode)
            ) {
                return;
            }
            const id = String(blockNode.getAttribute("data-h4bs-preview-block") || "");
            if (id !== "") {
                if (seen.has(id)) {
                    return;
                }
                seen.add(id);
            }
            candidates.push(blockNode);
        };

        if (
            event &&
            typeof document.elementsFromPoint === "function" &&
            Number.isFinite(Number(event.clientX)) &&
            Number.isFinite(Number(event.clientY))
        ) {
            const stack = document.elementsFromPoint(
                Number(event.clientX),
                Number(event.clientY)
            );
            for (let i = 0; i < stack.length; i += 1) {
                pushCandidate(stack[i]);
            }
        }

        pushCandidate(target);
        if (!candidates.length) {
            return null;
        }

        const depthOf = function (node) {
            let depth = 0;
            let current = node;
            while (current && current !== els.previewCanvas) {
                depth += 1;
                current = current.parentElement;
            }
            return depth;
        };

        candidates.sort(function (a, b) {
            return depthOf(b) - depthOf(a);
        });

        const nonContainerCandidate = candidates.find(function (node) {
            if (!(node instanceof HTMLElement)) {
                return false;
            }
            const blockId = String(node.getAttribute("data-h4bs-preview-block") || "");
            if (blockId === "") {
                return false;
            }
            const block = findBlockById(blockId);
            if (!block || typeof block !== "object") {
                return false;
            }
            return !isContainerType(String(block.type || ""));
        });
        if (nonContainerCandidate instanceof HTMLElement) {
            return nonContainerCandidate;
        }

        return candidates[0];
    }

    function beginInlineEdit(node) {
        if (!(node instanceof HTMLElement)) {
            return;
        }
        if (node.isContentEditable) {
            return;
        }

        const original = String(node.textContent || "");
        node.dataset.h4bsInlineOriginal = original;
        node.contentEditable = "true";
        node.classList.add("is-inline-editing");

        const range = document.createRange();
        range.selectNodeContents(node);
        range.collapse(false);
        const selection = window.getSelection();
        if (selection) {
            selection.removeAllRanges();
            selection.addRange(range);
        }

        const commit = function (keepChanges) {
            node.contentEditable = "false";
            node.classList.remove("is-inline-editing");
            node.removeEventListener("keydown", onKeyDown);
            if (!keepChanges) {
                node.textContent = original;
                return;
            }
            const blockId = String(node.getAttribute("data-h4bs-inline-block") || "");
            const key = String(node.getAttribute("data-h4bs-inline-key") || "");
            const value = String(node.textContent || "")
                .replace(/\n+/g, " ")
                .trim();
            if (blockId === "" || key === "") {
                return;
            }
            if (
                state.modalMode === "block" &&
                state.modalDraftBlock &&
                String(state.modalDraftBlock.id) === blockId
            ) {
                applyDraftBlockSettingChange(state.modalDraftBlock, key, value);
                return;
            }

            const realBlock = findBlockById(blockId);
            if (!realBlock) {
                return;
            }
            applyBlockSettingChange(realBlock, key, value);
        };

        const onKeyDown = function (event) {
            if (event.key === "Enter" && !event.shiftKey) {
                event.preventDefault();
                commit(true);
            } else if (event.key === "Escape") {
                event.preventDefault();
                commit(false);
            }
        };

        node.addEventListener("keydown", onKeyDown);
        node.addEventListener(
            "blur",
            function () {
                commit(true);
            },
            { once: true }
        );
        node.focus();
    }

    function layoutStructureSignature(layout) {
        if (!Array.isArray(layout)) {
            return "";
        }
        return layout
            .map(function (block) {
                const id = String(block && block.id ? block.id : "");
                const parentId = String(
                    block && typeof block.parent_id !== "undefined"
                        ? block.parent_id
                        : ""
                );
                const slot = normalizedSlot(
                    block && typeof block.slot !== "undefined" ? block.slot : 0
                );
                return id + "::" + parentId + "::" + String(slot);
            })
            .join("||");
    }

    function syncLayoutFromPreviewDom() {
        if (!els.previewCanvas) {
            return false;
        }

        const beforeSignature = layoutStructureSignature(state.layout);
        const snapshotBefore = historySnapshot();

        const order = [];
        const placement = {};
        const topNodes = Array.from(els.previewCanvas.children).filter(function (child) {
            return (
                child instanceof HTMLElement &&
                child.classList.contains("h4bs-preview-block") &&
                child.hasAttribute("data-h4bs-preview-block")
            );
        });

        topNodes.forEach(function (node) {
            const blockId = String(node.getAttribute("data-h4bs-preview-block") || "");
            if (blockId === "") {
                return;
            }
            order.push(blockId);
            placement[blockId] = { parent_id: "", slot: 0 };

            const blockType = inferBlockTypeFromNode(node);
            if (!isContainerType(blockType)) {
                return;
            }

            node.querySelectorAll("[data-h4bs-section-dropzone]").forEach(function (zone) {
                if (!(zone instanceof HTMLElement)) {
                    return;
                }
                const parentId = String(zone.getAttribute("data-h4bs-parent") || blockId);
                const slot = normalizedSlot(zone.getAttribute("data-h4bs-slot") || "0");
                Array.from(zone.children).forEach(function (childNode) {
                    if (
                        !(childNode instanceof HTMLElement) ||
                        !childNode.classList.contains("h4bs-preview-block") ||
                        !childNode.hasAttribute("data-h4bs-preview-block")
                    ) {
                        return;
                    }
                    const childId = String(
                        childNode.getAttribute("data-h4bs-preview-block") || ""
                    );
                    if (childId === "") {
                        return;
                    }
                    order.push(childId);
                    placement[childId] = { parent_id: parentId, slot: slot };
                });
            });
        });

        if (!order.length) {
            return false;
        }

        state.layout.forEach(function (block) {
            const id = String(block && block.id ? block.id : "");
            if (!id || !placement[id]) {
                return;
            }
            block.parent_id = String(placement[id].parent_id || "");
            block.slot = normalizedSlot(placement[id].slot || 0);
        });

        state.layout.forEach(function (block) {
            const id = String(block && block.id ? block.id : "");
            if (id !== "" && order.indexOf(id) < 0) {
                order.push(id);
            }
        });

        state.layout.sort(function (a, b) {
            return order.indexOf(String(a.id || "")) - order.indexOf(String(b.id || ""));
        });

        const afterSignature = layoutStructureSignature(state.layout);
        if (beforeSignature === afterSignature) {
            return false;
        }
        pushHistorySnapshot(snapshotBefore, true);
        return true;
    }

    function wireSectionSortables() {
        if (!els.previewCanvas) {
            return;
        }
        els.previewCanvas
            .querySelectorAll("[data-h4bs-section-dropzone]")
            .forEach(function (zone) {
                if (!(zone instanceof HTMLElement)) {
                    return;
                }
                const $zone = $(zone);
                if ($zone.hasClass("ui-sortable")) {
                    $zone.sortable("destroy");
                }

                $zone.sortable({
                    items: "> .h4bs-preview-block[data-h4bs-preview-block]",
                    placeholder: "h4bs-preview-placeholder",
                    tolerance: "pointer",
                    connectWith: "[data-h4bs-section-dropzone]",
                    distance: 8,
                    cancel: "[contenteditable='true'], input, textarea, select, button",
                    start: function () {
                        state.previewDragging = true;
                        setDropTargetsActive(true);
                    },
                    stop: function () {
                        window.setTimeout(function () {
                            state.previewDragging = false;
                            setDropTargetsActive(false);
                        }, 10);
                    },
                    receive: function (_event, ui) {
                        const parentId = String(
                            zone.getAttribute("data-h4bs-parent") || ""
                        );
                        const slot = normalizedSlot(
                            zone.getAttribute("data-h4bs-slot") || "0"
                        );
                        const insertAt = Math.max(0, Number(ui.item.index() || 0));

                        if (ui && ui.item && ui.item.attr("data-h4bs-preview-block")) {
                            const movedId = String(
                                ui.item.attr("data-h4bs-preview-block") || ""
                            );
                            if (movedId !== "") {
                                const moved = findBlockById(movedId);
                                if (moved) {
                                    moved.parent_id = parentId;
                                    moved.slot = slot;
                                }
                                syncLayoutFromPreviewDom();
                                setDirty(true);
                                renderAll();
                                return;
                            }
                        }

                        let payload = payloadFromSortableItem(ui.item);
                        if (
                            !payload &&
                            ui &&
                            ui.helper &&
                            typeof ui.helper.attr === "function"
                        ) {
                            payload = parseDropPayload(
                                String(ui.helper.attr("data-h4bs-drop-payload") || "")
                            );
                        }
                        ui.item.remove();
                        cleanupDroppedHelpers();
                        state.activeDragPayload = null;
                        root.removeAttribute("data-h4bs-active-payload");
                        root.classList.remove("is-dragging-library");
                        if (!payload) {
                            return;
                        }
                        if (
                            String(payload.kind || "") === "element" &&
                            String(payload.type || "") === "section"
                        ) {
                            return;
                        }
                        handleExternalDrop(payload, insertAt, parentId, slot);
                    },
                    update: function (_event, ui) {
                        if (ui && ui.sender) {
                            return;
                        }
                        if (
                            ui &&
                            ui.item &&
                            !ui.item.attr("data-h4bs-preview-block")
                        ) {
                            return;
                        }
                        if (syncLayoutFromPreviewDom()) {
                            setDirty(true);
                            renderAll();
                        }
                    },
                });
            });
    }

    function wirePreviewSortable() {
        if (!els.previewCanvas) {
            return;
        }

        const $canvas = $(els.previewCanvas);
        if ($canvas.hasClass("ui-sortable")) {
            $canvas.sortable("destroy");
        }

        $canvas.sortable({
            items: "> .h4bs-preview-block[data-h4bs-preview-block]",
            placeholder: "h4bs-preview-placeholder",
            tolerance: "pointer",
            distance: 8,
            cancel: "[contenteditable='true'], input, textarea, select, button",
            start: function () {
                state.previewDragging = true;
                setDropTargetsActive(true);
            },
            stop: function () {
                window.setTimeout(function () {
                    state.previewDragging = false;
                    setDropTargetsActive(false);
                }, 10);
            },
            receive: function (_event, ui) {
                const insertAt = clampInsertIndex(ui.item.index());
                let payload = payloadFromSortableItem(ui.item);
                if (
                    !payload &&
                    ui &&
                    ui.helper &&
                    typeof ui.helper.attr === "function"
                ) {
                    const helperRaw = String(
                        ui.helper.attr("data-h4bs-drop-payload") || ""
                    );
                    payload = parseDropPayload(helperRaw);
                }
                ui.item.remove();
                cleanupDroppedHelpers();
                state.activeDragPayload = null;
                root.removeAttribute("data-h4bs-active-payload");
                root.classList.remove("is-dragging-library");
                if (!payload) {
                    return;
                }
                handleExternalDrop(payload, insertAt, "", 0);
            },
            update: function (_event, ui) {
                if (ui && ui.sender) {
                    return;
                }
                if (
                    ui &&
                    ui.item &&
                    (!ui.item.attr("data-h4bs-preview-block") ||
                        ui.item.hasClass("h4bs-drag-helper") ||
                        ui.item.hasClass("h4bs-library-tile"))
                ) {
                    ui.item.remove();
                    cleanupDroppedHelpers();
                    return;
                }
                if (!syncLayoutFromPreviewDom()) {
                    return;
                }
                setDirty(true);
                renderAll();
            },
        });
    }

    function sanitizeHeadingTag(tag) {
        const safe = ["h1", "h2", "h3", "h4", "h5", "h6"];
        return safe.includes(tag) ? tag : "h2";
    }

    function sanitizeCtaHeadingTag(tag) {
        const value = String(tag || "").trim().toLowerCase();
        return ["h2", "h3", "h4", "h5", "h6"].indexOf(value) >= 0 ? value : "h3";
    }

    function toBool(value, fallback) {
        if (value === null || typeof value === "undefined") {
            return !!fallback;
        }
        const text = String(value).toLowerCase();
        if (["1", "true", "yes", "on"].includes(text)) {
            return true;
        }
        if (["0", "false", "no", "off"].includes(text)) {
            return false;
        }
        return !!fallback;
    }

    function youtubeEmbedUrl(raw, autoplay, controls, muted, loop) {
        const text = String(raw || "").trim();
        if (text === "") {
            return "";
        }
        let videoId = "";
        const watchMatch = text.match(/[?&]v=([A-Za-z0-9_-]{6,})/);
        const shortMatch = text.match(/youtu\.be\/([A-Za-z0-9_-]{6,})/);
        const embedMatch = text.match(/youtube\.com\/embed\/([A-Za-z0-9_-]{6,})/);
        if (watchMatch && watchMatch[1]) {
            videoId = watchMatch[1];
        } else if (shortMatch && shortMatch[1]) {
            videoId = shortMatch[1];
        } else if (embedMatch && embedMatch[1]) {
            videoId = embedMatch[1];
        } else if (/^[A-Za-z0-9_-]{6,}$/.test(text)) {
            videoId = text;
        }
        if (videoId === "") {
            return "";
        }
        const params = [
            "autoplay=" + (autoplay ? "1" : "0"),
            "controls=" + (controls ? "1" : "0"),
            "mute=" + (muted ? "1" : "0"),
            "loop=" + (loop ? "1" : "0"),
            "playsinline=1",
            "rel=0",
        ];
        if (loop) {
            params.push("playlist=" + encodeURIComponent(videoId));
        }
        return (
            "https://www.youtube.com/embed/" +
            encodeURIComponent(videoId) +
            "?" +
            params.join("&")
        );
    }

    function vimeoEmbedUrl(raw, autoplay, controls, muted, loop) {
        const text = String(raw || "").trim();
        if (text === "") {
            return "";
        }
        let videoId = "";
        const match = text.match(/vimeo\.com\/(?:video\/)?(\d{5,})/);
        if (match && match[1]) {
            videoId = match[1];
        } else if (/^\d{5,}$/.test(text)) {
            videoId = text;
        }
        if (videoId === "") {
            return "";
        }
        const params = [
            "autoplay=" + (autoplay ? "1" : "0"),
            "muted=" + (muted ? "1" : "0"),
            "loop=" + (loop ? "1" : "0"),
            "title=0",
            "byline=0",
            "portrait=0",
        ];
        if (!controls) {
            params.push("controls=0");
        }
        return (
            "https://player.vimeo.com/video/" +
            encodeURIComponent(videoId) +
            "?" +
            params.join("&")
        );
    }

    function splitTextItems(raw) {
        return normalizeMultilineDelimiters(raw)
            .split(/\r?\n|\|/g)
            .map(function (item) {
                return item.trim();
            })
            .filter(function (item) {
                return item !== "";
            });
    }

    function normalizeMultilineDelimiters(raw) {
        return String(raw || "").replace(/\\r\\n|\\n|\\r/g, "\n");
    }

    function splitCsvItems(raw) {
        return String(raw || "")
            .split(",")
            .map(function (item) {
                return item.trim();
            })
            .filter(function (item) {
                return item !== "";
            });
    }

    function galleryAltFromUrl(url) {
        let name = "";
        try {
            const parsed = new URL(String(url || ""), window.location.href);
            const parts = parsed.pathname.split("/");
            name = parts[parts.length - 1] || "";
        } catch (error) {
            const parts = String(url || "").split("/");
            name = parts[parts.length - 1] || "";
        }
        name = name
            .replace(/\.[a-z0-9]{2,6}$/i, "")
            .replace(/[-_]+/g, " ")
            .replace(/\b(crop|cropped|scaled|final|image|img|photo|screenshot)\b/gi, " ")
            .replace(/\b20\d{4,}\b/g, " ")
            .replace(/\s+/g, " ")
            .trim();
        if (!name) {
            return "Gallery image";
        }
        return name.replace(/\b\w/g, function (char) {
            return char.toUpperCase();
        }) + " image";
    }

    function parseFaqItems(raw) {
        return splitTextItems(raw)
            .map(function (line) {
                const pair = line.split("::");
                if (pair.length < 2) {
                    return null;
                }
                return {
                    q: String(pair.shift() || "").trim(),
                    a: String(pair.join("::") || "").trim(),
                };
            })
            .filter(function (entry) {
                return !!entry && entry.q !== "" && entry.a !== "";
            });
    }

    function isTypingTarget(target) {
        if (!(target instanceof HTMLElement)) {
            return false;
        }
        const tag = String(target.tagName || "").toLowerCase();
        if (
            tag === "input" ||
            tag === "textarea" ||
            tag === "select" ||
            target.isContentEditable
        ) {
            return true;
        }
        return !!target.closest(
            "input, textarea, select, [contenteditable='true'], .is-inline-editing"
        );
    }

    function publicationSaveLabel() {
        if (state.postStatus === "publish") {
            return "Update Live";
        }
        if (state.postStatus === "private") {
            return "Update Private";
        }
        return "Save Draft";
    }

    function syncPublicationUi() {
        const saveLabel = publicationSaveLabel();
        els.saveCommandLabels.forEach(function (label) {
            label.textContent = saveLabel;
        });
        els.saveButtons.forEach(function (button) {
            button.title = saveLabel;
        });
        if (els.reviewSave) {
            els.reviewSave.textContent = saveLabel;
            els.reviewSave.hidden = state.postStatus === "publish";
        }
        if (els.reviewPublish) {
            els.reviewPublish.textContent =
                state.postStatus === "publish" ? "Update Live" : "Publish Page";
            els.reviewPublish.hidden =
                state.postStatus !== "publish" && !state.canPublish;
        }
        if (els.reviewPostStatus) {
            els.reviewPostStatus.textContent = state.postStatusLabel;
        }
        if (els.pageStatus) {
            Array.from(els.pageStatus.classList).forEach(function (className) {
                if (className.indexOf("h4bs-page-status-badge--") === 0) {
                    els.pageStatus.classList.remove(className);
                }
            });
            els.pageStatus.classList.add(
                "h4bs-page-status-badge--" +
                    String(state.postStatus || "draft").replace(/[^a-z0-9_-]/gi, "")
            );
            els.pageStatus.textContent = "Page: " + state.postStatusLabel;
        }
        if (els.reviewPreview) {
            const reviewPreviewUrl = state.postStatus === "publish"
                ? String(data.previewUrl || "")
                : String(data.draftPreviewUrl || data.previewUrl || "");
            if (reviewPreviewUrl.trim() !== "") {
                els.reviewPreview.href = reviewPreviewUrl;
            }
        }
    }

    function readRecentQuickActions() {
        try {
            const parsed = JSON.parse(window.sessionStorage.getItem(QUICK_ACTIONS_RECENT_KEY) || "[]");
            return Array.isArray(parsed)
                ? parsed.map(String).filter(Boolean).slice(0, 4)
                : [];
        } catch (_error) {
            return [];
        }
    }

    function rememberQuickAction(actionId) {
        const id = String(actionId || "").trim();
        if (id === "") {
            return;
        }
        const recent = readRecentQuickActions().filter(function (candidate) {
            return candidate !== id;
        });
        recent.unshift(id);
        try {
            window.sessionStorage.setItem(
                QUICK_ACTIONS_RECENT_KEY,
                JSON.stringify(recent.slice(0, 4))
            );
        } catch (_error) {
            // A blocked storage API must not stop the editor workflow.
        }
    }

    function firstBlockByTypes(types) {
        const wanted = Array.isArray(types) ? types.map(String) : [];
        return state.layout.find(function (block) {
            return block && wanted.indexOf(String(block.type || "")) >= 0;
        }) || null;
    }

    function revealLibrary(tabKey, query) {
        state.canvasFocus = false;
        persistStoredBoolean(CANVAS_FOCUS_KEY, false);
        applyCanvasFocusState();
        state.inspectorAutoCollapsedSide = false;
        state.sideCollapsed = false;
        persistStoredBoolean(SIDE_COLLAPSED_KEY, false);
        applySidePanelState();
        activateLibraryTab(tabKey, true);

        const normalizedTab = normalizeLibraryTab(tabKey);
        const input = normalizedTab === "templates"
            ? els.templateSearch
            : normalizedTab === "site-kits"
                ? els.siteKitSearch
                : normalizedTab === "widgets"
                    ? els.widgetSearch
                    : els.elementSearch;
        if (input instanceof HTMLInputElement) {
            input.value = String(query || "");
            input.dispatchEvent(new Event("input", { bubbles: true }));
            window.requestAnimationFrame(function () {
                input.focus();
                input.select();
            });
        }
    }

    function openBlockOrLibrary(types, searchTerm, missingMessage) {
        const block = firstBlockByTypes(types);
        if (block) {
            openBlockModal(String(block.id || ""));
            updateDirtyText("Opened " + blockLabel(block, state.layout.indexOf(block)) + ".");
            return;
        }
        revealLibrary("elements", searchTerm);
        updateDirtyText(String(missingMessage || "Choose an element to add."));
    }

    function openPageSettingsTab(tabLabel) {
        openPageSettingsModal();
        const targetLabel = String(tabLabel || "").trim().toLowerCase();
        if (targetLabel === "") {
            return;
        }
        window.requestAnimationFrame(function () {
            if (!(els.modalBody instanceof HTMLElement)) {
                return;
            }
            const button = Array.from(
                els.modalBody.querySelectorAll(".h4bs-inspector-tabs button")
            ).find(function (candidate) {
                return String(candidate.textContent || "").trim().toLowerCase() === targetLabel;
            });
            if (button instanceof HTMLButtonElement) {
                button.click();
                const finder = els.modalBody.querySelector(".h4bs-setting-finder-input");
                if (finder instanceof HTMLInputElement) {
                    finder.focus({ preventScroll: true });
                }
            }
        });
    }

    function assignedTemplateButton(role) {
        return Array.from(els.assignedTemplateButtons || []).find(function (button) {
            return (
                button instanceof HTMLElement &&
                !button.hidden &&
                String(button.getAttribute("data-h4bs-edit-assigned-template") || "") === role
            );
        }) || null;
    }

    function quickActionCatalog() {
        const hasSelection = !!findBlockById(state.selectedId);
        const headerButton = assignedTemplateButton("header");
        const footerButton = assignedTemplateButton("footer");
        return [
            {
                id: "edit-selected",
                label: "Edit selected element",
                detail: "Open the real settings for the element selected on the page.",
                icon: "dashicons-edit-page",
                aliases: "edit selected current element block settings inspector",
                available: hasSelection,
                run: function () {
                    openBlockModal(String(state.selectedId || ""));
                },
            },
            {
                id: "edit-text",
                label: "Edit text or a heading",
                detail: "Open the first text area on this page, or show text elements to add.",
                icon: "dashicons-editor-textcolor",
                aliases: "text copy words title heading paragraph content change type",
                run: function () {
                    openBlockOrLibrary(
                        ["heading", "text", "html"],
                        "text",
                        "No text element was found. Choose a text element to add."
                    );
                },
            },
            {
                id: "edit-image",
                label: "Replace or add a photo",
                detail: "Open the first image settings, or show image elements to add.",
                icon: "dashicons-format-image",
                aliases: "image photo picture media upload replace graphic logo",
                run: function () {
                    openBlockOrLibrary(
                        ["image"],
                        "image",
                        "No image element was found. Choose Image to add one."
                    );
                },
            },
            {
                id: "edit-button",
                label: "Edit or add a button",
                detail: "Open the first button or call-to-action settings.",
                icon: "dashicons-button",
                aliases: "button link cta call action click url label",
                run: function () {
                    openBlockOrLibrary(
                        ["button", "cta"],
                        "button",
                        "No button was found. Choose Button to add one."
                    );
                },
            },
            {
                id: "add-section",
                label: "Add a section",
                detail: "Show layout sections so you can choose where the new content belongs.",
                icon: "dashicons-columns",
                aliases: "add section row container columns layout area band",
                run: function () {
                    revealLibrary("elements", "section");
                },
            },
            {
                id: "choose-design",
                label: "Choose a page design",
                detail: "Open starter templates without changing the page until you choose one.",
                icon: "dashicons-layout",
                aliases: "template design starter page layout theme inspiration import",
                run: function () {
                    state.templateUseCase = "pages";
                    revealLibrary("templates", "");
                },
            },
            {
                id: "global-styles",
                label: "Change site colors and fonts",
                detail: "Open global design controls used across Builder pages and modules.",
                icon: "dashicons-admin-appearance",
                aliases: "colors colours fonts typography brand palette global styles design",
                run: function () {
                    openPageSettingsTab("Globals");
                },
            },
            {
                id: "page-settings",
                label: "Change page settings",
                detail: "Open layout, history, global styles, and page-level controls.",
                icon: "dashicons-admin-generic",
                aliases: "page settings layout canvas full width history recovery css",
                run: function () {
                    openPageSettingsTab("Layout");
                },
            },
            {
                id: "edit-header",
                label: headerButton ? "Edit the site header" : "Choose a header design",
                detail: headerButton
                    ? "Save this page if needed, then open the assigned header template."
                    : "No header is assigned here. Open templates filtered to headers.",
                icon: "dashicons-arrow-up-alt2",
                aliases: "header menu navigation nav logo top site",
                run: function () {
                    if (headerButton instanceof HTMLElement) {
                        headerButton.click();
                        return;
                    }
                    revealLibrary("templates", "header");
                },
            },
            {
                id: "edit-footer",
                label: footerButton ? "Edit the site footer" : "Choose a footer design",
                detail: footerButton
                    ? "Save this page if needed, then open the assigned footer template."
                    : "No footer is assigned here. Open templates filtered to footers.",
                icon: "dashicons-arrow-down-alt2",
                aliases: "footer bottom copyright links site",
                run: function () {
                    if (footerButton instanceof HTMLElement) {
                        footerButton.click();
                        return;
                    }
                    revealLibrary("templates", "footer");
                },
            },
            {
                id: "desktop-view",
                label: "Preview desktop",
                detail: "Switch the editing canvas to the desktop viewport.",
                icon: "dashicons-desktop",
                aliases: "desktop computer monitor wide responsive preview viewport",
                run: function () {
                    openReviewViewport("monitor");
                },
            },
            {
                id: "tablet-view",
                label: "Preview tablet",
                detail: "Switch the editing canvas to the tablet viewport.",
                icon: "dashicons-tablet",
                aliases: "tablet ipad responsive preview viewport",
                run: function () {
                    openReviewViewport("tablet");
                },
            },
            {
                id: "mobile-view",
                label: "Preview mobile",
                detail: "Switch the editing canvas to the phone viewport.",
                icon: "dashicons-smartphone",
                aliases: "mobile phone responsive small screen preview viewport",
                run: function () {
                    openReviewViewport("mobile");
                },
            },
            {
                id: "undo",
                label: "Undo the last page change",
                detail: state.historyPast.length > 1
                    ? "Go back one saved editing step."
                    : "There is no page change to undo yet.",
                icon: "dashicons-undo",
                aliases: "undo back reverse restore change",
                available: state.historyPast.length > 1 && !(els.undoButton && els.undoButton.disabled),
                run: undoHistory,
            },
            {
                id: "redo",
                label: "Redo the last page change",
                detail: state.historyFuture.length > 0
                    ? "Restore the page change you just undid."
                    : "There is no page change to redo yet.",
                icon: "dashicons-redo",
                aliases: "redo forward restore change",
                available: state.historyFuture.length > 0 && !(els.redoButton && els.redoButton.disabled),
                run: redoHistory,
            },
            {
                id: "save",
                label: publicationSaveLabel(),
                detail: state.dirty
                    ? "Save the current Builder changes without changing publication status."
                    : "All current Builder changes are already saved.",
                icon: "dashicons-saved",
                aliases: "save draft update changes keep work",
                available: state.dirty && !state.saving,
                run: function () {
                    saveLayout(false);
                },
            },
            {
                id: "review",
                label: state.postStatus === "publish" ? "Review before updating live" : "Review and publish",
                detail: "Check readiness and every screen before a deliberate publish action.",
                icon: "dashicons-yes-alt",
                aliases: "review publish live launch update ready check preview",
                run: function () {
                    openReviewWorkspace(els.openQuickActions);
                },
            },
            {
                id: "quick-help",
                label: "Find a tutorial",
                detail: "Search the Help4 task guides without leaving your work.",
                icon: "dashicons-editor-help",
                aliases: "help tutorial guide learn instructions how support",
                run: function () {
                    if (els.quickHelp instanceof HTMLDetailsElement) {
                        els.quickHelp.open = true;
                    }
                    if (els.quickHelpSearch instanceof HTMLInputElement) {
                        els.quickHelpSearch.focus();
                    }
                },
            },
        ];
    }

    function quickActionSearchText(action) {
        return [action.id, action.label, action.detail, action.aliases]
            .join(" ")
            .toLowerCase();
    }

    function quickActionMatches(action, query) {
        const tokens = String(query || "")
            .toLowerCase()
            .trim()
            .split(/\s+/)
            .filter(Boolean);
        if (tokens.length < 1) {
            return true;
        }
        const haystack = quickActionSearchText(action);
        return tokens.every(function (token) {
            return haystack.indexOf(token) >= 0;
        });
    }

    function quickActionSort(actions, query) {
        const recent = readRecentQuickActions();
        const suggested = [
            "edit-selected",
            "edit-text",
            "edit-image",
            "edit-button",
            "add-section",
            "global-styles",
            "mobile-view",
            "review",
        ];
        return actions.slice().sort(function (left, right) {
            if (String(query || "").trim() !== "") {
                const normalized = String(query).trim().toLowerCase();
                const leftStarts = String(left.label || "").toLowerCase().indexOf(normalized) === 0;
                const rightStarts = String(right.label || "").toLowerCase().indexOf(normalized) === 0;
                if (leftStarts !== rightStarts) {
                    return leftStarts ? -1 : 1;
                }
            }
            const leftRecent = recent.indexOf(left.id);
            const rightRecent = recent.indexOf(right.id);
            if (leftRecent !== rightRecent) {
                if (leftRecent < 0) {
                    return 1;
                }
                if (rightRecent < 0) {
                    return -1;
                }
                return leftRecent - rightRecent;
            }
            const leftSuggested = suggested.indexOf(left.id);
            const rightSuggested = suggested.indexOf(right.id);
            if (leftSuggested !== rightSuggested) {
                if (leftSuggested < 0) {
                    return 1;
                }
                if (rightSuggested < 0) {
                    return -1;
                }
                return leftSuggested - rightSuggested;
            }
            return String(left.label || "").localeCompare(String(right.label || ""));
        });
    }

    function selectQuickActionResult(nextIndex) {
        const buttons = els.quickActionsList
            ? Array.from(els.quickActionsList.querySelectorAll("[data-h4bs-quick-action]"))
            : [];
        if (buttons.length < 1) {
            state.quickActionActiveIndex = -1;
            if (els.quickActionsSearch) {
                els.quickActionsSearch.removeAttribute("aria-activedescendant");
            }
            return;
        }
        state.quickActionActiveIndex = Math.max(
            0,
            Math.min(buttons.length - 1, Number(nextIndex || 0))
        );
        buttons.forEach(function (button, index) {
            const active = index === state.quickActionActiveIndex;
            button.classList.toggle("is-active", active);
            button.setAttribute("aria-selected", active ? "true" : "false");
            if (active && els.quickActionsSearch) {
                els.quickActionsSearch.setAttribute("aria-activedescendant", button.id);
                button.scrollIntoView({ block: "nearest" });
            }
        });
    }

    function runQuickAction(actionId) {
        const action = quickActionCatalog().find(function (candidate) {
            return candidate.id === String(actionId || "");
        });
        if (!action || action.available === false || typeof action.run !== "function") {
            return;
        }
        rememberQuickAction(action.id);
        closeQuickActions(false);
        if (els.openQuickActions instanceof HTMLElement) {
            els.openQuickActions.focus({ preventScroll: true });
        }
        window.requestAnimationFrame(function () {
            action.run();
        });
    }

    function renderQuickActions() {
        if (!(els.quickActionsList instanceof HTMLElement)) {
            return;
        }
        const query = els.quickActionsSearch instanceof HTMLInputElement
            ? String(els.quickActionsSearch.value || "")
            : "";
        const results = quickActionSort(
            quickActionCatalog().filter(function (action) {
                return quickActionMatches(action, query);
            }),
            query
        ).slice(0, 12);
        state.quickActionResults = results;
        state.quickActionActiveIndex = -1;
        els.quickActionsList.innerHTML = "";

        results.forEach(function (action, index) {
            const button = document.createElement("button");
            button.type = "button";
            button.id = "h4bs-quick-action-" + String(index);
            button.className = "h4bs-quick-action";
            button.setAttribute("data-h4bs-quick-action", action.id);
            button.setAttribute("role", "option");
            button.setAttribute("aria-selected", "false");
            button.disabled = action.available === false;

            const icon = document.createElement("span");
            icon.className = "dashicons " + String(action.icon || "dashicons-arrow-right-alt2");
            icon.setAttribute("aria-hidden", "true");
            const copy = document.createElement("span");
            copy.className = "h4bs-quick-action-copy";
            const label = document.createElement("strong");
            label.textContent = String(action.label || "Builder action");
            const detail = document.createElement("span");
            detail.textContent = String(action.detail || "");
            const arrow = document.createElement("span");
            arrow.className = "dashicons dashicons-arrow-right-alt2";
            arrow.setAttribute("aria-hidden", "true");
            copy.appendChild(label);
            copy.appendChild(detail);
            button.appendChild(icon);
            button.appendChild(copy);
            button.appendChild(arrow);
            button.addEventListener("click", function () {
                runQuickAction(action.id);
            });
            els.quickActionsList.appendChild(button);
        });

        if (els.quickActionsEmpty) {
            els.quickActionsEmpty.hidden = results.length > 0;
        }
        if (els.quickActionsStatus) {
            els.quickActionsStatus.textContent = results.length === 1
                ? "1 Builder action found."
                : String(results.length) + " Builder actions found.";
        }
    }

    function closeQuickActions(restoreFocus) {
        if (!(els.quickActionsModal instanceof HTMLElement)) {
            return;
        }
        els.quickActionsModal.hidden = true;
        state.quickActionsOpen = false;
        state.quickActionActiveIndex = -1;
        document.body.classList.remove("h4bs-quick-actions-is-open");
        if (els.quickActionsSearch instanceof HTMLInputElement) {
            els.quickActionsSearch.value = "";
            els.quickActionsSearch.removeAttribute("aria-activedescendant");
        }
        if (restoreFocus && state.quickActionsReturnFocus instanceof HTMLElement) {
            state.quickActionsReturnFocus.focus();
        }
        state.quickActionsReturnFocus = null;
    }

    function openQuickActions(returnFocus) {
        if (!(els.quickActionsModal instanceof HTMLElement)) {
            return;
        }
        if (state.modalMode && state.modalDirty) {
            updateDirtyText("Save or cancel the element popup before opening Quick Actions.");
            if (els.modalSaveButton instanceof HTMLElement) {
                els.modalSaveButton.focus();
            }
            return;
        }
        if (state.reviewOpen) {
            closeReviewWorkspace(false);
        }
        state.quickActionsReturnFocus = returnFocus instanceof HTMLElement
            ? returnFocus
            : document.activeElement;
        state.quickActionsOpen = true;
        els.quickActionsModal.hidden = false;
        document.body.classList.add("h4bs-quick-actions-is-open");
        if (els.quickActionsSearch instanceof HTMLInputElement) {
            els.quickActionsSearch.value = "";
        }
        renderQuickActions();
        window.requestAnimationFrame(function () {
            if (els.quickActionsSearch instanceof HTMLInputElement) {
                els.quickActionsSearch.focus();
            } else if (els.quickActionsDialog instanceof HTMLElement) {
                els.quickActionsDialog.focus();
            }
        });
    }

    function initQuickActions() {
        if (!(els.quickActionsModal instanceof HTMLElement)) {
            return;
        }
        if (els.openQuickActions) {
            els.openQuickActions.addEventListener("click", function () {
                openQuickActions(els.openQuickActions);
            });
        }
        els.quickActionsCloseButtons.forEach(function (button) {
            button.addEventListener("click", function () {
                closeQuickActions(true);
            });
        });
        if (els.quickActionsSearch instanceof HTMLInputElement) {
            els.quickActionsSearch.addEventListener("input", renderQuickActions);
            els.quickActionsSearch.addEventListener("keydown", function (event) {
                if (event.key === "ArrowDown" || event.key === "ArrowUp") {
                    event.preventDefault();
                    const direction = event.key === "ArrowDown" ? 1 : -1;
                    const start = state.quickActionActiveIndex < 0
                        ? direction > 0 ? 0 : state.quickActionResults.length - 1
                        : state.quickActionActiveIndex + direction;
                    selectQuickActionResult(start);
                    return;
                }
                if (event.key === "Enter" && state.quickActionResults.length > 0) {
                    event.preventDefault();
                    const index = state.quickActionActiveIndex < 0
                        ? 0
                        : state.quickActionActiveIndex;
                    const action = state.quickActionResults[index];
                    if (action) {
                        runQuickAction(action.id);
                    }
                }
            });
        }
        els.quickActionsModal.addEventListener("click", function (event) {
            if (event.target === els.quickActionsModal) {
                closeQuickActions(true);
            }
        });
        els.quickActionsModal.addEventListener("keydown", function (event) {
            if (!state.quickActionsOpen) {
                return;
            }
            if (event.key === "Escape") {
                event.preventDefault();
                event.stopPropagation();
                closeQuickActions(true);
                return;
            }
            if (event.key !== "Tab") {
                return;
            }
            const focusable = Array.from(
                els.quickActionsModal.querySelectorAll(
                    'button:not([hidden]):not([disabled]), input:not([hidden]):not([disabled]), [tabindex]:not([tabindex="-1"])'
                )
            ).filter(function (node) {
                return node instanceof HTMLElement && node.offsetParent !== null;
            });
            if (focusable.length < 1) {
                return;
            }
            const first = focusable[0];
            const last = focusable[focusable.length - 1];
            if (event.shiftKey && document.activeElement === first) {
                event.preventDefault();
                last.focus();
            } else if (!event.shiftKey && document.activeElement === last) {
                event.preventDefault();
                first.focus();
            }
        });
        document.addEventListener("keydown", function (event) {
            if (
                String(event.key || "").toLowerCase() !== "k" ||
                (!event.metaKey && !event.ctrlKey) ||
                event.altKey
            ) {
                return;
            }
            event.preventDefault();
            if (state.quickActionsOpen) {
                closeQuickActions(true);
                return;
            }
            openQuickActions(document.activeElement);
        });
    }

    function reviewDraftSnapshot() {
        const empty = {
            available: false,
            h1Count: 0,
            missingAlt: 0,
            placeholderLinks: 0,
            overflow: 0,
        };
        const frame = root.querySelector("[data-h4bs-draft-frame]");
        if (!(frame instanceof HTMLIFrameElement)) {
            return empty;
        }
        try {
            const doc = frame.contentDocument;
            if (!doc || !doc.documentElement) {
                return empty;
            }
            const pageRoot =
                doc.querySelector(
                    '.h4bs-builder-page[data-h4bs-layout-id="' +
                        String(Number(data.postId || 0)) +
                        '"]'
                ) ||
                doc.querySelector(".h4bs-builder-page[data-h4bs-builder-page]") ||
                doc.querySelector(".h4bs-builder-page") ||
                doc.querySelector("main") ||
                doc.body;
            const html = doc.documentElement;
            return {
                available: true,
                h1Count: pageRoot ? pageRoot.querySelectorAll("h1").length : 0,
                missingAlt: pageRoot
                    ? pageRoot.querySelectorAll("img:not([alt])").length
                    : 0,
                placeholderLinks: pageRoot
                    ? Array.from(pageRoot.querySelectorAll("a[href]")).filter(
                          function (link) {
                              const href = String(link.getAttribute("href") || "").trim();
                              return href === "" || href === "#";
                          }
                      ).length
                    : 0,
                overflow: Math.max(
                    0,
                    Number(html.scrollWidth || 0) - Number(html.clientWidth || 0)
                ),
            };
        } catch (_error) {
            return empty;
        }
    }

    function reviewReadinessItems() {
        refreshDirtyState(false);
        const snapshot = reviewDraftSnapshot();
        const reviewedCount = ["monitor", "tablet", "mobile"].filter(function (group) {
            return !!state.reviewedDevices[group];
        }).length;
        const items = [];
        const add = function (key, status, label, detail) {
            items.push({ key: key, status: status, label: label, detail: detail });
        };

        add(
            "content",
            state.layout.length > 0 ? "pass" : "block",
            "Page content",
            state.layout.length > 0
                ? state.layout.length + (state.layout.length === 1 ? " element is ready for review." : " elements are ready for review.")
                : "Add at least one element before publishing."
        );
        if (state.modalMode && state.modalDirty) {
            add(
                "element-edit",
                "block",
                "Open element changes",
                "Save or cancel the element popup before publishing."
            );
        } else if (state.dirty) {
            const dirtyScope = state.pageDirty && state.globalDesignDirty
                ? "page and global style changes"
                : state.globalDesignDirty
                    ? "global style changes"
                    : "page changes";
            add(
                "saved",
                "warn",
                "Unsaved changes",
                "Builder will save the current " + dirtyScope + " before publishing."
            );
        } else {
            add("saved", "pass", "Saved state", "All current Builder changes are saved.");
        }
        if (state.globalDesignConflict && state.globalDesignDirty) {
            add(
                "global-conflict",
                "block",
                "Global style conflict",
                "Reload Studio before publishing global style changes from this tab."
            );
        }
        add(
            "title",
            String(data.postTitle || "").trim() !== "" ? "pass" : "warn",
            "WordPress title",
            String(data.postTitle || "").trim() !== ""
                ? "The page has a WordPress title."
                : "Add a clear WordPress title for navigation and search previews."
        );
        if (!snapshot.available) {
            add(
                "preview",
                "warn",
                "Draft preview",
                "The preview is still loading. Wait a moment, then run Review again."
            );
        } else {
            add(
                "heading",
                snapshot.h1Count === 1 ? "pass" : "warn",
                "Main page heading",
                snapshot.h1Count === 1
                    ? "Exactly one H1 is present in the Builder page."
                    : snapshot.h1Count === 0
                        ? "No H1 was found. Give the page one clear main heading."
                        : snapshot.h1Count + " H1 headings were found. Keep one main H1."
            );
            add(
                "images",
                snapshot.missingAlt === 0 ? "pass" : "warn",
                "Image descriptions",
                snapshot.missingAlt === 0
                    ? "Every rendered image declares an alt attribute."
                    : snapshot.missingAlt + (snapshot.missingAlt === 1 ? " image needs an alt attribute." : " images need alt attributes.")
            );
            add(
                "links",
                snapshot.placeholderLinks === 0 ? "pass" : "warn",
                "Button and link destinations",
                snapshot.placeholderLinks === 0
                    ? "No empty or placeholder links were found."
                    : snapshot.placeholderLinks + (snapshot.placeholderLinks === 1 ? " link still points to # or an empty destination." : " links still point to # or empty destinations.")
            );
            add(
                "overflow",
                snapshot.overflow === 0 ? "pass" : "warn",
                "Current responsive view",
                snapshot.overflow === 0
                    ? "The current preview has no horizontal overflow."
                    : "The current preview extends " + snapshot.overflow + "px past its viewport."
            );
        }
        add(
            "devices",
            reviewedCount === 3 ? "pass" : "warn",
            "Desktop, tablet, and mobile",
            reviewedCount === 3
                ? "All three responsive views were opened in this review session."
                : reviewedCount + " of 3 responsive views opened in this review session."
        );
        return items;
    }

    function setReviewActionStatus(message, status) {
        if (!els.reviewActionStatus) {
            return;
        }
        els.reviewActionStatus.textContent = String(message || "");
        els.reviewActionStatus.classList.toggle("is-error", status === "error");
        els.reviewActionStatus.classList.toggle("is-success", status === "success");
    }

    function renderReviewWorkspace() {
        if (!els.reviewModal) {
            return [];
        }
        const items = reviewReadinessItems();
        const blockers = items.filter(function (item) {
            return item.status === "block";
        });
        const warnings = items.filter(function (item) {
            return item.status === "warn";
        });
        if (els.reviewChecks) {
            els.reviewChecks.innerHTML = "";
            items.forEach(function (item) {
                const row = document.createElement("li");
                row.className = "h4bs-review-check is-" + item.status;
                row.setAttribute("data-h4bs-review-check", item.key);
                const icon = document.createElement("span");
                icon.className = "dashicons " +
                    (item.status === "pass"
                        ? "dashicons-yes-alt"
                        : item.status === "block"
                            ? "dashicons-dismiss"
                            : "dashicons-warning");
                icon.setAttribute("aria-hidden", "true");
                const copy = document.createElement("span");
                const title = document.createElement("strong");
                title.textContent = item.label;
                const detail = document.createElement("small");
                detail.textContent = item.detail;
                copy.appendChild(title);
                copy.appendChild(detail);
                row.appendChild(icon);
                row.appendChild(copy);
                els.reviewChecks.appendChild(row);
            });
        }
        if (els.reviewSummaryTitle && els.reviewSummaryText) {
            if (blockers.length > 0) {
                els.reviewSummaryTitle.textContent = "Fix " + blockers.length + (blockers.length === 1 ? " blocking item" : " blocking items");
                els.reviewSummaryText.textContent = "Nothing has been published. Resolve the red items, then run Review again.";
            } else if (warnings.length > 0) {
                els.reviewSummaryTitle.textContent = "Ready with " + warnings.length + (warnings.length === 1 ? " item to review" : " items to review");
                els.reviewSummaryText.textContent = state.postStatus === "publish"
                    ? "Saving this page updates the live version. Review the yellow items before continuing."
                    : "The page can be published, but the yellow items deserve a final look.";
            } else {
                els.reviewSummaryTitle.textContent = state.postStatus === "publish" ? "Ready to update live" : "Ready to publish";
                els.reviewSummaryText.textContent = "The current Builder checks are clear.";
            }
        }
        els.reviewDeviceButtons.forEach(function (button) {
            const group = String(button.getAttribute("data-h4bs-review-device") || "");
            const reviewed = !!state.reviewedDevices[group];
            button.setAttribute("aria-pressed", reviewed ? "true" : "false");
            button.classList.toggle("is-reviewed", reviewed);
        });
        if (els.reviewPublish) {
            els.reviewPublish.disabled = blockers.length > 0 || state.saving || state.publishing;
        }
        if (els.reviewSave) {
            els.reviewSave.disabled = state.saving || state.publishing;
        }
        syncPublicationUi();
        return blockers;
    }

    function closeReviewWorkspace(restoreFocus) {
        if (!els.reviewModal) {
            return;
        }
        els.reviewModal.hidden = true;
        state.reviewOpen = false;
        document.body.classList.remove("h4bs-review-is-open");
        if (restoreFocus && state.reviewReturnFocus instanceof HTMLElement) {
            state.reviewReturnFocus.focus();
        }
        state.reviewReturnFocus = null;
    }

    function openReviewWorkspace(returnFocus) {
        if (!els.reviewModal) {
            return;
        }
        if (state.modalMode && state.modalDirty) {
            updateDirtyText("Save or cancel the element popup before opening Review.");
            return;
        }
        state.reviewReturnFocus = returnFocus instanceof HTMLElement
            ? returnFocus
            : document.activeElement;
        state.reviewOpen = true;
        els.reviewModal.hidden = false;
        document.body.classList.add("h4bs-review-is-open");
        setReviewActionStatus("", "");
        renderReviewWorkspace();
        window.requestAnimationFrame(function () {
            const close = els.reviewModal.querySelector("[data-h4bs-review-close]");
            if (close instanceof HTMLElement) {
                close.focus();
            } else if (els.reviewDialog instanceof HTMLElement) {
                els.reviewDialog.focus();
            }
        });
    }

    function openReviewViewport(group) {
        const normalized = ["monitor", "tablet", "mobile"].includes(group)
            ? group
            : "monitor";
        state.reviewedDevices[normalized] = true;
        const viewportButton = els.viewportIcons
            ? els.viewportIcons.querySelector(
                  '[data-h4bs-viewport-group="' + normalized + '"]'
              )
            : null;
        if (viewportButton instanceof HTMLButtonElement) {
            viewportButton.click();
        }
        updateDirtyText(
            (normalized === "monitor" ? "Desktop" : normalized.charAt(0).toUpperCase() + normalized.slice(1)) +
                " review opened. Inspect the canvas, then return to Review."
        );
        closeReviewWorkspace(false);
        if (els.previewStage instanceof HTMLElement) {
            els.previewStage.setAttribute("tabindex", "-1");
            els.previewStage.focus();
        }
    }

    function publishSavedPage() {
        if (state.postStatus === "publish") {
            setReviewActionStatus("The live page is updated with the saved Builder changes.", "success");
            renderReviewWorkspace();
            return;
        }
        if (!state.canPublish || state.publishing) {
            setReviewActionStatus("Your WordPress role cannot publish this page.", "error");
            return;
        }
        state.publishing = true;
        setReviewActionStatus("Publishing through WordPress...", "");
        renderReviewWorkspace();
        $.post(data.ajaxUrl, {
            action: "h4bs_builder_publish_page",
            nonce: data.nonce,
            post_id: data.postId,
        })
            .done(function (response) {
                if (!response || !response.success) {
                    const message = response && response.data && response.data.message
                        ? String(response.data.message)
                        : "WordPress could not publish this page.";
                    setReviewActionStatus(message, "error");
                    return;
                }
                const responseData = response.data || {};
                state.postStatus = String(responseData.post_status || "publish");
                state.postStatusLabel = String(responseData.post_status_label || "Published");
                if (String(responseData.permalink || "").trim() !== "") {
                    data.previewUrl = String(responseData.permalink);
                }
                setReviewActionStatus("Published. The public page is ready to open.", "success");
                syncPublicationUi();
            })
            .fail(function (xhr) {
                const payload = xhr && xhr.responseJSON && xhr.responseJSON.data
                    ? xhr.responseJSON.data
                    : null;
                setReviewActionStatus(
                    payload && payload.message
                        ? String(payload.message)
                        : "Publishing failed. Your saved draft remains unchanged.",
                    "error"
                );
            })
            .always(function () {
                state.publishing = false;
                renderReviewWorkspace();
            });
    }

    function requestReviewPublish() {
        const blockers = renderReviewWorkspace();
        if (blockers.length > 0) {
            setReviewActionStatus("Resolve the blocking items before publishing.", "error");
            return;
        }
        setReviewActionStatus(
            state.postStatus === "publish"
                ? "Saving the changes that will update the live page..."
                : "Saving the draft before publishing...",
            ""
        );
        saveLayout(false, function () {
            publishSavedPage();
        });
    }

    function initReviewWorkspace() {
        syncPublicationUi();
        if (!(els.reviewModal instanceof HTMLElement)) {
            return;
        }
        if (els.openReview) {
            els.openReview.addEventListener("click", function () {
                openReviewWorkspace(els.openReview);
            });
        }
        els.reviewCloseButtons.forEach(function (button) {
            button.addEventListener("click", function () {
                closeReviewWorkspace(true);
            });
        });
        els.reviewDeviceButtons.forEach(function (button) {
            button.addEventListener("click", function () {
                openReviewViewport(
                    String(button.getAttribute("data-h4bs-review-device") || "monitor")
                );
            });
        });
        if (els.reviewSave) {
            els.reviewSave.addEventListener("click", function () {
                setReviewActionStatus("Saving current Builder changes...", "");
                saveLayout(false, function () {
                    setReviewActionStatus(
                        state.postStatus === "publish"
                            ? "The live page is updated."
                            : "Draft saved. Nothing was published.",
                        "success"
                    );
                    renderReviewWorkspace();
                });
            });
        }
        if (els.reviewPublish) {
            els.reviewPublish.addEventListener("click", requestReviewPublish);
        }
        els.reviewModal.addEventListener("click", function (event) {
            if (event.target === els.reviewModal) {
                closeReviewWorkspace(true);
            }
        });
        els.reviewModal.addEventListener("keydown", function (event) {
            if (!state.reviewOpen) {
                return;
            }
            if (event.key === "Escape") {
                event.preventDefault();
                closeReviewWorkspace(true);
                return;
            }
            if (event.key !== "Tab") {
                return;
            }
            const focusable = Array.from(
                els.reviewModal.querySelectorAll(
                    'button:not([hidden]):not([disabled]), a[href]:not([hidden]), [tabindex]:not([tabindex="-1"])'
                )
            ).filter(function (node) {
                return node instanceof HTMLElement && node.offsetParent !== null;
            });
            if (focusable.length < 1) {
                return;
            }
            const first = focusable[0];
            const last = focusable[focusable.length - 1];
            if (event.shiftKey && document.activeElement === first) {
                event.preventDefault();
                last.focus();
            } else if (!event.shiftKey && document.activeElement === last) {
                event.preventDefault();
                first.focus();
            }
        });
    }

    function wireGlobalControls() {
        els.saveButtons.forEach(function (button) {
            button.addEventListener("click", function () {
                if (state.modalMode && state.modalDirty) {
                    updateDirtyText("Save the popup changes before publishing.");
                    return;
                }
                saveLayout(false, function () {
                    syncPublicationUi();
                    if (state.reviewOpen) {
                        renderReviewWorkspace();
                    }
                });
            });
        });

        if (els.copyPageSpec) {
            els.copyPageSpec.addEventListener("click", function () {
                copyPageSpec();
            });
        }
        if (els.pastePageSpec) {
            els.pastePageSpec.addEventListener("click", function () {
                pastePageSpec();
            });
        }
        if (els.saveThemePack) {
            els.saveThemePack.addEventListener("click", saveCurrentThemePack);
        }
        if (els.importThemePack) {
            els.importThemePack.addEventListener("click", importThemePack);
        }
        if (els.exportThemePack) {
            els.exportThemePack.addEventListener("click", exportThemePack);
        }
        if (els.undoButton) {
            els.undoButton.addEventListener("click", function () {
                undoHistory();
            });
        }
        if (els.redoButton) {
            els.redoButton.addEventListener("click", function () {
                redoHistory();
            });
        }
        if (els.addElement) {
            els.addElement.addEventListener("click", function () {
                state.inspectorAutoCollapsedSide = false;
                state.sideCollapsed = false;
                persistStoredBoolean(SIDE_COLLAPSED_KEY, false);
                applySidePanelState();
                activateLibraryTab("elements", true);
                window.requestAnimationFrame(function () {
                    if (els.elementSearch instanceof HTMLElement) {
                        els.elementSearch.focus();
                    }
                });
            });
        }

        if (els.viewportSelect) {
            els.viewportSelect.addEventListener("change", function () {
                state.viewportSlug = String(els.viewportSelect.value || state.viewportSlug);
                const nextViewport = viewportBySlug(state.viewportSlug);
                state.viewportGroup = inferViewportGroup(nextViewport);
                renderViewportIcons();
                renderViewportSelect();
                applyViewport();
                renderPreview();
            });
        }
        if (els.frameButtons && els.frameButtons.length > 0) {
            els.frameButtons.forEach(function (button) {
                button.addEventListener("click", function () {
                    state.frameMode = normalizeFrameMode(
                        button.getAttribute("data-h4bs-frame-mode")
                    );
                    persistFrameMode();
                    renderFrameModeButtons();
                    applyViewport();
                });
            });
        }
        if (els.previewSizingButtons && els.previewSizingButtons.length > 0) {
            els.previewSizingButtons.forEach(function (button) {
                button.addEventListener("click", function () {
                    state.previewSizingMode = normalizePreviewSizingMode(
                        button.getAttribute("data-h4bs-preview-sizing")
                    );
                    persistPreviewSizingMode();
                    renderPreviewSizingButtons();
                    applyViewport();
                    renderPreview();
                });
            });
        }
        if (els.parityToggle) {
            els.parityToggle.addEventListener("click", function () {
                toggleCurrentDraftReview();
            });
        }
        if (els.compareParity) {
            els.compareParity.addEventListener("click", comparePreviewParity);
        }
        if (els.previewStage) {
            els.previewStage.addEventListener("scroll", function () {
                updateMiniPreviewViewportWindow();
            });
        }

        window.addEventListener("resize", function () {
            applyViewport();
        });
        window.addEventListener("scroll", function () {
            syncSelectedPreviewBlockVisual();
        }, true);

        document.addEventListener("keydown", function (event) {
            if (!(event.ctrlKey || event.metaKey) || event.altKey) {
                return;
            }
            if (isTypingTarget(event.target)) {
                return;
            }

            const key = String(event.key || "").toLowerCase();
            if (key === "s") {
                event.preventDefault();
                saveLayout(false);
                return;
            }
            if (key === "d" && state.selectedId) {
                event.preventDefault();
                duplicateBlock(String(state.selectedId));
                return;
            }
            if (key === "z") {
                event.preventDefault();
                if (event.shiftKey) {
                    redoHistory();
                    return;
                }
                undoHistory();
                return;
            }
            if (key === "y") {
                event.preventDefault();
                redoHistory();
            }
        });
    }

    function applyViewport() {
        const viewport = selectedViewport();
        const exactWidth = Math.max(320, Number(viewport.width || 1920));
        const height = Math.max(480, Number(viewport.height || 1080));
        const viewportHeight = Math.max(480, Math.min(height, 4320));
        const group = String(viewport.group || state.viewportGroup || "monitor");
        const framed = state.frameMode !== "clean";
        const workspaceFit = state.previewSizingMode === "workspace";
        const horizontalInset = framed ? 44 : 28;
        const verticalInset = framed ? 34 : 22;
        const stageWidth = els.previewStage
            ? Math.max(320, els.previewStage.clientWidth - horizontalInset)
            : exactWidth;
        const stageHeight = els.previewStage
            ? Math.max(280, els.previewStage.clientHeight - verticalInset)
            : viewportHeight;
        const desktopWorkspaceWidth = Math.max(1025, stageWidth);
        const width = workspaceFit && (group === "monitor" || group === "tv")
            ? Math.min(exactWidth, desktopWorkspaceWidth)
            : exactWidth;
        const shellClasses = [
            "is-device-monitor",
            "is-device-tablet",
            "is-device-mobile",
            "is-device-tv",
            "is-frame-clean",
        ];
        const contentMaxPercent =
            width >= 7680 ? 90 : width >= 5120 ? 91 : width >= 3840 ? 92 : 94;
        const contentMaxRem =
            width >= 7680 ? "320rem" : width >= 5120 ? "220rem" : width >= 3840 ? "180rem" : "118rem";
        const baseFontSize =
            width >= 7680 ? "23px" : width >= 5120 ? "21px" : width >= 3840 ? "19px" : "16px";
        const baseFontPx = Number.parseFloat(baseFontSize) || 16;
        const clampPx = function (minPx, preferredPx, maxPx) {
            return Math.min(maxPx, Math.max(minPx, preferredPx));
        };
        const shellPadY = clampPx(baseFontPx * 0.8, width * 0.012, baseFontPx * 1.1);
        const shellPadX = clampPx(baseFontPx * 0.9, width * 0.02, baseFontPx * 2);
        const mainPadY = clampPx(baseFontPx * 1.4, width * 0.02, baseFontPx * 2.8);
        const fullWidthMainPad = clampPx(baseFontPx * 0.8, width * 0.014, baseFontPx * 1.4);
        const contentPanelPad = clampPx(baseFontPx, width * 0.02, baseFontPx * 2);

        if (els.previewShell) {
            shellClasses.forEach(function (className) {
                els.previewShell.classList.remove(className);
            });
            els.previewShell.classList.add("is-device-" + group);
            if (!framed) {
                els.previewShell.classList.add("is-frame-clean");
            }
            els.previewShell.style.width = width + "px";
            els.previewShell.style.minHeight = viewportHeight + "px";
            els.previewShell.style.setProperty("--h4bs-device-width", width + "px");
            els.previewShell.style.setProperty("--h4bs-device-height", viewportHeight + "px");
            // Keep theme tokens viewport-relative to the selected preview size, not wp-admin width.
            els.previewShell.style.setProperty(
                "--h4-content-max",
                "min(" + contentMaxPercent + "%, " + contentMaxRem + ")"
            );
            els.previewShell.style.setProperty("--h4-base-font", baseFontSize);
            els.previewShell.style.setProperty("--h4bs-site-shell-pad-y", shellPadY.toFixed(2) + "px");
            els.previewShell.style.setProperty("--h4bs-site-shell-pad-x", shellPadX.toFixed(2) + "px");
            els.previewShell.style.setProperty("--h4bs-site-main-pad-y", mainPadY.toFixed(2) + "px");
            els.previewShell.style.setProperty("--h4bs-site-main-pad-x", shellPadX.toFixed(2) + "px");
            els.previewShell.style.setProperty(
                "--h4bs-site-main-pad-full-width",
                fullWidthMainPad.toFixed(2) + "px"
            );
            els.previewShell.style.setProperty(
                "--h4bs-content-panel-pad",
                contentPanelPad.toFixed(2) + "px"
            );
        }
        if (els.previewCanvas) {
            els.previewCanvas.style.minHeight = viewportHeight + "px";
        }
        if (els.previewStage) {
            els.previewStage.classList.toggle("is-frame-clean", !framed);
            els.previewStage.classList.toggle("is-workspace-fit", workspaceFit);
        }
        root.setAttribute(
            "data-h4bs-preview-sizing",
            normalizePreviewSizingMode(state.previewSizingMode)
        );
        if (els.previewScale) {
            const bodyStyles = window.getComputedStyle(document.body);
            const bodyBackground = bodyStyles && bodyStyles.background
                ? String(bodyStyles.background)
                : "";
            if (bodyBackground !== "") {
                els.previewScale.style.background = bodyBackground;
            } else {
                els.previewScale.style.removeProperty("background");
            }
        }

        if (els.previewStage && els.previewScale) {
            const scaleByWidth = stageWidth / width;
            const scaleByHeight = stageHeight / viewportHeight;
            const scale = workspaceFit
                ? Math.min(1, scaleByWidth)
                : 1;
            const scaledWidth = Math.max(1, Math.round(width * scale));
            const scaledHeight = Math.max(1, Math.round(viewportHeight * scale));
            els.previewScale.style.transform = "none";
            els.previewScale.style.width = scaledWidth + "px";
            els.previewScale.style.height = scaledHeight + "px";
            els.previewScale.style.position = "relative";
            els.previewScale.style.overflow = "visible";
            if (els.previewShell) {
                els.previewShell.style.position = "absolute";
                els.previewShell.style.left = "0";
                els.previewShell.style.top = "0";
                els.previewShell.style.transformOrigin = "top left";
                els.previewShell.style.transform = "scale(" + scale.toFixed(4) + ")";
            }
            els.previewStage.scrollLeft = 0;
        }

        if (els.viewportLive) {
            els.viewportLive.textContent = workspaceFit
                ? "Fit: " + width + "px wide"
                : String(viewport.label || "Viewport") +
                    " - " +
                    exactWidth +
                    "x" +
                    height;
        }
        ensureParityPreviewFrame(false);
        syncSelectedPreviewBlockVisual();
        scheduleMiniPreviewSync(true);
    }

    function saveLayout(isAutosave, onSuccess) {
        refreshDirtyState(false);
        const savePage = state.pageDirty;
        const globalSaveBlocked = state.globalDesignConflict && state.globalDesignDirty;
        const saveGlobals = state.globalDesignDirty && !globalSaveBlocked;
        if (globalSaveBlocked && !savePage) {
            updateDirtyText("Global styles changed in another Studio tab. Reload before saving.");
            if (!isAutosave) {
                window.alert("Reload Studio before saving global styles. Page changes remain independently saveable.");
            }
            return;
        }
        if (state.modalMode && state.modalDirty) {
            if (!isAutosave) {
                updateDirtyText("Save the popup changes before publishing.");
            }
            return;
        }
        if (state.saving) {
            return;
        }
        if (!savePage && !saveGlobals) {
            updateDirtyText("All changes saved.");
            if (typeof onSuccess === "function") {
                onSuccess(null);
            }
            return;
        }

        const requestedPageKey = savePage ? currentPageStateKey() : "";
        const requestedGlobalKey = saveGlobals ? currentGlobalStateKey() : "";
        const payload = {
            action: "h4bs_builder_save_layout",
            nonce: data.nonce,
            post_id: data.postId,
            save_layout: savePage ? "1" : "0",
            save_globals: saveGlobals ? "1" : "0",
        };
        if (savePage) {
            payload.layout = JSON.stringify(state.layout);
            payload.layout_hash = String(state.layoutHash || "");
            payload.page_layout = state.pageLayout;
            payload.page_title_mode = state.pageTitleMode;
            payload.page_css = String(state.pageCss || "");
            payload.page_css_hash = String(state.pageCssHash || "");
            payload.template_conditions = state.isTemplate
                ? JSON.stringify(state.templateConditions || {})
                : "";
        }
        if (saveGlobals) {
            payload.global_design_tokens = JSON.stringify(
                state.globalDesignTokens || {}
            );
            payload.custom_theme_packs = JSON.stringify(
                state.customThemePacks || []
            );
            payload.active_theme_pack = String(state.activeThemePack || "");
            payload.global_revision = String(state.globalDesignRevision || 1);
        }

        state.saving = true;
        const savingScope = savePage && saveGlobals
            ? "page and global styles"
            : savePage
                ? "page"
                : "global styles";
        updateDirtyText(
            (isAutosave ? "Autosaving " : "Saving ") + savingScope + "..."
        );

        $.post(data.ajaxUrl, payload)
            .done(function (response) {
                if (!response || !response.success) {
                    const message =
                        response &&
                        response.data &&
                        typeof response.data.message === "string"
                            ? response.data.message
                            : "Save failed.";
                    updateDirtyText(message);
                    return;
                }
                const responseData = response.data || {};
                if (savePage) {
                    const responseLayout = Array.isArray(responseData.layout)
                        ? responseData.layout
                        : state.layout;
                    const responsePageLayout = typeof responseData.page_layout === "string"
                        ? responseData.page_layout
                        : state.pageLayout;
                    const responsePageCss = typeof responseData.page_css === "string"
                        ? responseData.page_css
                        : state.pageCss;
                    const responsePageTitleMode = typeof responseData.page_title_mode === "string"
                        ? responseData.page_title_mode
                        : state.pageTitleMode;
                    const responseConditions =
                        responseData.template_conditions &&
                        typeof responseData.template_conditions === "object"
                            ? responseData.template_conditions
                            : state.templateConditions;
                    const responsePageKey = pageStateKeyFromValues(
                        responseLayout,
                        responsePageLayout,
                        responsePageTitleMode,
                        responseConditions,
                        responsePageCss
                    );
                    if (currentPageStateKey() === requestedPageKey) {
                        state.layout = normalizeLayout(responseLayout);
                        state.pageLayout = normalizePageLayout(responsePageLayout);
                        state.pageTitleMode = normalizePageTitleMode(responsePageTitleMode);
                        state.pageCss = String(responsePageCss || "");
                        state.templateConditions = normalizeTemplateConditions(
                            responseConditions
                        );
                    }
                    state.savedPageStateKey = responsePageKey;
                    if (typeof responseData.layout_hash === "string") {
                        state.layoutHash = String(responseData.layout_hash || "");
                    }
                    if (typeof responseData.page_css_hash === "string") {
                        state.pageCssHash = String(responseData.page_css_hash || "");
                    }
                    state.isFreshPage = false;
                    if (!isAutosave) {
                        state.explicitFirstSaveRequired = false;
                    }
                    state.startJourneyDismissed = true;
                    renderStartJourney();
                }
                if (saveGlobals) {
                    const responseTokens =
                        responseData.global_design_tokens &&
                        typeof responseData.global_design_tokens === "object"
                            ? responseData.global_design_tokens
                            : state.globalDesignTokens;
                    const responsePacks = Array.isArray(responseData.custom_theme_packs)
                        ? responseData.custom_theme_packs
                        : state.customThemePacks;
                    const responseActive = typeof responseData.active_theme_pack === "string"
                        ? responseData.active_theme_pack
                        : state.activeThemePack;
                    const responseGlobalKey = globalStateKeyFromValues(
                        responseTokens,
                        responsePacks,
                        responseActive
                    );
                    if (currentGlobalStateKey() === requestedGlobalKey) {
                        state.globalDesignTokens = normalizeGlobalDesignTokens(
                            responseTokens
                        );
                        state.customThemePacks = normalizeCustomThemePacks(
                            responsePacks
                        );
                        state.activeThemePack = String(responseActive || "").trim();
                        renderThemePackCards();
                    }
                    state.savedGlobalStateKey = responseGlobalKey;
                    state.globalDesignConflict = false;
                }
                if (response.data && Number(response.data.global_revision || 0) > 0) {
                    state.globalDesignRevision = Number(response.data.global_revision);
                }
                if (response.data && typeof response.data.global_hash === "string") {
                    state.globalDesignHash = String(response.data.global_hash || "");
                }
                refreshDirtyState(false);
                const stamp =
                    response.data &&
                    typeof response.data.updated_at === "string"
                        ? response.data.updated_at
                        : "just now";
                const purge = response.data && response.data.purge_result
                    ? response.data.purge_result
                    : null;
                const purgeText = purge && Number(purge.pages || 0) > 0
                    ? " | cache purge: " + String(purge.status || "requested") + " (" + String(purge.pages) + " pages)"
                    : "";
                const noOpText = responseData.no_op ? "No write needed. " : "Saved. ";
                const pendingText = state.dirty
                    ? state.globalDesignConflict && state.globalDesignDirty
                        ? " Global styles still need a reload; page changes remain tracked."
                        : " New edits made during the save are still unsaved."
                    : "";
                updateDirtyText(noOpText + stamp + purgeText + pendingText);
                refreshBlockLabels();
                renderPreview();
                updateEstimate();
                applyViewport();
                if (state.parityMode) {
                    ensureParityPreviewFrame(true);
                }
                if (typeof onSuccess === "function") {
                    onSuccess(response.data || null);
                }
            })
            .fail(function (xhr) {
                const payload = xhr && xhr.responseJSON && xhr.responseJSON.data
                    ? xhr.responseJSON.data
                    : null;
                if (payload && payload.code === "global_revision_conflict") {
                    state.globalDesignConflict = true;
                    updateDirtyText("Global styles changed in another Studio tab. Reload before publishing globals.");
                    window.alert("Global styles were updated elsewhere. Your page layout was not saved, and no global values were overwritten. Reload Studio to merge safely.");
                    return;
                }
                if (payload && payload.code === "layout_revision_conflict") {
                    updateDirtyText("This page changed in another Builder session. Reload before saving.");
                    window.alert("This page was updated elsewhere. Your current layout was not written. Reload Studio before continuing so the newer page is not overwritten.");
                    return;
                }
                if (payload && payload.code === "invalid_layout_structure") {
                    updateDirtyText("Save blocked: the element structure is incomplete.");
                    window.alert("Builder blocked this save because an element has a missing or duplicate relationship. Your published page was not changed.");
                    return;
                }
                updateDirtyText("Save failed. Please retry.");
            })
            .always(function () {
                state.saving = false;
                if (state.reviewOpen) {
                    renderReviewWorkspace();
                }
            });
    }

    function setDirty(flag) {
        refreshDirtyState(true);
    }

    function refreshDirtyState(showStatus) {
        state.pageDirty = currentPageStateKey() !== state.savedPageStateKey;
        state.globalDesignDirty =
            currentGlobalStateKey() !== state.savedGlobalStateKey;
        state.dirty = state.pageDirty || state.globalDesignDirty;
        if (!showStatus) {
            return;
        }
        if (state.pageDirty && state.globalDesignDirty) {
            updateDirtyText("Unsaved page and global style changes");
        } else if (state.pageDirty) {
            updateDirtyText("Unsaved page changes");
        } else if (state.globalDesignDirty) {
            updateDirtyText("Unsaved global style changes");
        } else {
            updateDirtyText("All changes saved.");
        }
    }

    function updateDirtyText(text) {
        if (!els.dirtyState) {
            return;
        }
        els.dirtyState.textContent = text;
    }

    function updatePerformanceCoach(totalMs, addedMs, grade, typeCounts, blockCount) {
        if (
            !(els.performanceCoach instanceof HTMLElement) ||
            !(els.performanceSummary instanceof HTMLElement) ||
            !(els.performanceTips instanceof HTMLElement)
        ) {
            return;
        }

        const counts = typeCounts && typeof typeCounts === "object" ? typeCounts : {};
        const tips = [];
        let severity = "good";
        const bumpSeverity = function (next) {
            const rank = { good: 0, caution: 1, warning: 2 };
            const current = Object.prototype.hasOwnProperty.call(rank, severity)
                ? rank[severity]
                : 0;
            const incoming = Object.prototype.hasOwnProperty.call(rank, next)
                ? rank[next]
                : 0;
            if (incoming > current) {
                severity = next;
            }
        };

        if (blockCount >= 60) {
            tips.push(
                "High element count can hurt Core Web Vitals and SEO rankings. Keep only what truly supports conversions."
            );
            bumpSeverity(blockCount >= 110 ? "warning" : "caution");
        }
        if (Number(totalMs || 0) >= 2600 || Number(addedMs || 0) >= 1200) {
            tips.push(
                "Google generally favors pages that load quickly. This layout is trending heavy. Consider reducing above-the-fold widgets."
            );
            bumpSeverity(Number(totalMs || 0) >= 3400 ? "warning" : "caution");
        }
        if (Number(counts.image || 0) >= 10 || Number(counts.gallery || 0) >= 3) {
            tips.push(
                "Compress images (WebP/AVIF), lazy-load below-the-fold media, and avoid stacking large galleries in one viewport."
            );
            bumpSeverity("caution");
        }
        if (
            Number(counts.slider || 0) >= 2 ||
            Number(counts.video || 0) >= 2 ||
            Number(counts.shortcode || 0) >= 6
        ) {
            tips.push(
                "Multiple sliders/videos/shortcodes are strong lag creators. Use one hero motion element per viewport when possible."
            );
            bumpSeverity("warning");
        }
        if (
            Number(counts.section || 0) >= 16 &&
            Number(counts.container || 0) + Number(counts.inner_section || 0) >= 20
        ) {
            tips.push(
                "Deep nesting increases DOM cost. Merge adjacent sections/containers and prefer reusable templates."
            );
            bumpSeverity("caution");
        }
        if (tips.length < 1) {
            tips.push(
                "This page is in a healthy range. Keep scripts minimal and avoid duplicate widgets on the same fold."
            );
        }

        const gradeText = String(grade || "Fast");
        const summary =
            "SEO Guidance: " +
            gradeText +
            " build profile. " +
            blockCount +
            " element" +
            (blockCount === 1 ? "" : "s") +
            " in layout.";
        els.performanceSummary.textContent = summary;

        els.performanceCoach.classList.remove(
            "is-performance-good",
            "is-performance-caution",
            "is-performance-warning"
        );
        els.performanceCoach.classList.add("is-performance-" + severity);

        els.performanceTips.innerHTML = "";
        tips.slice(0, 5).forEach(function (tip) {
            const item = document.createElement("li");
            item.textContent = String(tip || "");
            els.performanceTips.appendChild(item);
        });
    }

    function updateEstimate() {
        if (!els.estimate) {
            return;
        }
        const baseMs = Math.max(250, Number(data.basePageLoadMs || 900));
        let addedMs = 0;
        const weights = {
            section: 20,
            heading: 6,
            text: 8,
            image: 65,
            button: 4,
            html: 20,
            shortcode: 140,
            slider: 280,
            spacer: 1,
            divider: 2,
            video: 220,
            icon: 4,
            list: 12,
            quote: 8,
            cta: 16,
            gallery: 180,
            map: 210,
            faq: 18,
            counter: 10,
            progress: 14,
            menu: 22,
            container: 12,
            inner_section: 16,
        };
        const typeCounts = {};

        state.layout.forEach(function (block) {
            if (!block || typeof block !== "object") {
                return;
            }
            const type = String(block.type || "");
            typeCounts[type] = Number(typeCounts[type] || 0) + 1;
            addedMs += Number(weights[type] || 15);
            if (type === "shortcode") {
                const shortcode = String(
                    block.settings && block.settings.shortcode
                        ? block.settings.shortcode
                        : ""
                );
                if (/\[h4_slider\b/i.test(shortcode)) {
                    addedMs += 180;
                    typeCounts.slider = Number(typeCounts.slider || 0) + 1;
                }
                if (/\[h4_products\b/i.test(shortcode)) {
                    addedMs += 120;
                }
                if (/\[h4_checkout\b/i.test(shortcode)) {
                    addedMs += 180;
                }
                if (/\[h4_search\b/i.test(shortcode)) {
                    addedMs += 90;
                }
            }
        });

        const measuredMs = Math.max(0, Number(state.previewMeasuredMs || 0));
        const totalMs = measuredMs > 0
            ? Math.max(1, Math.round(measuredMs))
            : Math.max(300, Math.round(baseMs));
        const addedRounded = measuredMs > 0
            ? Math.max(0, Math.round(Number(state.previewMeasuredRenderMs || 0)))
            : Math.max(0, Math.round(addedMs));
        const secs = (totalMs / 1000).toFixed(2);
        const label = totalMs < 1800 ? "Fast" : totalMs < 2800 ? "Moderate" : "Heavy";
        if (measuredMs > 0) {
            els.estimate.textContent =
                secs +
                "s measured preview (" +
                label +
                ", " +
                Number(state.layout.length || 0) +
                " elements, " +
                Math.max(0, Math.round(Number(state.previewMeasuredTtfbMs || 0))) +
                " ms TTFB, " +
                addedRounded +
                " ms render)";
        } else {
            els.estimate.textContent =
                "Measuring frontend preview... (" +
                Number(state.layout.length || 0) +
                " elements)";
        }
        updatePerformanceCoach(
            totalMs,
            addedRounded,
            label,
            typeCounts,
            Number(state.layout.length || 0)
        );
    }

    function updatePageLayoutLabel() {
        if (!els.pageLayoutLabel) {
            return;
        }
        const options = pageLayoutOptions();
        const layout = normalizePageLayout(state.pageLayout);
        const label = options[layout] || options.default || "Theme Default";
        els.pageLayoutLabel.textContent = "Layout: " + String(label);
    }

    function encodeSpecPayload(prefix, payload) {
        try {
            const json = JSON.stringify(payload || {});
            const encoded = window.btoa(unescape(encodeURIComponent(json)));
            return String(prefix || "") + encoded;
        } catch (_error) {
            return "";
        }
    }

    function decodeSpecPayload(prefix, raw) {
        let source = String(raw || "").trim();
        if (source === "") {
            return null;
        }
        const marker = String(prefix || "");
        if (marker !== "" && source.indexOf(marker) === 0) {
            source = source.substring(marker.length);
        }
        if (source.charAt(0) === "{") {
            try {
                const parsedJson = JSON.parse(source);
                return parsedJson && typeof parsedJson === "object"
                    ? parsedJson
                    : null;
            } catch (_error) {
                // continue to base64 decode fallback
            }
        }
        try {
            const json = decodeURIComponent(escape(window.atob(source)));
            const parsed = JSON.parse(json);
            return parsed && typeof parsed === "object" ? parsed : null;
        } catch (_error) {
            return null;
        }
    }

    function copyTextToClipboard(text) {
        const value = String(text || "");
        if (value === "") {
            return Promise.resolve(false);
        }
        if (
            navigator.clipboard &&
            typeof navigator.clipboard.writeText === "function"
        ) {
            return navigator.clipboard
                .writeText(value)
                .then(function () {
                    return true;
                })
                .catch(function () {
                    return fallbackCopy(value);
                });
        }
        return Promise.resolve(fallbackCopy(value));
    }

    function readTextFromClipboard() {
        if (
            navigator.clipboard &&
            typeof navigator.clipboard.readText === "function"
        ) {
            return navigator.clipboard
                .readText()
                .then(function (value) {
                    return String(value || "");
                })
                .catch(function () {
                    return "";
                });
        }
        return Promise.resolve("");
    }

    function fallbackCopy(value) {
        const field = document.createElement("textarea");
        field.value = value;
        field.setAttribute("readonly", "readonly");
        field.style.position = "fixed";
        field.style.top = "-2000px";
        field.style.left = "-2000px";
        document.body.appendChild(field);
        field.focus();
        field.select();
        let ok = false;
        try {
            ok = document.execCommand("copy");
        } catch (_error) {
            ok = false;
        }
        document.body.removeChild(field);
        return ok;
    }

    function sanitizeHtmlPreview(value) {
        const raw = String(value || "");
        if (raw.trim() === "") {
            return "";
        }
        const template = document.createElement("template");
        template.innerHTML = raw;
        template.content
            .querySelectorAll("script,style,object,embed,link,meta")
            .forEach(function (node) {
                node.remove();
            });
        template.content.querySelectorAll("*").forEach(function (node) {
            Array.from(node.attributes || []).forEach(function (attr) {
                const name = String(attr.name || "").toLowerCase();
                const valueText = String(attr.value || "");
                if (name.indexOf("on") === 0) {
                    node.removeAttribute(attr.name);
                    return;
                }
                if (
                    (name === "href" || name === "src") &&
                    /^\s*javascript:/i.test(valueText)
                ) {
                    node.removeAttribute(attr.name);
                    return;
                }
                if (node.tagName === "IMG" && name === "srcset") {
                    const srcset = sanitizePreviewSrcset(valueText);
                    if (srcset === "") {
                        node.removeAttribute(attr.name);
                    } else {
                        node.setAttribute("srcset", srcset);
                    }
                    return;
                }
                if (node.tagName === "IMG" && name === "sizes") {
                    const sizes = sanitizePreviewSizes(valueText);
                    if (sizes === "") {
                        node.removeAttribute(attr.name);
                    } else {
                        node.setAttribute("sizes", sizes);
                    }
                    return;
                }
                if (node.tagName === "IMG" && name === "decoding") {
                    const decoding = valueText.trim().toLowerCase();
                    if (["async", "sync", "auto"].indexOf(decoding) === -1) {
                        node.removeAttribute(attr.name);
                    } else {
                        node.setAttribute("decoding", decoding);
                    }
                }
            });
        });
        return template.innerHTML;
    }

    function sanitizePreviewSrcset(value) {
        const raw = String(value || "").trim();
        if (
            raw === "" ||
            raw.length > 8192 ||
            /(?:javascript|vbscript|data|file)\s*:/i.test(raw)
        ) {
            return "";
        }
        const safe = [];
        raw.split(/\s*,\s*/)
            .slice(0, 100)
            .forEach(function (candidate) {
                const match = String(candidate || "")
                    .trim()
                    .match(/^(\S+?)(?:\s+((?:[1-9]\d*)w|(?:(?:[1-9]\d*)(?:\.\d+)?|0\.\d*[1-9]\d*)x))?$/i);
                if (!match) {
                    return;
                }
                let parsed;
                try {
                    parsed = new URL(match[1], window.location.href);
                } catch (_error) {
                    return;
                }
                if (["http:", "https:"].indexOf(parsed.protocol) === -1) {
                    return;
                }
                const descriptor = String(match[2] || "").toLowerCase();
                const normalized = match[1] + (descriptor === "" ? "" : " " + descriptor);
                if (safe.indexOf(normalized) === -1) {
                    safe.push(normalized);
                }
            });
        return safe.join(", ");
    }

    function sanitizePreviewSizes(value) {
        const sizes = String(value || "").trim().replace(/\s+/g, " ");
        if (
            sizes === "" ||
            sizes.length > 2048 ||
            /(?:url|expression)\s*\(|@|[;{}\\`"']/i.test(sizes) ||
            !/^[a-z0-9\s.,%()\/:+*<>=-]+$/i.test(sizes)
        ) {
            return "";
        }
        return sizes;
    }

    function escHtml(value) {
        return String(value)
            .replace(/&/g, "&amp;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;")
            .replace(/"/g, "&quot;")
            .replace(/'/g, "&#039;");
    }

    function escAttr(value) {
        return escHtml(value);
    }
})(jQuery);
