(function () {
    function request(path, payload, options) {
        options = options || {};
        return fetch((window.APD_RUNTIME && window.APD_RUNTIME.restUrl ? window.APD_RUNTIME.restUrl : '') + path, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-WP-Nonce': window.APD_RUNTIME && window.APD_RUNTIME.nonce ? window.APD_RUNTIME.nonce : ''
            },
            body: JSON.stringify(payload || {}),
            signal: options.signal
        }).then(function (response) {
            return response.json();
        });
    }


    function isApdVariationDebugEnabled() {
        return false;
    }

    function getApdVariationDebugStore() {
        return [];
    }

    function getApdVariationDebugSequence() {
        return 0;
    }

    function safeObjectKeys(value) {
        if (!value || typeof value !== 'object' || Array.isArray(value)) {
            return [];
        }
        try {
            return Object.keys(value);
        } catch (error) {
            return [];
        }
    }



    function apdDebugScalar(value) {
        if (value == null) {
            return '';
        }
        if (typeof value === 'number' || typeof value === 'boolean') {
            return value;
        }
        return String(value || '');
    }

    function apdDebugSummarizeObjectList(objects, limit) {
        objects = Array.isArray(objects) ? objects : [];
        limit = typeof limit === 'number' ? limit : 4;
        return {
            present: objects.length > 0,
            count: objects.length,
            samples: objects.slice(0, limit).map(function (object) {
                object = object && typeof object === 'object' ? object : {};
                return {
                    type: apdDebugScalar(object.type || object.objectType || object.kind),
                    id: apdDebugScalar(object.id || object._asukaObjectId || object.uuid || object.objectId),
                    name: apdDebugScalar(object.name || object.label || object._asukaElementName || object.asukaElementName),
                    itemGroup: apdDebugScalar(object.itemGroup || object.group || object._asukaSourceModule),
                    asukaElementId: apdDebugScalar(object._asukaElementId || object.asukaElementId),
                    left: object.left != null ? Number(object.left) : null,
                    top: object.top != null ? Number(object.top) : null,
                    width: object.width != null ? Number(object.width) : null,
                    height: object.height != null ? Number(object.height) : null,
                    srcLength: object.src != null ? String(object.src || '').length : (object.url != null ? String(object.url || '').length : 0),
                    keys: safeObjectKeys(object).slice(0, 14)
                };
            })
        };
    }

    function apdDebugSummarizeByViewBucket(bucket, snapshotMode) {
        var summary = {
            present: false,
            viewCount: 0,
            totalObjects: 0,
            viewIds: [],
            counts: {},
            samples: {}
        };
        if (!bucket || typeof bucket !== 'object' || Array.isArray(bucket)) {
            return summary;
        }
        var keys = safeObjectKeys(bucket);
        summary.present = keys.length > 0;
        summary.viewCount = keys.length;
        summary.viewIds = keys.slice(0, 12);
        keys.forEach(function (viewId) {
            var value = bucket[viewId];
            var objects = [];
            if (snapshotMode && value && typeof value === 'object' && Array.isArray(value.objects)) {
                objects = value.objects;
            } else if (!snapshotMode && Array.isArray(value)) {
                objects = value;
            } else if (!snapshotMode && value && typeof value === 'object' && Array.isArray(value.objects)) {
                objects = value.objects;
            }
            summary.counts[String(viewId)] = objects.length;
            summary.totalObjects += objects.length;
            if (objects.length) {
                summary.samples[String(viewId)] = apdDebugSummarizeObjectList(objects, 2).samples;
            }
        });
        return summary;
    }

    function apdDebugMaybeAddBucket(target, name, bucket, snapshotMode) {
        var summary = apdDebugSummarizeByViewBucket(bucket, !!snapshotMode);
        if (summary.present) {
            target[name] = summary;
        }
    }

    function apdDebugViewsSummary(value) {
        value = value && typeof value === 'object' ? value : {};
        var views = [];
        var shape = 'none';
        var activeViewId = value.activeViewId != null ? String(value.activeViewId || '') : '';
        if (Array.isArray(value.views)) {
            views = value.views;
            shape = 'array';
        } else if (value.views && typeof value.views === 'object' && Array.isArray(value.views.views)) {
            views = value.views.views;
            shape = 'bucket';
            activeViewId = value.views.activeViewId != null ? String(value.views.activeViewId || '') : activeViewId;
        }
        return {
            shape: shape,
            count: views.length,
            activeViewId: activeViewId,
            ids: views.slice(0, 12).map(function (view, index) {
                if (!view || typeof view !== 'object') {
                    return 'index:' + index;
                }
                return view.id != null ? String(view.id) : (view.name != null ? String(view.name) : 'index:' + index);
            })
        };
    }

    function apdDebugSummarizePayloadRestorePaths(value, depth) {
        depth = typeof depth === 'number' ? depth : 0;
        if (!value || typeof value !== 'object') {
            return {
                present: !!value,
                type: typeof value
            };
        }
        var canvas = value.canvas && typeof value.canvas === 'object' && !Array.isArray(value.canvas) ? value.canvas : {};
        var objectBuckets = {};
        var snapshotBuckets = {};
        apdDebugMaybeAddBucket(objectBuckets, 'objects.byView', value.objects && !Array.isArray(value.objects) ? value.objects.byView : null, false);
        apdDebugMaybeAddBucket(objectBuckets, 'documentObjectsByView', value.documentObjectsByView, false);
        apdDebugMaybeAddBucket(objectBuckets, 'objectsByView', value.objectsByView, false);
        apdDebugMaybeAddBucket(objectBuckets, 'byView', value.byView, false);
        apdDebugMaybeAddBucket(objectBuckets, 'canvas.objects.byView', canvas.objects && !Array.isArray(canvas.objects) ? canvas.objects.byView : null, false);
        apdDebugMaybeAddBucket(objectBuckets, 'canvas.documentObjectsByView', canvas.documentObjectsByView, false);
        apdDebugMaybeAddBucket(objectBuckets, 'canvas.objectsByView', canvas.objectsByView, false);
        apdDebugMaybeAddBucket(objectBuckets, 'canvas.byView', canvas.byView, false);

        apdDebugMaybeAddBucket(snapshotBuckets, 'snapshotsByView', value.snapshotsByView, true);
        apdDebugMaybeAddBucket(snapshotBuckets, 'snapshots.snapshotsByView', value.snapshots && !Array.isArray(value.snapshots) ? value.snapshots.snapshotsByView : null, true);
        apdDebugMaybeAddBucket(snapshotBuckets, 'viewSnapshots.snapshotsByView', value.viewSnapshots && !Array.isArray(value.viewSnapshots) ? value.viewSnapshots.snapshotsByView : null, true);
        apdDebugMaybeAddBucket(snapshotBuckets, 'viewSnapshots', value.viewSnapshots, true);
        apdDebugMaybeAddBucket(snapshotBuckets, 'canvas.snapshotsByView', canvas.snapshotsByView, true);
        apdDebugMaybeAddBucket(snapshotBuckets, 'canvas.snapshots.snapshotsByView', canvas.snapshots && !Array.isArray(canvas.snapshots) ? canvas.snapshots.snapshotsByView : null, true);
        apdDebugMaybeAddBucket(snapshotBuckets, 'canvas.viewSnapshots.snapshotsByView', canvas.viewSnapshots && !Array.isArray(canvas.viewSnapshots) ? canvas.viewSnapshots.snapshotsByView : null, true);
        apdDebugMaybeAddBucket(snapshotBuckets, 'canvas.viewSnapshots', canvas.viewSnapshots, true);

        var nested = {};
        if (depth < 1) {
            ['initialDocument', 'document', 'documentState', 'initialState', 'state', 'legacy'].forEach(function (key) {
                if (value[key] && typeof value[key] === 'object') {
                    nested[key] = apdDebugSummarizePayloadRestorePaths(value[key], depth + 1);
                }
            });
        }

        return {
            present: true,
            type: Array.isArray(value) ? 'array' : 'object',
            topKeys: safeObjectKeys(value).slice(0, 40),
            views: apdDebugViewsSummary(value),
            rootObjects: apdDebugSummarizeObjectList(Array.isArray(value.objects) ? value.objects : [], 4),
            objectBuckets: objectBuckets,
            snapshotBuckets: snapshotBuckets,
            selectedObjectsByView: apdDebugSummarizeByViewBucket(getPayloadObjectsByView(value), false),
            selectedSnapshotsByView: apdDebugSummarizeByViewBucket(getPayloadSnapshotsByView(value), true),
            nested: nested
        };
    }

    function getPayloadSnapshotsByView(value) {
        if (!value || typeof value !== 'object') {
            return {};
        }
        var canvas = value.canvas && typeof value.canvas === 'object' && !Array.isArray(value.canvas) ? value.canvas : null;
        var candidates = [
            value.snapshotsByView,
            value.snapshots && value.snapshots.snapshotsByView,
            value.viewSnapshots && value.viewSnapshots.snapshotsByView,
            value.viewSnapshots,
            canvas && canvas.snapshotsByView,
            canvas && canvas.snapshots && canvas.snapshots.snapshotsByView,
            canvas && canvas.viewSnapshots && canvas.viewSnapshots.snapshotsByView,
            canvas && canvas.viewSnapshots
        ];
        for (var i = 0; i < candidates.length; i += 1) {
            var candidate = candidates[i];
            if (candidate && typeof candidate === 'object' && !Array.isArray(candidate) && safeObjectKeys(candidate).length) {
                return candidate;
            }
        }
        return {};
    }

    function deriveObjectsByViewFromSnapshots(snapshotsByView, baseByView) {
        var next = baseByView && typeof baseByView === 'object' && !Array.isArray(baseByView) ? clonePlainObject(baseByView) : {};
        snapshotsByView = snapshotsByView && typeof snapshotsByView === 'object' && !Array.isArray(snapshotsByView) ? snapshotsByView : {};
        safeObjectKeys(snapshotsByView).forEach(function (viewId) {
            if (Array.isArray(next[viewId]) && next[viewId].length) {
                return;
            }
            var snapshot = snapshotsByView[viewId];
            if (snapshot && typeof snapshot === 'object' && Array.isArray(snapshot.objects)) {
                next[viewId] = clonePlainObject(snapshot.objects);
            }
        });
        return next;
    }

    function getPayloadRootObjects(value) {
        if (!value || typeof value !== 'object') {
            return [];
        }
        var canvas = value.canvas && typeof value.canvas === 'object' && !Array.isArray(value.canvas) ? value.canvas : null;
        if (Array.isArray(value.objects)) {
            return value.objects;
        }
        if (value.objects && typeof value.objects === 'object' && Array.isArray(value.objects.objects)) {
            return value.objects.objects;
        }
        if (canvas && Array.isArray(canvas.objects)) {
            return canvas.objects;
        }
        if (canvas && canvas.objects && typeof canvas.objects === 'object' && Array.isArray(canvas.objects.objects)) {
            return canvas.objects.objects;
        }
        return [];
    }

    function getPayloadFallbackViewId(value) {
        if (!value || typeof value !== 'object') {
            return 'view-1';
        }
        if (value.activeViewId != null && String(value.activeViewId)) {
            return String(value.activeViewId);
        }
        if (value.views && typeof value.views === 'object' && value.views.activeViewId != null && String(value.views.activeViewId)) {
            return String(value.views.activeViewId);
        }
        var views = [];
        if (Array.isArray(value.views)) {
            views = value.views;
        } else if (value.views && typeof value.views === 'object' && Array.isArray(value.views.views)) {
            views = value.views.views;
        }
        if (views[0] && typeof views[0] === 'object' && views[0].id != null) {
            return String(views[0].id);
        }
        return 'view-1';
    }

    function getPayloadObjectsByView(value) {
        if (!value || typeof value !== 'object') {
            return {};
        }
        var canvas = value.canvas && typeof value.canvas === 'object' && !Array.isArray(value.canvas) ? value.canvas : null;
        var candidates = [
            value.objects && !Array.isArray(value.objects) && value.objects.byView,
            value.documentObjectsByView,
            value.objectsByView,
            value.byView,
            canvas && canvas.objects && !Array.isArray(canvas.objects) && canvas.objects.byView,
            canvas && canvas.documentObjectsByView,
            canvas && canvas.objectsByView,
            canvas && canvas.byView
        ];
        var selected = {};
        for (var i = 0; i < candidates.length; i += 1) {
            var candidate = candidates[i];
            if (candidate && typeof candidate === 'object' && !Array.isArray(candidate) && safeObjectKeys(candidate).length) {
                selected = clonePlainObject(candidate) || {};
                break;
            }
        }

        selected = deriveObjectsByViewFromSnapshots(getPayloadSnapshotsByView(value), selected);

        var rootObjects = getPayloadRootObjects(value);
        if (rootObjects.length) {
            var fallbackViewId = getPayloadFallbackViewId(value);
            if (!Array.isArray(selected[fallbackViewId]) || !selected[fallbackViewId].length) {
                selected[fallbackViewId] = clonePlainObject(rootObjects);
            }
        }

        return selected && typeof selected === 'object' && !Array.isArray(selected) ? selected : {};
    }

    function summarizeViewContainer(value) {
        if (!value || typeof value !== 'object') {
            return { hasValue: !!value, type: typeof value, viewsCount: 0, activeViewId: '', objectCount: 0, snapshotCount: 0 };
        }
        var views = [];
        var activeViewId = value.activeViewId != null ? String(value.activeViewId) : '';
        if (Array.isArray(value.views)) {
            views = value.views;
        } else if (value.views && typeof value.views === 'object' && Array.isArray(value.views.views)) {
            views = value.views.views;
            activeViewId = value.views.activeViewId != null ? String(value.views.activeViewId) : activeViewId;
        } else if (value.document && typeof value.document === 'object') {
            return summarizeViewContainer(value.document);
        } else if (value.initialDocument && typeof value.initialDocument === 'object') {
            return summarizeViewContainer(value.initialDocument);
        } else if (value.documentState && typeof value.documentState === 'object') {
            return summarizeViewContainer(value.documentState);
        }

        var snapshotsByView = getPayloadSnapshotsByView(value);
        var objectsByView = getPayloadObjectsByView(value);
        var rootObjects = [];
        var snapshotKeys = safeObjectKeys(snapshotsByView);
        var objectViewKeys = safeObjectKeys(objectsByView);
        var objectCount = 0;
        objectViewKeys.forEach(function (key) {
            if (Array.isArray(objectsByView[key])) {
                objectCount += objectsByView[key].length;
            }
        });
        snapshotKeys.forEach(function (key) {
            if (Array.isArray(objectsByView[key]) && objectsByView[key].length) {
                return;
            }
            var snapshot = snapshotsByView[key];
            if (snapshot && Array.isArray(snapshot.objects)) {
                objectCount += snapshot.objects.length;
            }
        });

        return {
            hasValue: true,
            type: 'object',
            topKeys: safeObjectKeys(value),
            viewsCount: Array.isArray(views) ? views.length : 0,
            activeViewId: activeViewId,
            firstViewIds: Array.isArray(views) ? views.slice(0, 4).map(function (item) {
                if (!item || typeof item !== 'object') {
                    return '';
                }
                return item.id != null ? String(item.id) : (item.name != null ? String(item.name) : '');
            }).filter(Boolean) : [],
            snapshotCount: snapshotKeys.length,
            snapshotViewIds: snapshotKeys.slice(0, 4),
            objectViewCount: objectViewKeys.length,
            objectViewIds: objectViewKeys.slice(0, 4),
            objectCount: objectCount,
            drawingAreasCount: Array.isArray(value.drawingAreas) ? value.drawingAreas.length : (value.drawingAreas && Array.isArray(value.drawingAreas.zones) ? value.drawingAreas.zones.length : 0)
        };
    }

    function summarizeMountPayload(payload) {
        payload = payload && typeof payload === 'object' ? payload : {};
        var stateDocument = payload.initialState && typeof payload.initialState === 'object'
            ? (payload.initialState.initialDocument || payload.initialState.document || payload.initialState)
            : null;
        var context = payload.context && typeof payload.context === 'object' ? payload.context : {};
        return {
            topKeys: safeObjectKeys(payload),
            hasInitialDocument: !!(payload.initialDocument && typeof payload.initialDocument === 'object'),
            hasInitialState: !!(payload.initialState && typeof payload.initialState === 'object'),
            initialDocument: summarizeViewContainer(payload.initialDocument),
            initialStateDocument: summarizeViewContainer(stateDocument),
            viewsCount: Array.isArray(payload.views) ? payload.views.length : 0,
            drawingZonesCount: Array.isArray(payload.drawingZones) ? payload.drawingZones.length : 0,
            layout: summarizeLayoutPayloadDebug(payload.layout),
            layoutKeys: safeObjectKeys(payload.layout),
            contextKeys: safeObjectKeys(payload.context),
            context: {
                productId: Number(context.productId || 0) || 0,
                configId: Number(context.configId || 0) || 0,
                variationId: Number(context.variationId || 0) || 0,
                userDesignId: Number(context.userDesignId || 0) || 0,
                resumeDesignId: Number(context.resumeDesignId || 0) || 0,
                replaceCartItemKey: context.replaceCartItemKey || '',
                cartLineToken: context.cartLineToken || '',
                apdBootStrategy: context.apdBootStrategy || '',
                apdStateBridgeEnabled: !!context.apdStateBridgeEnabled,
            },
            templateDebug: summarizeTemplateDebugContext(payload)
        };
    }

    function summarizeLayoutPayloadDebug(layout) {
        layout = layout && typeof layout === 'object' && !Array.isArray(layout) ? layout : {};
        var zoneItemCounts = {};
        var itemIdsByZone = {};
        var itemIds = [];
        ['left', 'right', 'top', 'bottom'].forEach(function (zone) {
            var zoneConfig = layout[zone] && typeof layout[zone] === 'object' ? layout[zone] : {};
            var items = Array.isArray(zoneConfig.items) ? zoneConfig.items : [];
            if (!items.length && layout.blocksByZone && layout.blocksByZone[zone] && Array.isArray(layout.blocksByZone[zone])) {
                items = layout.blocksByZone[zone];
            }
            zoneItemCounts[zone] = items.length;
            itemIdsByZone[zone] = [];
            items.forEach(function (item) {
                if (!item || typeof item !== 'object') {
                    return;
                }
                var id = item.id != null ? String(item.id) : (item.kind != null ? String(item.kind) : '');
                if (id) {
                    itemIds.push(id);
                    itemIdsByZone[zone].push(id);
                }
            });
        });
        return {
            hasLayout: !!Object.keys(layout).length,
            topKeys: safeObjectKeys(layout),
            zoneItemCounts: zoneItemCounts,
            itemIdsByZone: itemIdsByZone,
            itemIds: itemIds
        };
    }

    function summarizeTemplateDebugContext(config) {
        config = config && typeof config === 'object' ? config : {};
        var context = config.context && typeof config.context === 'object' ? config.context : {};
        var debug = context.apdTemplateLayoutDebug && typeof context.apdTemplateLayoutDebug === 'object'
            ? context.apdTemplateLayoutDebug
            : {};
        return {
            configId: Number(context.configId || debug.configId || 0) || 0,
            productId: Number(context.productId || debug.productId || 0) || 0,
            variationId: Number(context.variationId || debug.variationId || 0) || 0,
            configTitle: debug.configTitle || '',
            templateId: Number(debug.templateId || 0) || 0,
            templateTitle: debug.templateTitle || '',
            templateExists: !!debug.templateExists,
            templateHasLayout: !!debug.templateHasLayout,
            sourceProductHasBootViews: !!debug.sourceProductHasBootViews,
            productLayout: debug.productLayout || null,
            templateLayout: debug.templateLayout || null,
            mergedConfigLayout: debug.mergedConfigLayout || null,
            frontendLayout: debug.frontendLayout || summarizeLayoutPayloadDebug(config.layout),
            layoutSource: debug.layoutSource || '',
            frontendLayoutIsNull: !!debug.frontendLayoutIsNull || config.layout === null,
            frontendInitialDocument: debug.frontendInitialDocument || null,
            frontendInitialState: debug.frontendInitialState || null,
            bootStrategy: context.apdBootStrategy || ''
        };
    }

    function summarizeRegistryPayloadDebug(payload) {
        payload = payload && typeof payload === 'object' ? payload : {};
        var config = payload.config && typeof payload.config === 'object' ? payload.config : {};
        var fullState = getRegistryFullState(payload);
        var documentState = getRegistryDocumentState(payload);
        return {
            productId: Number(payload.productId || 0) || 0,
            configId: Number(payload.configId || 0) || 0,
            variationId: Number(payload.variationId || 0) || 0,
            payloadKeys: safeObjectKeys(payload),
            hasFullState: !!(fullState && typeof fullState === 'object' && safeObjectKeys(fullState).length),
            hasDocumentState: !!(documentState && typeof documentState === 'object' && safeObjectKeys(documentState).length),
            config: summarizeMountPayload(config),
            fullStateKeys: fullState && typeof fullState === 'object' ? safeObjectKeys(fullState) : [],
            fullStateLayout: summarizeLayoutPayloadDebug(fullState && typeof fullState === 'object' ? fullState.layout : null),
            fullStateScopeLayout: !!(fullState && fullState.scope && fullState.scope.layout),
            fullStateDocument: summarizeViewContainer(fullState && typeof fullState === 'object' ? (fullState.initialDocument || fullState.document || fullState.documentState || fullState) : null),
            fullStateInitialStateDocument: summarizeViewContainer(fullState && fullState.initialState && typeof fullState.initialState === 'object' ? (fullState.initialState.initialDocument || fullState.initialState.document || fullState.initialState) : null),
            documentState: summarizeViewContainer(documentState)
        };
    }

    function summarizeRegistryMapDebug(map) {
        var out = {};
        map = map && typeof map === 'object' ? map : {};
        Object.keys(map).forEach(function (key) {
            out[key] = summarizeRegistryPayloadDebug(map[key]);
        });
        return out;
    }

    function getRuntimeShellDebugState(shell) {
        if (window.APDRuntimeBridge && typeof window.APDRuntimeBridge.getShellDebugState === 'function') {
            try {
                return window.APDRuntimeBridge.getShellDebugState(shell);
            } catch (error) {
                return { error: error && error.message ? error.message : String(error) };
            }
        }
        return null;
    }

    function logApdTemplateCheck(tag, data) {
        if (!isApdVariationDebugEnabled()) {
            return;
        }
        var payload = data || {};
        logApdVariationDebug('TEMPLATE_CHECK:' + String(tag || ''), payload);
        if (!window.APDTemplateDebugDump) {
            window.APDTemplateDebugDump = function () {
                var logs = getApdVariationDebugStore().filter(function (item) {
                    return item && typeof item.tag === 'string' && item.tag.indexOf('TEMPLATE_CHECK:') === 0;
                });
                return logs;
            };
        }
    }

    function safeParseJson(raw, fallback) {
        if (!raw || !String(raw).trim()) {
            return fallback;
        }
        try {
            return JSON.parse(raw);
        } catch (error) {
            return fallback;
        }
    }

    function getApdProductRegistryStore() {
        if (!window.__APD_PRODUCT_REGISTRY || typeof window.__APD_PRODUCT_REGISTRY !== 'object') {
            window.__APD_PRODUCT_REGISTRY = {};
        }
        return window.__APD_PRODUCT_REGISTRY;
    }

    function getApdMountSequence() {
        window.__APD_MOUNT_SEQ = Number(window.__APD_MOUNT_SEQ || 0) + 1;
        return window.__APD_MOUNT_SEQ;
    }

    function clonePlainObject(value) {
        if (!value || typeof value !== 'object') {
            return value;
        }
        try {
            return JSON.parse(JSON.stringify(value));
        } catch (error) {
            return value;
        }
    }

    function buildCanonicalDocumentState(value) {
        if (value && value.format === 'asuka-state' && Number(value.schemaVersion) === 2) {
            return clonePlainObject(value);
        }
        var document = normalizeCartDocumentPayload(value);
        if (!document || typeof document !== 'object') {
            return null;
        }
        return {
            format: 'asuka-state',
            schemaVersion: 2,
            exportedAt: (new Date()).toISOString(),
            scope: {
                document: {
                    views: true,
                    drawingAreas: true,
                    snapshots: true,
                    objects: true,
                    selection: true,
                    viewportByView: true,
                    scenes3d: true,
                    asukaDocument: true
                },
                catalog: { elements: true }
            },
            document: document
        };
    }

    function getShellPayloadRegistryMap(switcher) {
        if (!switcher) {
            return {};
        }
        if (switcher.__apdPayloadRegistry && typeof switcher.__apdPayloadRegistry === 'object') {
            return switcher.__apdPayloadRegistry;
        }
        var registryId = switcher.getAttribute('data-apd-registry-id') || '';
        var store = getApdProductRegistryStore();
        if (registryId && store[registryId] && typeof store[registryId] === 'object') {
            switcher.__apdPayloadRegistry = store[registryId];
            return switcher.__apdPayloadRegistry;
        }
        var script = switcher.querySelector('.apd-shell-payload-map');
        var payloads = script ? safeParseJson(script.textContent || '{}', {}) : {};
        payloads = payloads && typeof payloads === 'object' ? payloads : {};
        if (registryId) {
            store[registryId] = payloads;
        }
        switcher.__apdPayloadRegistry = payloads;
        return payloads;
    }

    function getShellBlueprint(switcher, host) {
        if (!switcher) {
            return null;
        }
        if (switcher.__apdShellBlueprint) {
            return switcher.__apdShellBlueprint;
        }
        var sourceShell = host && host.querySelector ? host.querySelector('[data-apd-shell]:not([hidden])') : null;
        if (!sourceShell) {
            var template = switcher.querySelector('template[data-apd-shell-template]');
            sourceShell = template && template.content ? template.content.querySelector('[data-apd-shell]') : null;
        }
        if (!sourceShell || !sourceShell.cloneNode) {
            return null;
        }
        switcher.__apdShellBlueprint = sourceShell.cloneNode(true);
        return switcher.__apdShellBlueprint;
    }

    function getRegistryMountConfig(payload) {
        payload = payload && typeof payload === 'object' ? payload : {};
        var config = clonePlainObject(payload.config && typeof payload.config === 'object' ? payload.config : {}) || {};
        var fullState = getRegistryFullState(payload);
        var documentState = getRegistryDocumentState(payload);

        if (fullState && fullState.format === 'asuka-state' && Number(fullState.schemaVersion) === 2) {
            config.initialState = clonePlainObject(fullState);
        } else if (documentState && typeof documentState === 'object') {
            config.initialState = buildCanonicalDocumentState(documentState);
        }
        if (config.initialState) {
            config.boot = {
                mode: 'initialState',
                state: clonePlainObject(config.initialState)
            };
        }
        delete config.initialDocument;

        return config;
    }

    function resetShellPayloadFields(shell, payload, key) {
        if (!shell) {
            return;
        }
        payload = payload && typeof payload === 'object' ? payload : {};
        var config = getRegistryMountConfig(payload);
        var context = config.context && typeof config.context === 'object' ? config.context : {};

        shell.dataset.apdShellKey = key || '';
        shell.dataset.configId = String(Number(payload.configId || 0) || 0);
        shell.dataset.productId = String(Number(payload.productId || 0) || 0);
        shell.dataset.variationId = String(Number(payload.variationId || 0) || 0);
        shell.dataset.apdCartEdit = (context.isCartEdit || context.replaceCartItemKey) ? '1' : '0';
        shell.dataset.apdCartSubmitLabel = context.cartSubmitLabel ? String(context.cartSubmitLabel) : '';
        var templateDebug = summarizeTemplateDebugContext(config || {});
        shell.dataset.templateId = String(Number(templateDebug.templateId || 0) || 0);
        shell.dataset.templateTitle = String(templateDebug.templateTitle || '');
        shell.dataset.configTitle = String(templateDebug.configTitle || '');
        shell.dataset.apdShellBound = '0';

        shell.__apdInstance = null;
        shell.__apdMountConfig = null;
        shell.__apdRawMountConfig = null;
        shell.__apdCreateMountConfig = null;
        shell.__apdBootPayload = null;
        shell.__apdBootAppliedAtCreate = false;

        var mount = shell.querySelector('[data-apd-mount]');
        if (mount) {
            mount.innerHTML = '';
            mount.dataset.apdMounted = '0';
            mount.id = 'apd-mount-runtime-' + getApdMountSequence();
            mount.style.height = config.layout && config.layout.height ? String(config.layout.height) : '720px';
        }

        var configNode = shell.querySelector('.apd-config');
        if (configNode) {
            configNode.textContent = JSON.stringify(clonePlainObject(config || {}));
        }

        logApdVariationDebug('resetShellPayloadFields:applied', {
            key: key || '',
            payloadConfigId: Number(payload.configId || 0) || 0,
            payloadProductId: Number(payload.productId || 0) || 0,
            payloadVariationId: Number(payload.variationId || 0) || 0,
            configJsonLength: configNode ? String(configNode.textContent || '').length : 0,
            payloadSummary: summarizeMountPayload(config || {}),
            shell: summarizeShellDebug(shell)
        });

        [
            '[data-apd-design-json]',
            '[data-apd-state-json]',
            '[data-apd-preview-data]',
            '[data-apd-preview-url]',
            '[data-apd-preview-attachment-id]',
            '[data-apd-price-adjustment]',
            '[data-apd-price-total]',
            '[data-apd-price-breakdown]',
            '[data-apd-pricing-payload]'
        ].forEach(function (selector) {
            var field = shell.querySelector(selector);
            if (field) {
                field.value = selector === '[data-apd-price-adjustment]' || selector === '[data-apd-price-total]' ? '0' : '';
            }
        });

        var configField = shell.querySelector('input[name="apd_config_id"]');
        if (configField) { configField.value = String(Number(payload.configId || 0) || 0); }
        var productField = shell.querySelector('input[name="apd_product_id"]');
        if (productField) { productField.value = String(Number(payload.productId || 0) || 0); }
        var variationField = shell.querySelector('[data-apd-variation-id]');
        if (variationField) { variationField.value = Number(payload.variationId || 0) > 0 ? String(Number(payload.variationId || 0)) : ''; }
        var attributesField = shell.querySelector('[data-apd-variation-attributes]');
        if (attributesField) { attributesField.value = ''; }
        var designIdField = shell.querySelector('[data-apd-user-design-id]');
        if (designIdField) { designIdField.value = context.userDesignId != null ? String(context.userDesignId) : ''; }
        var cartLineTokenField = shell.querySelector('[data-apd-cart-line-token]');
        if (cartLineTokenField) { cartLineTokenField.value = context.cartLineToken != null ? String(context.cartLineToken) : ''; }
        var replaceCartField = shell.querySelector('[data-apd-replace-cart-item-key]');
        if (replaceCartField) { replaceCartField.value = context.replaceCartItemKey != null ? String(context.replaceCartItemKey) : ''; }
        seedShellCartDocumentFromRegistryPayload(shell, payload, key || '', 'reset-shell-payload-fields');
    }


    function updateLiveShellRegistryPayloadFields(shell, payload, key) {
        if (!shell) {
            return;
        }
        payload = payload && typeof payload === 'object' ? payload : {};
        var config = payload.config && typeof payload.config === 'object' ? payload.config : {};
        var context = config.context && typeof config.context === 'object' ? config.context : {};

        shell.dataset.apdShellKey = key || '';
        shell.dataset.configId = String(Number(payload.configId || 0) || 0);
        shell.dataset.productId = String(Number(payload.productId || 0) || 0);
        shell.dataset.variationId = String(Number(payload.variationId || 0) || 0);
        shell.dataset.apdCartEdit = (context.isCartEdit || context.replaceCartItemKey) ? '1' : '0';
        shell.dataset.apdCartSubmitLabel = context.cartSubmitLabel ? String(context.cartSubmitLabel) : '';
        var templateDebug = summarizeTemplateDebugContext(config || {});
        shell.dataset.templateId = String(Number(templateDebug.templateId || 0) || 0);
        shell.dataset.templateTitle = String(templateDebug.templateTitle || '');
        shell.dataset.configTitle = String(templateDebug.configTitle || '');

        var configNode = shell.querySelector('.apd-config');
        if (configNode) {
            configNode.textContent = JSON.stringify(clonePlainObject(config || {}));
        }
        shell.__apdRawMountConfig = clonePlainObject(config || {});
        shell.__apdMountConfig = clonePlainObject(config || {});
        shell.__apdCreateMountConfig = clonePlainObject(config || {});

        var configField = shell.querySelector('input[name="apd_config_id"]');
        if (configField) { configField.value = String(Number(payload.configId || 0) || 0); }
        var productField = shell.querySelector('input[name="apd_product_id"]');
        if (productField) { productField.value = String(Number(payload.productId || 0) || 0); }
        var variationField = shell.querySelector('[data-apd-variation-id]');
        if (variationField) { variationField.value = Number(payload.variationId || 0) > 0 ? String(Number(payload.variationId || 0)) : ''; }
        var attributesField = shell.querySelector('[data-apd-variation-attributes]');
        if (attributesField) { attributesField.value = ''; }
        var designIdField = shell.querySelector('[data-apd-user-design-id]');
        if (designIdField) { designIdField.value = context.userDesignId != null ? String(context.userDesignId) : ''; }
        var cartLineTokenField = shell.querySelector('[data-apd-cart-line-token]');
        if (cartLineTokenField) { cartLineTokenField.value = context.cartLineToken != null ? String(context.cartLineToken) : ''; }
        var replaceCartField = shell.querySelector('[data-apd-replace-cart-item-key]');
        if (replaceCartField) { replaceCartField.value = context.replaceCartItemKey != null ? String(context.replaceCartItemKey) : ''; }
        seedShellCartDocumentFromRegistryPayload(shell, payload, key || '', 'update-live-shell-payload-fields');

        logApdVariationDebug('updateLiveShellRegistryPayloadFields:applied', {
            key: key || '',
            payloadConfigId: Number(payload.configId || 0) || 0,
            payloadProductId: Number(payload.productId || 0) || 0,
            payloadVariationId: Number(payload.variationId || 0) || 0,
            configJsonLength: configNode ? String(configNode.textContent || '').length : 0,
            payloadSummary: summarizeMountPayload(config || {}),
            shell: summarizeShellDebug(shell)
        });
    }


    function getRegistryDocumentState(payload) {
        if (!payload || typeof payload !== 'object') {
            return null;
        }
        if (payload.document && typeof payload.document === 'object') {
            return normalizeCartDocumentPayload(payload.document);
        }
        var config = payload.config && typeof payload.config === 'object' ? payload.config : {};
        if (config.document && typeof config.document === 'object') {
            return normalizeCartDocumentPayload(config.document);
        }
        if (config.initialDocument && typeof config.initialDocument === 'object') {
            return normalizeCartDocumentPayload(config.initialDocument);
        }
        return null;
    }


    function getRegistryFullState(payload) {
        if (!payload || typeof payload !== 'object') {
            return null;
        }
        if (payload.state && typeof payload.state === 'object') {
            return clonePlainObject(payload.state);
        }
        var config = payload.config && typeof payload.config === 'object' ? payload.config : {};
        if (config.state && typeof config.state === 'object') {
            return clonePlainObject(config.state);
        }
        return null;
    }





    function hasDirectCartViews(value) {
        if (!value || typeof value !== 'object') {
            return false;
        }
        if (Array.isArray(value.views) && value.views.length) {
            return true;
        }
        return !!(value.views && typeof value.views === 'object' && Array.isArray(value.views.views) && value.views.views.length);
    }

    function normalizeCartDrawingAreaZone(zone, fallbackViewId) {
        if (!zone || typeof zone !== 'object' || Array.isArray(zone)) {
            return null;
        }
        var next = clonePlainObject(zone) || {};
        var viewId = next.viewId != null ? String(next.viewId || '') : (next.view != null ? String(next.view || '') : (next.view_id != null ? String(next.view_id || '') : String(fallbackViewId || '')));
        if (viewId) {
            next.viewId = viewId;
        }
        if (!next.id && next.uid != null) {
            next.id = String(next.uid);
        }
        if (!next.id) {
            next.id = 'drawing-area-' + String(viewId || 'view') + '-' + String(Math.random()).slice(2);
        }
        if (next.left == null && next.x != null) next.left = next.x;
        if (next.top == null && next.y != null) next.top = next.y;
        if (next.x == null && next.left != null) next.x = next.left;
        if (next.y == null && next.top != null) next.y = next.top;
        ['left', 'top', 'x', 'y', 'width', 'height'].forEach(function (key) {
            if (next[key] == null || next[key] === '') {
                return;
            }
            var numeric = Number(next[key]);
            if (Number.isFinite(numeric)) {
                next[key] = numeric;
            }
        });
        return next;
    }

    function groupCartDrawingAreasByView(zones, fallbackViewId) {
        var byView = {};
        if (!Array.isArray(zones)) {
            return byView;
        }
        zones.forEach(function (zone) {
            var normalized = normalizeCartDrawingAreaZone(zone, fallbackViewId || '');
            if (!normalized) {
                return;
            }
            var viewId = normalized.viewId != null ? String(normalized.viewId || '') : String(fallbackViewId || '');
            if (!viewId) {
                viewId = '__default__';
            }
            if (!Array.isArray(byView[viewId])) {
                byView[viewId] = [];
            }
            byView[viewId].push(normalized);
        });
        return byView;
    }

    function flattenCartDrawingAreasByView(byView) {
        var zones = [];
        if (!byView || typeof byView !== 'object' || Array.isArray(byView)) {
            return zones;
        }
        safeObjectKeys(byView).forEach(function (viewId) {
            if (!Array.isArray(byView[viewId])) {
                return;
            }
            byView[viewId].forEach(function (zone) {
                var normalized = normalizeCartDrawingAreaZone(zone, viewId === '__default__' ? '' : viewId);
                if (normalized) {
                    zones.push(normalized);
                }
            });
        });
        return zones;
    }

    function normalizeCartDrawingAreasPayload(source, activeViewId) {
        var byView = {};
        var activeDrawingAreaId = source && source.activeDrawingAreaId != null ? source.activeDrawingAreaId : null;
        if (!source || typeof source !== 'object') {
            return null;
        }
        if (source.drawingAreas && typeof source.drawingAreas === 'object' && !Array.isArray(source.drawingAreas)) {
            if (source.drawingAreas.activeDrawingAreaId != null) {
                activeDrawingAreaId = source.drawingAreas.activeDrawingAreaId;
            }
            if (source.drawingAreas.byView && typeof source.drawingAreas.byView === 'object' && !Array.isArray(source.drawingAreas.byView)) {
                safeObjectKeys(source.drawingAreas.byView).forEach(function (viewId) {
                    var zones = Array.isArray(source.drawingAreas.byView[viewId]) ? source.drawingAreas.byView[viewId] : [];
                    var grouped = groupCartDrawingAreasByView(zones, viewId === '__default__' ? '' : viewId);
                    Object.keys(grouped).forEach(function (key) {
                        byView[key] = (byView[key] || []).concat(grouped[key]);
                    });
                });
            } else if (Array.isArray(source.drawingAreas.zones)) {
                byView = groupCartDrawingAreasByView(source.drawingAreas.zones, activeViewId || '');
            }
        } else if (source.drawingAreasByView && typeof source.drawingAreasByView === 'object' && !Array.isArray(source.drawingAreasByView)) {
            safeObjectKeys(source.drawingAreasByView).forEach(function (viewId) {
                var zones = Array.isArray(source.drawingAreasByView[viewId]) ? source.drawingAreasByView[viewId] : [];
                var grouped = groupCartDrawingAreasByView(zones, viewId === '__default__' ? '' : viewId);
                Object.keys(grouped).forEach(function (key) {
                    byView[key] = (byView[key] || []).concat(grouped[key]);
                });
            });
        } else if (Array.isArray(source.drawingZones)) {
            byView = groupCartDrawingAreasByView(source.drawingZones, activeViewId || '');
        }
        if (!safeObjectKeys(byView).length) {
            return null;
        }
        var flat = flattenCartDrawingAreasByView(byView);
        return {
            byView: byView,
            zones: activeViewId && Array.isArray(byView[activeViewId]) ? clonePlainObject(byView[activeViewId]) : flat,
            activeDrawingAreaId: activeDrawingAreaId
        };
    }

    function normalizeCartDocumentPayload(value) {
        if (!value || typeof value !== 'object') {
            return value || null;
        }

        var source = value;
        if (!hasDirectCartViews(source)) {
            if (source.document && typeof source.document === 'object') {
                source = source.document;
            } else if (source.initialDocument && typeof source.initialDocument === 'object') {
                source = source.initialDocument;
            }
        }

        var viewList = [];
        var activeViewId = source.activeViewId != null ? String(source.activeViewId || '') : '';
        if (Array.isArray(source.views)) {
            viewList = clonePlainObject(source.views);
        } else if (source.views && typeof source.views === 'object' && Array.isArray(source.views.views)) {
            viewList = clonePlainObject(source.views.views);
            activeViewId = source.views.activeViewId != null ? String(source.views.activeViewId || '') : activeViewId;
        }
        if (!activeViewId && viewList[0] && viewList[0].id != null) {
            activeViewId = String(viewList[0].id);
        }

        var snapshotsByView = getPayloadSnapshotsByView(source);
        var objectsByView = filterCartObjectsByView(deriveObjectsByViewFromSnapshots(snapshotsByView, getPayloadObjectsByView(source)));
        var rootObjects = filterCartPersistableObjects(getPayloadRootObjects(source));
        if (rootObjects.length) {
            var fallbackViewId = activeViewId || getPayloadFallbackViewId(source);
            if (!Array.isArray(objectsByView[fallbackViewId]) || !objectsByView[fallbackViewId].length) {
                objectsByView[fallbackViewId] = clonePlainObject(rootObjects);
            }
        }

        var document = {
            schemaVersion: 1,
            views: {
                views: viewList,
                activeViewId: activeViewId
            },
            activeViewId: activeViewId
        };
        if (safeObjectKeys(objectsByView).length) {
            document.objects = { byView: clonePlainObject(objectsByView) };
        }
        if (source.viewportByView && typeof source.viewportByView === 'object' && !Array.isArray(source.viewportByView)) {
            document.viewportByView = clonePlainObject(source.viewportByView);
        } else if (source.documentViewportByView && typeof source.documentViewportByView === 'object' && !Array.isArray(source.documentViewportByView)) {
            document.viewportByView = clonePlainObject(source.documentViewportByView);
        }
        if (source.selection && typeof source.selection === 'object' && !Array.isArray(source.selection)) {
            document.selection = clonePlainObject(source.selection);
        }
        var neutralDocument = source.asukaDocument && typeof source.asukaDocument === 'object' && !Array.isArray(source.asukaDocument)
            ? source.asukaDocument
            : null;
        var scenes3d = source.scenes3d && typeof source.scenes3d === 'object' && !Array.isArray(source.scenes3d)
            ? source.scenes3d
            : (source.document3dScenesByView && typeof source.document3dScenesByView === 'object' && !Array.isArray(source.document3dScenesByView)
                ? source.document3dScenesByView
                : (neutralDocument && neutralDocument.scenes3d && typeof neutralDocument.scenes3d === 'object' && !Array.isArray(neutralDocument.scenes3d)
                    ? neutralDocument.scenes3d
                    : null));
        if (scenes3d && safeObjectKeys(scenes3d).length) {
            document.scenes3d = clonePlainObject(scenes3d);
        }
        if (neutralDocument) {
            document.asukaDocument = clonePlainObject(neutralDocument);
        }
        var drawingAreasPayload = normalizeCartDrawingAreasPayload(source, activeViewId);
        if (drawingAreasPayload) {
            document.drawingAreas = drawingAreasPayload;
            document.drawingAreasByView = clonePlainObject(drawingAreasPayload.byView || {});
            document.drawingZones = flattenCartDrawingAreasByView(drawingAreasPayload.byView || {});
        }
        if (Array.isArray(source.elements) && source.elements.length) {
            document.elements = clonePlainObject(source.elements);
        }
        if (Array.isArray(source.fixedSlots) && source.fixedSlots.length) {
            document.fixedSlots = clonePlainObject(source.fixedSlots);
            document.fixedSlotActiveId = source.fixedSlotActiveId || null;
        }
        if (source.meta && typeof source.meta === 'object' && !Array.isArray(source.meta)) {
            document.meta = clonePlainObject(source.meta);
        }
        if (source.__apdSubmitProof && typeof source.__apdSubmitProof === 'object') {
            document.__apdSubmitProof = clonePlainObject(source.__apdSubmitProof);
        }
        return document;
    }

    function getCartDocumentFromState(state) {
        if (!state || typeof state !== 'object') {
            return null;
        }
        if (state.initialDocument && typeof state.initialDocument === 'object') {
            return normalizeCartDocumentPayload(state.initialDocument);
        }
        if (state.document && typeof state.document === 'object') {
            return normalizeCartDocumentPayload(state.document);
        }
        if (state.documentState && typeof state.documentState === 'object') {
            return normalizeCartDocumentPayload(state.documentState);
        }
        if (state.state && typeof state.state === 'object') {
            return getCartDocumentFromState(state.state);
        }
        return normalizeCartDocumentPayload(state);
    }

    function cartDocumentScore(document) {
        var summary = summarizeViewContainer(document || null);
        var sceneProducts = 0;
        var scenes3d = document && document.scenes3d && typeof document.scenes3d === 'object'
            ? document.scenes3d
            : (document && document.document3dScenesByView && typeof document.document3dScenesByView === 'object'
                ? document.document3dScenesByView
                : null);
        safeObjectKeys(scenes3d).forEach(function (viewId) {
            var scene = scenes3d[viewId];
            sceneProducts += scene && Array.isArray(scene.products) ? scene.products.length : 0;
        });
        return Number(sceneProducts || 0) * 1000
            + Number(summary.objectCount || 0) * 100
            + Number(summary.viewsCount || 0) * 10
            + Number(summary.snapshotCount || 0) * 2
            + Number(summary.drawingAreasCount || 0);
    }

    function cartDocumentHasContent(document) {
        return cartDocumentScore(document) > 0;
    }


    function buildCartStateFromDocument(document, previousState, config) {
        var state = previousState && typeof previousState === 'object' ? clonePlainObject(previousState) : {};
        state.format = 'asuka-product-designer-state';
        state.schemaVersion = 1;
        state.exportedAt = (new Date()).toISOString();
        state.scope = state.scope && typeof state.scope === 'object' ? state.scope : {};
        state.scope.document = false;

        var context = config && config.context && typeof config.context === 'object' ? config.context : {};
        state.product = state.product && typeof state.product === 'object' ? state.product : {};
        if (context.productId != null) { state.product.productId = Number(context.productId || 0) || 0; }
        if (context.configId != null) { state.product.configId = Number(context.configId || 0) || 0; }
        if (context.variationId != null) { state.product.variationId = Number(context.variationId || 0) || 0; }
        state.scope.product = true;

        delete state.document;
        delete state.initialDocument;
        delete state.documentState;
        delete state.objectsByView;
        delete state.documentObjectsByView;
        delete state.snapshotsByView;
        delete state.viewSnapshots;
        delete state.canvas;
        delete state.legacy;

        if (config && config.layout && typeof config.layout === 'object') {
            state.layout = clonePlainObject(config.layout);
            state.scope.layout = true;
        }
        return state;
    }

    function pickBestCartDocument() {
        var best = null;
        var bestScore = 0;
        Array.prototype.forEach.call(arguments, function (candidate) {
            var document = getCartDocumentFromState(candidate);
            var score = cartDocumentScore(document);
            if (score > bestScore) {
                bestScore = score;
                best = document;
            }
        });
        return best && bestScore > 0 ? clonePlainObject(best) : null;
    }


    function getCartDocumentActiveViewId(document) {
        document = document && typeof document === 'object' ? document : {};
        if (document.activeViewId != null && String(document.activeViewId)) {
            return String(document.activeViewId);
        }
        if (document.views && typeof document.views === 'object' && document.views.activeViewId != null && String(document.views.activeViewId)) {
            return String(document.views.activeViewId);
        }
        var views = [];
        if (Array.isArray(document.views)) {
            views = document.views;
        } else if (document.views && typeof document.views === 'object' && Array.isArray(document.views.views)) {
            views = document.views.views;
        }
        return views[0] && views[0].id != null ? String(views[0].id) : 'view-1';
    }

    function isCartPersistableObject(object) {
        if (!object || typeof object !== 'object') {
            return false;
        }
        if (object.excludeFromExport === true || object._excludeFromExport === true || object._asukaTemporary === true || object._asukaSnapIndicator === true || object._asukaGuide === true) {
            return false;
        }
        var type = String(object.type || object.objectType || '').toLowerCase();
        var itemGroup = String(object.itemGroup || '').toLowerCase();
        var role = String(object.role || '').toLowerCase();
        var source = String(object._asukaSourceModule || object.sourceModule || '').toLowerCase();
        if (itemGroup === 'tools' || itemGroup === 'guides' || itemGroup === 'guide' || role === 'guide' || role === 'snap' || role === 'helper' || source === 'tools' || source === 'guides') {
            return false;
        }
        // Snap guides are Fabric lines injected temporarily while moving objects.
        // They can still be present on the live canvas at the exact click moment,
        // but they are UI helpers, not customer design content.
        if (type === 'line' && (object.selectable === false || object.evented === false || itemGroup === 'tools')) {
            return false;
        }
        return true;
    }

    function filterCartPersistableObjects(objects) {
        if (!Array.isArray(objects)) {
            return [];
        }
        return objects.filter(isCartPersistableObject);
    }

    function filterCartObjectsByView(objectsByView) {
        var filtered = {};
        if (!objectsByView || typeof objectsByView !== 'object' || Array.isArray(objectsByView)) {
            return filtered;
        }
        Object.keys(objectsByView).forEach(function (viewId) {
            var objects = filterCartPersistableObjects(objectsByView[viewId]);
            filtered[viewId] = objects;
        });
        return filtered;
    }

    function serializeCanvasObjectForCart(object) {
        if (!isCartPersistableObject(object)) {
            return null;
        }
        var extraProps = [
            'id', 'name', 'itemGroup', 'itemType', 'role', 'data', 'excludeFromExport',
            '_asukaImage', '_asukaDesign', '_asukaQrCode', '_asukaElementId', '_asukaElementName', '_asukaElementFamilyId', '_asukaElementIsInstance', '_asukaSourceModule', '_asukaFixedSlotId', '_asukaDrawingAreaId', '_asukaDrawingZoneId'
        ];
        try {
            if (typeof object.toObject === 'function') {
                var serialized = object.toObject(extraProps);
                return isCartPersistableObject(serialized) ? serialized : null;
            }
        } catch (error) {}
        var cloned = clonePlainObject(object);
        return isCartPersistableObject(cloned) ? cloned : null;
    }

    function getLiveCanvasForCart(shell) {
        var instance = shell && shell.__apdInstance ? shell.__apdInstance : null;
        return instance && instance.util && instance.util.state && typeof instance.util.state.exportPart === 'function'
            ? instance
            : null;
    }

    function getLiveCanvasObjectsForCart(shell) {
        var instance = getLiveCanvasForCart(shell);
        if (!instance) {
            return [];
        }
        try {
            var state = instance.util.state.exportPart('document');
            var document = normalizeCartDocumentPayload(state);
            var activeViewId = getCartDocumentActiveViewId(document || {});
            var byView = getPayloadObjectsByView(document || {});
            return filterCartPersistableObjects(Array.isArray(byView[activeViewId]) ? byView[activeViewId] : []);
        } catch (error) {
            return [];
        }
    }


    function getRuntimeActiveViewIdForCart(shell, fallback) {
        var instance = shell && shell.__apdInstance ? shell.__apdInstance : null;
        var value = '';
        try {
            var store = instance && instance.store && typeof instance.store.getState === 'function' ? instance.store : null;
            var state = store ? (store.getState() || {}) : null;
            if (state && state.activeViewId != null) {
                value = String(state.activeViewId || '');
            }
        } catch (error) {}
        if (!value) {
            try {
                var exported = instance && window.APDRuntimeBridge && typeof window.APDRuntimeBridge.exportDesign === 'function'
                    ? window.APDRuntimeBridge.exportDesign(instance)
                    : null;
                value = getCartDocumentActiveViewId(exported || {});
            } catch (error) {}
        }
        return value || String(fallback || '');
    }

    function getRuntimeDocumentObjectsByViewForCart(shell) {
        var instance = shell && shell.__apdInstance ? shell.__apdInstance : null;
        try {
            var exported = instance && instance.util && instance.util.state && typeof instance.util.state.exportPart === 'function'
                ? instance.util.state.exportPart('document')
                : null;
            var document = normalizeCartDocumentPayload(exported);
            var byView = document ? getPayloadObjectsByView(document) : null;
            if (byView && Object.keys(byView).length) {
                return clonePlainObject(byView);
            }
        } catch (error) {}
        return {};
    }


    function buildCartDocumentFromLiveCanvas(shell) {
        if (!shell) {
            return null;
        }
        var config = getShellConfig(shell);
        var base = pickBestCartDocument(
            shell.__apdLastCartDocument,
            safeParseJson((shell.querySelector('[data-apd-design-json]') || {}).value || '{}', {}),
            config.document,
            config.initialDocument,
            {
                views: Array.isArray(config.views) ? config.views : [],
                drawingAreas: config.drawingAreas && typeof config.drawingAreas === 'object' ? config.drawingAreas : null,
                drawingZones: Array.isArray(config.drawingZones) ? config.drawingZones : []
            }
        );
        if (!base || !cartDocumentHasContent(base)) {
            return null;
        }
        var document = normalizeCartDocumentPayload(base) || clonePlainObject(base);
        var activeViewId = getRuntimeActiveViewIdForCart(shell, getCartDocumentActiveViewId(document));
        var runtimeObjectsByView = filterCartObjectsByView(getRuntimeDocumentObjectsByViewForCart(shell));
        var objectsByView = Object.assign({}, runtimeObjectsByView || {});
        if (!Object.keys(objectsByView).length) {
            return document;
        }
        document.activeViewId = String(activeViewId || document.activeViewId || '');
        if (document.views && typeof document.views === 'object' && !Array.isArray(document.views)) {
            document.views.activeViewId = document.activeViewId;
        }
        document.objects = { byView: clonePlainObject(objectsByView) };
        return normalizeCartDocumentPayload(document) || document;
    }

    function getBestCartDocumentFromRegistryPayload(payload) {
        payload = payload && typeof payload === 'object' ? payload : {};
        var config = payload.config && typeof payload.config === 'object' ? payload.config : {};
        var fullState = getRegistryFullState(payload);
        var documentState = getRegistryDocumentState(payload);
        return pickBestCartDocument(
            documentState,
            fullState,
            config.initialDocument,
            config.initialState,
            config.documentState,
            config.document,
            {
                views: Array.isArray(config.views) ? config.views : [],
                drawingZones: Array.isArray(config.drawingZones) ? config.drawingZones : []
            }
        );
    }


    function getBestCartStateFromRegistryPayload(payload, document) {
        payload = payload && typeof payload === 'object' ? payload : {};
        var config = payload.config && typeof payload.config === 'object' ? payload.config : {};
        var state = getRegistryFullState(payload);
        return buildCartStateFromDocument(document, state || null, config);
    }

    function setShellCartPayloadFields(shell, document, state, options) {
        if (!shell || !cartDocumentHasContent(document)) {
            return false;
        }
        options = options || {};
        var designField = shell.querySelector('[data-apd-design-json]');
        var stateField = shell.querySelector('[data-apd-state-json]');
        var proofEnvelope = attachApdSubmitProof(shell, document, options.reason || 'set-fields');
        document = proofEnvelope.document || normalizeCartDocumentPayload(document) || document;
        var designJson = JSON.stringify(document || {});
        var stateJson = JSON.stringify(state && typeof state === 'object' ? state : buildCartStateFromDocument(document, null, getShellConfig(shell)));
        if (designField && (options.force || !cartDocumentHasContent(safeParseJson(designField.value || '{}', {})))) {
            designField.value = designJson;
        }
        if (stateField && (options.force || !cartDocumentHasContent(safeParseJson(stateField.value || '{}', {})))) {
            stateField.value = stateJson;
        }
        shell.__apdLastCartDocument = clonePlainObject(document || {});
        shell.__apdLastCartState = clonePlainObject(state && typeof state === 'object' ? state : buildCartStateFromDocument(document, null, getShellConfig(shell)));
        return true;
    }

    function seedShellCartDocumentFromRegistryPayload(shell, payload, key, reason) {
        if (!shell) {
            return false;
        }
        var document = getBestCartDocumentFromRegistryPayload(payload);
        if (!cartDocumentHasContent(document)) {
            return false;
        }
        var state = getBestCartStateFromRegistryPayload(payload, document);
        var seeded = setShellCartPayloadFields(shell, document, state, { force: false, reason: reason || 'seed' });
        return seeded;
    }



    function seedShellCartDocumentFromConfig(shell, reason) {
        if (!shell) {
            return false;
        }
        var config = getShellConfig(shell);
        if (!config || typeof config !== 'object' || !Object.keys(config).length) {
            return false;
        }
        return seedShellCartDocumentFromRegistryPayload(shell, {
            productId: Number(shell.dataset.productId || 0) || 0,
            configId: Number(shell.dataset.configId || 0) || 0,
            variationId: Number(shell.dataset.variationId || 0) || 0,
            config: config
        }, shell.dataset.apdShellKey || 'parent', reason || 'shell-config');
    }

    function mountAndBindRegistryShell(scope, shell, payload, key) {
        if (!shell) {
            mountAndBind(scope);
            return;
        }


        if (window.APDRuntimeBridge && typeof window.APDRuntimeBridge.mountOne === 'function') {
            window.APDRuntimeBridge.mountOne(shell);
        }

        var fullState = getRegistryFullState(payload);
        var documentState = getRegistryDocumentState(payload);
        var bootAppliedAtCreate = !!shell.__apdBootAppliedAtCreate;
        var importedFull = false;
        var importedDocument = false;

        if (!bootAppliedAtCreate && fullState && window.APDRuntimeBridge && typeof window.APDRuntimeBridge.importFullProductStateToShell === 'function') {
            importedFull = !!window.APDRuntimeBridge.importFullProductStateToShell(shell, fullState, documentState, {
                source: 'woocommerce-variation-registry',
                key: key || '',
                replaceViews: true,
                replaceSnapshots: true,
                importDocumentFallback: true
            });
        }

        if (!bootAppliedAtCreate && !importedFull && documentState && window.APDRuntimeBridge && typeof window.APDRuntimeBridge.importDocumentStateToShell === 'function') {
            importedDocument = !!window.APDRuntimeBridge.importDocumentStateToShell(shell, documentState, {
                source: 'woocommerce-variation-registry:fallback-document',
                key: key || '',
                replaceViews: true,
                replaceSnapshots: true
            });
        }

        logApdVariationDebug('registryShell:fullStateModelImport', {
            key: key || '',
            bootAppliedAtCreate: bootAppliedAtCreate,
            importedFull: importedFull,
            importedDocumentFallback: importedDocument,
            fullStateKeys: fullState && typeof fullState === 'object' ? safeObjectKeys(fullState) : [],
            document: summarizeViewContainer(documentState),
            shell: summarizeShellDebug(shell)
        });
        logApdTemplateCheck('registryShell:after-model-import', {
            key: key || '',
            importedFull: importedFull,
            importedDocumentFallback: importedDocument,
            selectedRegistryPayload: summarizeRegistryPayloadDebug(payload),
            shell: summarizeShellDebug(shell),
            runtimeAfterImport: getRuntimeShellDebugState(shell)
        });

        bindShell(shell);
    }

    function buildShellFromRegistryPayload(switcher, host, payload, key) {
        var blueprint = getShellBlueprint(switcher, host);
        if (!blueprint || !blueprint.cloneNode) {
            return null;
        }
        logApdVariationDebug('buildShellFromRegistryPayload:start', {
            key: key || '',
            payloadTopKeys: safeObjectKeys(payload || {}),
            payloadConfig: summarizeMountPayload(payload && payload.config ? payload.config : {})
        });
        var shell = blueprint.cloneNode(true);
        resetShellPayloadFields(shell, payload, key);
        logApdVariationDebug('buildShellFromRegistryPayload:end', {
            key: key || '',
            shell: summarizeShellDebug(shell)
        });
        return shell;
    }

    function summarizeShellDebug(shell) {
        if (!shell || typeof shell !== 'object') {
            return {};
        }
        var designField = shell.querySelector && shell.querySelector('[data-apd-design-json]');
        var stateField = shell.querySelector && shell.querySelector('[data-apd-state-json]');
        var shellSummary = {
            shellKey: shell.dataset && shell.dataset.apdShellKey ? String(shell.dataset.apdShellKey) : '',
            productId: shell.dataset && shell.dataset.productId ? Number(shell.dataset.productId || 0) : 0,
            configId: shell.dataset && shell.dataset.configId ? Number(shell.dataset.configId || 0) : 0,
            variationId: shell.dataset && shell.dataset.variationId ? Number(shell.dataset.variationId || 0) : 0,
            templateId: shell.dataset && shell.dataset.templateId ? Number(shell.dataset.templateId || 0) : 0,
            templateTitle: shell.dataset && shell.dataset.templateTitle ? String(shell.dataset.templateTitle || '') : '',
            configTitle: shell.dataset && shell.dataset.configTitle ? String(shell.dataset.configTitle || '') : '',
            hiddenVariationId: 0,
            mounted: !!shell.__apdInstance,
            bound: shell.dataset && shell.dataset.apdShellBound === '1'
        };
        var variationField = shell.querySelector && shell.querySelector('[name="apd_variation_id"]');
        if (variationField && variationField.value) {
            shellSummary.hiddenVariationId = Number(variationField.value || 0) || 0;
        }
        if (designField && designField.value) {
            shellSummary.designField = summarizeViewContainer(safeParseJson(designField.value, null));
        }
        if (stateField && stateField.value) {
            var stateValue = safeParseJson(stateField.value, null);
            shellSummary.stateField = summarizeViewContainer(stateValue && typeof stateValue === 'object' ? (stateValue.initialDocument || stateValue.document || stateValue) : null);
        }
        return shellSummary;
    }

    function logApdVariationDebug(tag, data) {
        return;
    }

    function isApdSubmitDebugEnabled() {
        try {
            if (window.location && /(?:\?|&)apd_submit_debug=1(?:&|$)/.test(window.location.search || '')) {
                return true;
            }
        } catch (error) {}
        return false;
    }

    function apdSmallHash(value) {
        var text = value == null ? '' : String(value);
        var hash = 2166136261;
        for (var i = 0; i < text.length; i += 1) {
            hash ^= text.charCodeAt(i);
            hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
        }
        return ('00000000' + (hash >>> 0).toString(16)).slice(-8);
    }

    function apdSubmitDebugSanitize(value, depth) {
        depth = typeof depth === 'number' ? depth : 0;
        if (value == null || typeof value === 'number' || typeof value === 'boolean') {
            return value;
        }
        if (typeof value === 'string') {
            return value.length > 500 ? value.slice(0, 500) + '…' : value;
        }
        if (depth > 4) {
            return '[max-depth]';
        }
        if (Array.isArray(value)) {
            return value.slice(0, 30).map(function (item) { return apdSubmitDebugSanitize(item, depth + 1); });
        }
        if (typeof value === 'object') {
            var out = {};
            safeObjectKeys(value).slice(0, 80).forEach(function (key) {
                out[key] = apdSubmitDebugSanitize(value[key], depth + 1);
            });
            return out;
        }
        return String(value);
    }

    var APD_SUBMIT_DEBUG_STORAGE_KEY = 'apd_submit_debug_entries';

    function apdSubmitDebugReadStored() {
        try {
            var raw = window.sessionStorage ? (window.sessionStorage.getItem(APD_SUBMIT_DEBUG_STORAGE_KEY) || '') : '';
            var parsed = raw ? JSON.parse(raw) : [];
            return Array.isArray(parsed) ? parsed : [];
        } catch (error) {
            return [];
        }
    }

    function apdSubmitDebugWriteStored(entries) {
        try {
            if (window.sessionStorage) {
                window.sessionStorage.setItem(APD_SUBMIT_DEBUG_STORAGE_KEY, JSON.stringify((entries || []).slice(-120)));
            }
        } catch (error) {}
    }

    function apdSubmitDebugInstallHelpers() {
        try {
            window.APDSubmitDebugDump = function () {
                var memory = window.__APD_SUBMIT_DEBUG__ || [];
                var stored = apdSubmitDebugReadStored();
                return stored.concat(memory).slice(-160);
            };
            window.APDSubmitDebugCopy = function () {
                var json = JSON.stringify(window.APDSubmitDebugDump(), null, 2);
                if (navigator && navigator.clipboard && navigator.clipboard.writeText) {
                    navigator.clipboard.writeText(json);
                }
                return json;
            };
            window.APDSubmitDebugClear = function () {
                window.__APD_SUBMIT_DEBUG__ = [];
                apdSubmitDebugWriteStored([]);
                return true;
            };
        } catch (error) {}
    }

    function apdSubmitDebugLog(tag, data) {
        if (!isApdSubmitDebugEnabled()) {
            return;
        }
        var entry = {
            time: (new Date()).toISOString(),
            tag: tag,
            data: apdSubmitDebugSanitize(data || {})
        };
        try {
            window.__APD_SUBMIT_DEBUG__ = window.__APD_SUBMIT_DEBUG__ || [];
            window.__APD_SUBMIT_DEBUG__.push(entry);
            var stored = apdSubmitDebugReadStored();
            stored.push(entry);
            apdSubmitDebugWriteStored(stored);
            apdSubmitDebugInstallHelpers();
        } catch (error) {}
        try {
            if (window.console && typeof window.console.log === 'function') {
                window.console.log('[APD SUBMIT] ' + tag + '\n' + JSON.stringify(entry.data, null, 2));
            }
        } catch (error) {}
    }

    apdSubmitDebugInstallHelpers();

    function summarizeLiveCanvasForSubmit(shell) {
        var canvas = shell ? getLiveCanvasForCart(shell) : null;
        var objects = shell ? getLiveCanvasObjectsForCart(shell) : [];
        return {
            hasCanvas: !!canvas,
            activeViewId: shell ? getRuntimeActiveViewIdForCart(shell, '') : '',
            objectCount: objects.length,
            objects: objects.slice(0, 8).map(function (object) {
                object = object && typeof object === 'object' ? object : {};
                return {
                    type: object.type || object.objectType || '',
                    id: object.id || object._asukaObjectId || '',
                    name: object.name || object._asukaElementName || '',
                    itemGroup: object.itemGroup || '',
                    left: object.left != null ? Number(object.left) : null,
                    top: object.top != null ? Number(object.top) : null,
                    width: object.width != null ? Number(object.width) : null,
                    height: object.height != null ? Number(object.height) : null,
                    srcHash: object.src ? apdSmallHash(object.src) : '',
                    srcLength: object.src ? String(object.src).length : 0
                };
            })
        };
    }

    function apdSubmitObjectSignature(object) {
        object = object && typeof object === 'object' ? object : {};
        var src = object.src != null ? String(object.src || '') : (object.url != null ? String(object.url || '') : '');
        return {
            type: String(object.type || object.objectType || ''),
            id: String(object.id || object._asukaObjectId || object.uuid || ''),
            name: String(object.name || object._asukaElementName || ''),
            itemGroup: String(object.itemGroup || object.group || object._asukaSourceModule || ''),
            left: object.left != null ? Number(Number(object.left).toFixed(4)) : null,
            top: object.top != null ? Number(Number(object.top).toFixed(4)) : null,
            scaleX: object.scaleX != null ? Number(Number(object.scaleX).toFixed(6)) : null,
            scaleY: object.scaleY != null ? Number(Number(object.scaleY).toFixed(6)) : null,
            angle: object.angle != null ? Number(Number(object.angle).toFixed(4)) : null,
            width: object.width != null ? Number(Number(object.width).toFixed(4)) : null,
            height: object.height != null ? Number(Number(object.height).toFixed(4)) : null,
            textHash: object.text != null ? apdSmallHash(String(object.text || '')) : '',
            srcHash: src ? apdSmallHash(src) : '',
            srcLength: src.length
        };
    }

    function apdSubmitObjectsByViewSignature(objectsByView) {
        var result = { totalObjects: 0, counts: {}, signatures: {} };
        if (!objectsByView || typeof objectsByView !== 'object' || Array.isArray(objectsByView)) {
            return result;
        }
        safeObjectKeys(objectsByView).sort().forEach(function (viewId) {
            var objects = Array.isArray(objectsByView[viewId]) ? objectsByView[viewId] : [];
            result.counts[String(viewId)] = objects.length;
            result.totalObjects += objects.length;
            result.signatures[String(viewId)] = objects.map(apdSubmitObjectSignature);
        });
        return result;
    }

    function buildApdSubmitProof(shell, document, reason) {
        document = normalizeCartDocumentPayload(document) || document || {};
        var documentForHash = clonePlainObject(document || {});
        if (documentForHash && typeof documentForHash === 'object') {
            delete documentForHash.__apdSubmitProof;
            if (documentForHash.meta && typeof documentForHash.meta === 'object') {
                delete documentForHash.meta.apdSubmitProof;
            }
        }
        var activeViewId = getRuntimeActiveViewIdForCart(shell, getCartDocumentActiveViewId(document));
        var objectsByView = getPayloadObjectsByView(document);
        var liveCanvas = summarizeLiveCanvasForSubmit(shell);
        var documentSignature = apdSubmitObjectsByViewSignature(objectsByView);
        var proof = {
            id: 'apd-submit-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2, 8),
            createdAt: (new Date()).toISOString(),
            reason: String(reason || ''),
            source: 'browser-submit-runtime',
            shellKey: shell && shell.dataset ? String(shell.dataset.apdShellKey || '') : '',
            productId: shell && shell.dataset ? Number(shell.dataset.productId || 0) || 0 : 0,
            configId: shell && shell.dataset ? Number(shell.dataset.configId || 0) || 0 : 0,
            activeViewId: String(activeViewId || ''),
            liveCanvas: liveCanvas,
            document: {
                hash: apdSmallHash(JSON.stringify(documentForHash || {})),
                views: summarizeViewContainer(document),
                objects: documentSignature
            }
        };
        return proof;
    }

    function attachApdSubmitProof(shell, document, reason) {
        document = normalizeCartDocumentPayload(document) || clonePlainObject(document || {});
        var proof = buildApdSubmitProof(shell, document, reason);
        document.meta = document.meta && typeof document.meta === 'object' && !Array.isArray(document.meta) ? clonePlainObject(document.meta) : {};
        document.meta.apdSubmitProof = proof;
        document.__apdSubmitProof = proof;
        if (shell) {
            shell.__apdLastSubmitProof = proof;
        }
        return { document: document, proof: proof };
    }

    function summarizeDuplicateFormFields(form) {
        var summary = {};
        if (!form || typeof form.querySelectorAll !== 'function') {
            return summary;
        }
        APD_FORM_FIELD_NAMES.forEach(function (name) {
            var nodes = Array.prototype.slice.call(form.querySelectorAll('[name="' + name + '"]'));
            summary[name] = {
                count: nodes.length,
                values: nodes.map(function (node, index) {
                    var value = String(node.value || '');
                    var isJson = name === 'apd_design_json' || name === 'apd_state_json' || name === 'apd_pricing_payload' || name === 'apd_price_breakdown';
                    return {
                        index: index,
                        managed: node.getAttribute('data-apd-form-field') === name,
                        shellField: !!(node.closest && node.closest('[data-apd-shell]')),
                        disabled: !!node.disabled,
                        length: value.length,
                        hash: apdSmallHash(value),
                        summary: isJson ? summarizeJsonText(value) : undefined,
                        value: isJson ? undefined : (value.length > 160 ? value.slice(0, 160) + '…' : value)
                    };
                })
            };
        });
        return summary;
    }

    function setAllNamedFormFields(form, name, value) {
        if (!form || typeof form.querySelectorAll !== 'function') {
            return 0;
        }
        var count = 0;
        Array.prototype.slice.call(form.querySelectorAll('[name="' + name + '"]')).forEach(function (field) {
            if (!field || field.disabled) {
                return;
            }
            field.value = value == null ? '' : String(value);
            count += 1;
        });
        return count;
    }

    function synchronizeDuplicateApdFormFields(form, fields, reason) {
        if (!form || !fields) {
            return;
        }
        var changed = {};
        APD_FORM_FIELD_NAMES.forEach(function (name) {
            if (!fields[name]) {
                return;
            }
            changed[name] = setAllNamedFormFields(form, name, fields[name].value || '');
        });
        apdSubmitDebugLog('duplicates-synchronized:' + String(reason || ''), {
            changed: changed,
            duplicates: summarizeDuplicateFormFields(form)
        });
    }

    function summarizeJsonText(value) {
        var text = value == null ? '' : String(value);
        var summary = {
            length: text.length,
            empty: text.length === 0,
            preview: text.length > 240 ? text.slice(0, 240) + '…' : text
        };
        if (!text) {
            return summary;
        }
        var parsed = safeParseJson(text, null);
        summary.parseOk = !!(parsed && typeof parsed === 'object');
        if (summary.parseOk) {
            summary.topKeys = safeObjectKeys(parsed);
            summary.viewSummary = summarizeViewContainer(parsed.initialDocument || parsed.document || parsed.documentState || parsed);
            summary.payloadDiagnostics = apdDebugSummarizePayloadRestorePaths(parsed.initialDocument || parsed.document || parsed.documentState || parsed);
            if (parsed.initialState && typeof parsed.initialState === 'object') {
                summary.initialState = summarizeViewContainer(parsed.initialState.initialDocument || parsed.initialState.document || parsed.initialState);
                summary.initialStateDiagnostics = apdDebugSummarizePayloadRestorePaths(parsed.initialState.initialDocument || parsed.initialState.document || parsed.initialState);
            }
            if (parsed.state && typeof parsed.state === 'object') {
                summary.state = summarizeViewContainer(parsed.state.initialDocument || parsed.state.document || parsed.state);
                summary.stateDiagnostics = apdDebugSummarizePayloadRestorePaths(parsed.state.initialDocument || parsed.state.document || parsed.state);
            }
        }
        return summary;
    }

    function summarizeCartFormPayload(form) {
        var summary = { hasForm: !!form, fields: {}, productId: 0, variationId: 0 };
        if (!form || typeof form.querySelector !== 'function') {
            return summary;
        }
        summary.productId = resolveProductId(form);
        var variationField = form.querySelector('[name="variation_id"], [name="apd_variation_id"]');
        summary.variationId = variationField ? (parseInt(String(variationField.value || '0'), 10) || 0) : 0;
        APD_FORM_FIELD_NAMES.forEach(function (name) {
            var field = form.querySelector('[name="' + name + '"]');
            if (!field) {
                summary.fields[name] = { present: false };
                return;
            }
            if (name === 'apd_design_json' || name === 'apd_state_json' || name === 'apd_pricing_payload' || name === 'apd_price_breakdown' || name === 'apd_submit_proof') {
                summary.fields[name] = Object.assign({ present: true }, summarizeJsonText(field.value || ''));
                return;
            }
            var value = String(field.value || '');
            summary.fields[name] = { present: true, length: value.length, value: value.length > 160 ? value.slice(0, 160) + '…' : value };
        });
        return summary;
    }

    function summarizeCartSnapshot(snapshot) {
        snapshot = snapshot && typeof snapshot === 'object' ? snapshot : {};
        return {
            topKeys: safeObjectKeys(snapshot),
            design: summarizeViewContainer(snapshot.design),
            state: summarizeViewContainer(snapshot.state && typeof snapshot.state === 'object' ? (snapshot.state.initialDocument || snapshot.state.document || snapshot.state.documentState || snapshot.state) : null),
            previewLength: snapshot.preview ? String(snapshot.preview).length : 0,
            pricingKeys: safeObjectKeys(snapshot.pricing),
            pricing: snapshot.pricing || null,
            submitProof: snapshot.design && typeof snapshot.design === 'object' ? ((snapshot.design.meta && snapshot.design.meta.apdSubmitProof) || snapshot.design.__apdSubmitProof || null) : null,
            designDiagnostics: apdDebugSummarizePayloadRestorePaths(snapshot.design || {}),
            stateDiagnostics: apdDebugSummarizePayloadRestorePaths(snapshot.state && typeof snapshot.state === 'object' ? (snapshot.state.initialDocument || snapshot.state.document || snapshot.state.documentState || snapshot.state) : {})
        };
    }

    function runtimeLabel(key, fallback, replacements) {
        var labels = window.APD_RUNTIME && window.APD_RUNTIME.labels ? window.APD_RUNTIME.labels : {};
        var value = Object.prototype.hasOwnProperty.call(labels, key) ? labels[key] : fallback;
        value = String(value == null ? '' : value);
        if (replacements && typeof replacements === 'object') {
            Object.keys(replacements).forEach(function (token) {
                value = value.replace(new RegExp('\\{' + token + '\}', 'g'), String(replacements[token]));
            });
        }
        return value;
    }

    function setStatus(shell, message) {
        var status = shell.querySelector('[data-apd-status]');
        if (status) {
            status.textContent = message;
        }
    }

    function extractPricingRules(container) {
        if (!container) {
            return [];
        }
        if (Array.isArray(container)) {
            return container.filter(function (item) { return item && typeof item === 'object'; });
        }
        if (typeof container !== 'object') {
            return [];
        }
        if (Array.isArray(container.pricingRules)) {
            return container.pricingRules.filter(function (item) { return item && typeof item === 'object'; });
        }
        if (Array.isArray(container.rules)) {
            return container.rules.filter(function (item) { return item && typeof item === 'object'; });
        }
        return [];
    }

    function debounce(fn, wait) {
        var timer = null;
        return function () {
            var args = arguments;
            var self = this;
            window.clearTimeout(timer);
            timer = window.setTimeout(function () {
                fn.apply(self, args);
            }, wait);
        };
    }

    function toNumber(value, fallback) {
        fallback = typeof fallback === 'number' ? fallback : 0;
        if (typeof value === 'number' && isFinite(value)) {
            return value;
        }
        if (typeof value !== 'string') {
            return fallback;
        }
        var normalized = value.replace(/\s+/g, '').replace(',', '.');
        var parsed = Number(normalized);
        return isFinite(parsed) ? parsed : fallback;
    }

    function escapeHtml(value) {
        return String(value)
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#039;');
    }

    function formatPrice(amount, shell) {
        var instance = shell && shell.__apdInstance ? shell.__apdInstance : null;
        var priceFormat = window.APD_RUNTIME && window.APD_RUNTIME.priceFormat ? window.APD_RUNTIME.priceFormat : {};

        if (instance && instance.util && typeof instance.util.formatPrice === 'function') {
            try {
                return instance.util.formatPrice(amount, priceFormat);
            } catch (error) {}
        }

        var precision = Math.max(0, parseInt(String(priceFormat.precision != null ? priceFormat.precision : 2), 10) || 0);
        var fixed = Number(amount || 0).toFixed(precision);
        var parts = fixed.split('.');
        var thousandSeparator = String(priceFormat.thousandSeparator != null ? priceFormat.thousandSeparator : ',');
        var decimalSeparator = String(priceFormat.decimalSeparator != null ? priceFormat.decimalSeparator : '.');
        var integer = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, thousandSeparator);
        var value = precision > 0 ? integer + decimalSeparator + (parts[1] || '') : integer;
        var template = String(priceFormat.priceFormat || '%1$s%2$s');
        return template
            .replace('%1$s', String(priceFormat.symbol || ''))
            .replace('%2$s', value);
    }

    function formatSignedPrice(amount, shell) {
        var numeric = Number(amount || 0);
        var sign = numeric > 0.00001 ? '+' : (numeric < -0.00001 ? '-' : '');
        return sign + formatPrice(Math.abs(numeric), shell);
    }

    var APD_FORM_FIELD_NAMES = [
        'apd_design_json',
        'apd_state_json',
        'apd_preview_data',
        'apd_preview_url',
        'apd_preview_attachment_id',
        'apd_price_adjustment',
        'apd_price_total',
        'apd_price_breakdown',
        'apd_pricing_payload',
        'apd_payload_version',
        'apd_config_id',
        'apd_product_id',
        'apd_variation_id',
        'apd_variation_attributes',
        'apd_add_to_cart_nonce',
        'apd_user_design_id',
        'apd_cart_line_token',
        'apd_replace_cart_item_key',
        'apd_submit_proof',
        'apd_submit_debug'
    ];

    function resolveProductId(node) {
        if (!node) {
            return 0;
        }

        if (node.dataset && node.dataset.productId) {
            return parseInt(String(node.dataset.productId || '0'), 10) || 0;
        }

        if (typeof node.querySelector === 'function') {
            var shellField = node.querySelector('[name="apd_product_id"]');
            if (shellField && shellField.value) {
                return parseInt(String(shellField.value || '0'), 10) || 0;
            }
            var addToCartField = node.querySelector('[name="add-to-cart"]');
            if (addToCartField && addToCartField.value) {
                return parseInt(String(addToCartField.value || '0'), 10) || 0;
            }
        }

        var shell = node.closest ? node.closest('[data-apd-shell]') : null;
        if (shell && shell.dataset && shell.dataset.productId) {
            return parseInt(String(shell.dataset.productId || '0'), 10) || 0;
        }

        var form = node.closest ? node.closest('form.variations_form, form.cart') : null;
        if (form) {
            if (form.dataset && form.dataset.product_id) {
                return parseInt(String(form.dataset.product_id || '0'), 10) || 0;
            }
            var formAddToCart = form.querySelector('[name="add-to-cart"]');
            if (formAddToCart && formAddToCart.value) {
                return parseInt(String(formAddToCart.value || '0'), 10) || 0;
            }
        }

        return 0;
    }

    function findProductFormById(productId) {
        if (!productId) {
            return null;
        }

        var exact = document.querySelector('form.variations_form[data-product_id="' + productId + '"]');
        if (exact) {
            return exact;
        }

        var forms = document.querySelectorAll('form.variations_form, form.cart');
        for (var i = 0; i < forms.length; i += 1) {
            var form = forms[i];
            if ((parseInt(String(form.dataset && form.dataset.product_id ? form.dataset.product_id : '0'), 10) || 0) === productId) {
                return form;
            }
            var addToCart = form.querySelector('[name="add-to-cart"]');
            if (addToCart && (parseInt(String(addToCart.value || '0'), 10) || 0) === productId) {
                return form;
            }
        }

        return null;
    }

    function getProductRoot(node) {
        var closestRoot = node && node.closest ? node.closest('.single-product div.product, .woocommerce div.product, .wp-block-group.woocommerce.product, .product') : null;
        if (closestRoot) {
            return closestRoot;
        }

        var productId = resolveProductId(node);
        var productForm = findProductFormById(productId);
        var formRoot = productForm && productForm.closest ? productForm.closest('.single-product div.product, .woocommerce div.product, .wp-block-group.woocommerce.product, .product') : null;
        if (formRoot) {
            return formRoot;
        }

        return document.body || document.documentElement;
    }

    function getProductForm(node) {
        var root = getProductRoot(node);
        var form = root && typeof root.querySelector === 'function' ? root.querySelector('form.variations_form, form.cart') : null;
        if (form) {
            return form;
        }
        return findProductFormById(resolveProductId(node));
    }

    function isApdShellInTemplate(shell) {
        if (!shell || typeof shell.closest !== 'function') {
            return false;
        }
        return !!shell.closest('template');
    }

    function isApdShellDormantBlueprint(shell) {
        if (!shell || typeof shell.closest !== 'function') {
            return false;
        }
        // Condensed/full-width product pages keep a hidden source blueprint while
        // the live designer is moved into the WooCommerce gallery. Never submit
        // that hidden blueprint as the customer design: it usually contains the
        // unedited product config and can overwrite the real cart design with an
        // empty/no-view payload.
        return !!shell.closest('[data-apd-condensed-source][hidden]');
    }

    function isApdShellVisibleEnough(shell) {
        if (!shell || !shell.isConnected) {
            return false;
        }
        if (typeof shell.getClientRects === 'function' && shell.getClientRects().length > 0) {
            return true;
        }
        var modal = shell.closest && shell.closest('[data-apd-modal]');
        // A modal designer can be hidden after the customer closes it, but it can
        // still be the authoritative edited shell for the add-to-cart form.
        return !!modal;
    }

    function nowForCartSource() {
        return Date.now ? Date.now() : (new Date()).getTime();
    }

    function markShellAsCartSource(shell, reason) {
        if (!shell) {
            return;
        }
        var now = nowForCartSource();
        shell.__apdLastCartSourceAt = now;
        shell.__apdLastCartSourceReason = String(reason || 'unknown');
        if (shell.dataset) {
            shell.dataset.apdLastCartSourceAt = String(now);
            shell.dataset.apdLastCartSourceReason = shell.__apdLastCartSourceReason;
        }
    }

    function getShellCartSourceAt(shell) {
        if (!shell) {
            return 0;
        }
        var direct = Number(shell.__apdLastCartSourceAt || 0);
        if (direct > 0) {
            return direct;
        }
        return Number(shell.dataset && shell.dataset.apdLastCartSourceAt ? shell.dataset.apdLastCartSourceAt : 0) || 0;
    }

    function readShellPayloadScoreFromField(shell, selector) {
        if (!shell || !shell.querySelector) {
            return 0;
        }
        var field = shell.querySelector(selector);
        if (!field || !field.value) {
            return 0;
        }
        var payload = safeParseJson(field.value, null);
        if (!payload || typeof payload !== 'object') {
            return 0;
        }
        var summary = summarizeViewContainer(payload.initialDocument || payload.document || payload.documentState || payload);
        return (Number(summary.viewsCount || 0) * 20) + (Number(summary.objectCount || 0) * 200) + (Number(summary.snapshotCount || 0) * 5);
    }

    function readShellRuntimeScore(shell) {
        if (!shell || !shell.__apdInstance) {
            return 0;
        }
        var debug = getRuntimeShellDebugState(shell);
        var exportedDocument = debug && debug.exportedDocument ? debug.exportedDocument : {};
        var exportedStateDocument = debug && debug.exportedStateDocument ? debug.exportedStateDocument : {};
        var objectCount = Math.max(Number(exportedDocument.objectCount || 0), Number(exportedStateDocument.objectCount || 0));
        var viewsCount = Math.max(Number(exportedDocument.viewsCount || 0), Number(exportedStateDocument.viewsCount || 0));
        var snapshotCount = Math.max(Number(exportedDocument.snapshotCount || 0), Number(exportedStateDocument.snapshotCount || 0));
        return (viewsCount * 25) + (objectCount * 250) + (snapshotCount * 5);
    }

    function scoreShellForForm(shell, form) {
        if (!shell || !shell.isConnected || isApdShellInTemplate(shell) || isApdShellDormantBlueprint(shell)) {
            return -1000000;
        }

        var score = 0;
        var productId = resolveProductId(form);
        var shellProductId = parseInt(String(shell.dataset && shell.dataset.productId ? shell.dataset.productId : '0'), 10) || 0;
        if (productId > 0 && shellProductId === productId) {
            score += 1000;
        }

        var selectedVariationId = getSelectedVariationId(form);
        var expectedKey = selectedVariationId > 0 ? ('variation:' + selectedVariationId) : 'parent';
        var shellKey = shell.dataset && shell.dataset.apdShellKey ? String(shell.dataset.apdShellKey || '') : '';
        var shellVariationId = parseInt(String(shell.dataset && shell.dataset.variationId ? shell.dataset.variationId : '0'), 10) || 0;
        if (shellKey && shellKey === expectedKey) {
            score += 260;
        }
        if (selectedVariationId > 0 && shellVariationId === selectedVariationId) {
            score += 220;
        }
        if (selectedVariationId <= 0 && (!shellVariationId || shellKey === 'parent')) {
            score += 120;
        }

        if (shell.__apdInstance) {
            score += 180;
        }
        var mount = shell.querySelector && shell.querySelector('[data-apd-mount]');
        if (mount && mount.dataset.apdMounted === '1') {
            score += 100;
        }
        if (shell.closest && shell.closest('[data-apd-active-shell]')) {
            score += 90;
        }
        if (isApdShellVisibleEnough(shell)) {
            score += 70;
        }
        var lastSourceAt = getShellCartSourceAt(shell);
        if (lastSourceAt > 0) {
            var age = Math.max(0, nowForCartSource() - lastSourceAt);
            // The last shell the customer interacted with is the authoritative
            // cart source. This prevents a visible but stale gallery/clone shell
            // from winning over the edited modal shell during submit.
            score += age < 30000 ? 5000 : (age < 300000 ? 2500 : 900);
        }
        var modal = shell.closest && shell.closest('[data-apd-modal]');
        if (modal && modal.hidden) {
            // Hidden modal shells are valid, but only beat visible gallery shells
            // when they actually contain more live design content.
            score -= 30;
        }

        score += readShellRuntimeScore(shell);
        score += readShellPayloadScoreFromField(shell, '[data-apd-design-json]');
        score += readShellPayloadScoreFromField(shell, '[data-apd-state-json]');

        return score;
    }

    function collectCandidateShellsForForm(form) {
        var candidates = [];
        var productId = resolveProductId(form);
        if (productId > 0) {
            document.querySelectorAll('[data-apd-shell]').forEach(function (shell) {
                if (!shell.isConnected || isApdShellInTemplate(shell) || isApdShellDormantBlueprint(shell)) {
                    return;
                }
                if ((parseInt(String(shell.dataset.productId || '0'), 10) || 0) !== productId) {
                    return;
                }
                candidates.push(shell);
            });
        }

        if (!candidates.length) {
            var root = getProductRoot(form);
            if (root && typeof root.querySelectorAll === 'function') {
                root.querySelectorAll('[data-apd-shell]').forEach(function (shell) {
                    if (!shell.isConnected || isApdShellInTemplate(shell) || isApdShellDormantBlueprint(shell)) {
                        return;
                    }
                    candidates.push(shell);
                });
            }
        }

        return candidates;
    }

    function getActiveShellForForm(form) {
        if (!form) {
            return null;
        }

        var candidates = collectCandidateShellsForForm(form);
        if (!candidates.length) {
            return null;
        }

        candidates.sort(function (left, right) {
            return scoreShellForForm(right, form) - scoreShellForForm(left, form);
        });

        var selected = null;
        for (var i = 0; i < candidates.length; i += 1) {
            if (candidates[i].querySelector('[data-apd-design-json]')) {
                selected = candidates[i];
                break;
            }
        }

        if (!selected) {
            selected = candidates[0] || null;
        }


        return selected;
    }

    function ensureFormPayloadFields(form) {
        if (!form) {
            return {};
        }
        var fields = {};
        APD_FORM_FIELD_NAMES.forEach(function (name) {
            var field = form.querySelector('[data-apd-form-field="' + name + '"]');
            if (!field) {
                field = document.createElement('input');
                field.type = 'hidden';
                field.name = name;
                field.setAttribute('data-apd-form-field', name);
                form.appendChild(field);
            }
            fields[name] = field;
        });
        return fields;
    }

    function clearFormPayloadFields(form) {
        if (!form) {
            return;
        }
        var fields = ensureFormPayloadFields(form);
        Object.keys(fields).forEach(function (name) {
            fields[name].value = '';
        });
    }

    function ensureWooAddToCartProductField(form, productId) {
        if (!form || !productId) {
            return;
        }
        var field = form.querySelector('input[data-apd-managed-add-to-cart="1"]');
        if (!field) {
            field = document.createElement('input');
            field.type = 'hidden';
            field.name = 'add-to-cart';
            field.setAttribute('data-apd-managed-add-to-cart', '1');
            form.appendChild(field);
        }
        field.value = String(productId);
    }

    function getShellCartEditInfo(shell, form) {
        var info = { isEdit: false, replaceKey: '', lineToken: '', label: '' };
        if (shell && shell.dataset) {
            info.replaceKey = String(shell.dataset.apdReplaceCartItemKey || '');
            info.lineToken = String(shell.dataset.apdCartLineToken || '');
            info.label = String(shell.dataset.apdCartSubmitLabel || '');
            if (shell.dataset.apdCartEdit === '1') {
                info.isEdit = true;
            }
        }
        if (shell && typeof shell.querySelector === 'function') {
            var shellReplace = shell.querySelector('[data-apd-replace-cart-item-key]');
            var shellToken = shell.querySelector('[data-apd-cart-line-token]');
            if (shellReplace && shellReplace.value) { info.replaceKey = String(shellReplace.value || ''); }
            if (shellToken && shellToken.value) { info.lineToken = String(shellToken.value || ''); }
        }
        if (form && typeof form.querySelector === 'function') {
            var formReplace = form.querySelector('[data-apd-form-field="apd_replace_cart_item_key"], [name="apd_replace_cart_item_key"]');
            var formToken = form.querySelector('[data-apd-form-field="apd_cart_line_token"], [name="apd_cart_line_token"]');
            if (formReplace && formReplace.value) { info.replaceKey = String(formReplace.value || ''); }
            if (formToken && formToken.value) { info.lineToken = String(formToken.value || ''); }
        }
        info.isEdit = !!(info.isEdit || (info.replaceKey && info.lineToken));
        info.label = info.label || runtimeLabel('cartEditSubmitLabel', 'Update cart item');
        return info;
    }

    function getWooSubmitButtons(form) {
        if (!form || typeof form.querySelectorAll !== 'function') {
            return [];
        }
        return Array.prototype.slice.call(form.querySelectorAll([
            'button.single_add_to_cart_button',
            'button[name="add-to-cart"]',
            'input.single_add_to_cart_button[type="submit"]',
            'input[name="add-to-cart"][type="submit"]'
        ].join(','))).filter(function (button) {
            return !button.matches || !button.matches('[data-apd-form-field], [data-apd-managed-add-to-cart]');
        });
    }

    function rememberSubmitButtonOriginalLabel(button) {
        if (!button || !button.dataset || button.dataset.apdOriginalSubmitLabel) {
            return;
        }
        if (String(button.tagName || '').toLowerCase() === 'input') {
            button.dataset.apdOriginalSubmitLabel = String(button.value || '');
        } else {
            button.dataset.apdOriginalSubmitLabel = String(button.textContent || '').trim();
        }
    }

    function setSubmitButtonLabel(button, label) {
        if (!button) {
            return;
        }
        label = String(label || '');
        if (String(button.tagName || '').toLowerCase() === 'input') {
            button.value = label;
            return;
        }
        button.textContent = label;
    }

    function updateCartEditSubmitUi(form, shell) {
        if (!form) {
            return;
        }
        var info = getShellCartEditInfo(shell, form);
        if (form.dataset) {
            form.dataset.apdCartEdit = info.isEdit ? '1' : '0';
        }
        getWooSubmitButtons(form).forEach(function (button) {
            rememberSubmitButtonOriginalLabel(button);
            if (info.isEdit) {
                setSubmitButtonLabel(button, info.label);
                if (button.dataset) {
                    button.dataset.apdCartEditButton = '1';
                }
            } else if (button.dataset && button.dataset.apdCartEditButton === '1') {
                setSubmitButtonLabel(button, button.dataset.apdOriginalSubmitLabel || runtimeLabel('cartAddSubmitLabel', 'Add to cart'));
                delete button.dataset.apdCartEditButton;
            }
        });
    }

    function attachProductContextToCartState(state, shell, form) {
        state = state && typeof state === 'object' ? clonePlainObject(state) : {};
        var productId = parseInt(String(shell && shell.dataset ? shell.dataset.productId || '0' : '0'), 10) || resolveProductId(form);
        var configId = parseInt(String(shell && shell.dataset ? shell.dataset.configId || '0' : '0'), 10) || 0;
        var variationId = getSelectedVariationId(form) || parseInt(String(shell && shell.dataset ? shell.dataset.variationId || '0' : '0'), 10) || 0;
        state.product = state.product && typeof state.product === 'object' ? state.product : {};
        state.product.productId = productId;
        state.product.configId = configId;
        state.product.variationId = variationId;
        state.product.variationAttributes = collectVariationAttributes(form);
        state.scope = state.scope && typeof state.scope === 'object' ? state.scope : {};
        state.scope.product = true;
        return state;
    }

    function syncFormPayloadFromShell(shell, form) {
        if (!form) {
            return;
        }
        if (!shell) {
            clearFormPayloadFields(form);
            return;
        }
        var fields = ensureFormPayloadFields(form);
        updateVariationFields(shell, form);
        var shellDesignField = shell.querySelector('[data-apd-design-json]');
        var shellStateField = shell.querySelector('[data-apd-state-json]');
        if ((!shellDesignField || !cartDocumentHasContent(safeParseJson(shellDesignField.value || '{}', {}))) && shell.__apdLastCartDocument && cartDocumentHasContent(shell.__apdLastCartDocument)) {
            setShellCartPayloadFields(shell, shell.__apdLastCartDocument, shell.__apdLastCartState || {}, { force: true, reason: 'syncFormPayloadFromShell-last-document' });
        }
        APD_FORM_FIELD_NAMES.forEach(function (name) {
            var source = shell.querySelector('[name="' + name + '"]');
            fields[name].value = source ? String(source.value || '') : '';
        });

        var productId = parseInt(String(shell.dataset && shell.dataset.productId ? shell.dataset.productId : '0'), 10) || resolveProductId(form);
        var configId = parseInt(String(shell.dataset && shell.dataset.configId ? shell.dataset.configId : '0'), 10) || parseInt(String(fields.apd_config_id ? fields.apd_config_id.value || '0' : '0'), 10) || 0;
        var variationId = getSelectedVariationId(form) || parseInt(String(shell.dataset && shell.dataset.variationId ? shell.dataset.variationId : '0'), 10) || 0;

        if (fields.apd_product_id) { fields.apd_product_id.value = productId ? String(productId) : fields.apd_product_id.value; }
        if (fields.apd_config_id) { fields.apd_config_id.value = configId ? String(configId) : fields.apd_config_id.value; }
        if (fields.apd_variation_id) { fields.apd_variation_id.value = variationId ? String(variationId) : ''; }
        if (fields.apd_variation_attributes) { fields.apd_variation_attributes.value = JSON.stringify(collectVariationAttributes(form)); }
        ensureWooAddToCartProductField(form, productId);
        updateCartEditSubmitUi(form, shell);

        if (fields.apd_state_json) {
            var designPayload = fields.apd_design_json ? safeParseJson(fields.apd_design_json.value || '{}', {}) : {};
            var statePayload = safeParseJson(fields.apd_state_json.value || '{}', {});
            // The WooCommerce submit contract is now strict: apd_design_json is the
            // only document source of truth. RuntimeBridge can still write a full
            // Asuka state in apd_state_json for a few milliseconds, so every form
            // mirror pass strips any embedded document before the browser/PHP can
            // use it as a competing source.
            statePayload = buildCartStateFromDocument(
                cartDocumentHasContent(designPayload) ? designPayload : (shell.__apdLastCartDocument || {}),
                statePayload && typeof statePayload === 'object' ? statePayload : {},
                getShellConfig(shell)
            );
            statePayload = attachProductContextToCartState(statePayload, shell, form);
            fields.apd_state_json.value = JSON.stringify(statePayload || {});
        }
        if (fields.apd_submit_proof) {
            fields.apd_submit_proof.value = shell.__apdLastSubmitProof ? JSON.stringify(shell.__apdLastSubmitProof) : '';
        }
        if (fields.apd_submit_debug) {
            fields.apd_submit_debug.value = isApdSubmitDebugEnabled() ? '1' : '';
        }
        synchronizeDuplicateApdFormFields(form, fields, 'syncFormPayloadFromShell');
        apdSubmitDebugLog('form-payload-synced', {
            shell: summarizeShellDebug(shell),
            liveCanvas: summarizeLiveCanvasForSubmit(shell),
            form: summarizeCartFormPayload(form),
            duplicates: summarizeDuplicateFormFields(form)
        });
    }


    function ensurePreviewStored(shell, snapshot) {
        return new Promise(function (resolve, reject) {
            if (!shell) {
                resolve({ previewUrl: '', attachmentId: 0 });
                return;
            }

            var previewUrlField = shell.querySelector('[data-apd-preview-url]');
            var previewAttachmentField = shell.querySelector('[data-apd-preview-attachment-id]');
            var previewData = snapshot && snapshot.preview ? String(snapshot.preview) : '';
            var currentPreviewUrl = previewUrlField ? String(previewUrlField.value || '') : '';
            var currentAttachmentId = previewAttachmentField ? (parseInt(String(previewAttachmentField.value || '0'), 10) || 0) : 0;


            if (!previewData) {
                resolve({ previewUrl: currentPreviewUrl, attachmentId: currentAttachmentId });
                return;
            }

            if (currentPreviewUrl && shell.__apdLastStoredPreviewDataUrl === previewData) {
                resolve({ previewUrl: currentPreviewUrl, attachmentId: currentAttachmentId });
                return;
            }

            request('preview/generate', {
                configId: Number(shell.dataset.configId || 0),
                productId: Number(shell.dataset.productId || 0),
                preview: previewData
            }).then(function (json) {
                if (!json || !json.success || !json.previewUrl) {
                    reject(new Error(json && json.message ? json.message : 'Preview storage failed.'));
                    return;
                }

                if (previewUrlField) {
                    previewUrlField.value = String(json.previewUrl || '');
                }
                if (previewAttachmentField) {
                    previewAttachmentField.value = String(parseInt(String(json.attachmentId || '0'), 10) || 0);
                }
                shell.__apdLastStoredPreviewDataUrl = previewData;
                shell.__apdLastStoredPreviewUrl = String(json.previewUrl || '');
                resolve({
                    previewUrl: String(json.previewUrl || ''),
                    attachmentId: parseInt(String(json.attachmentId || '0'), 10) || 0
                });
            }).catch(function (error) {
                reject(error);
            });
        });
    }

    function normalizePricingPayload(pricing, fallbackBase) {
        fallbackBase = typeof fallbackBase === 'number' ? fallbackBase : 0;
        if (!pricing || typeof pricing !== 'object') {
            pricing = {};
        }

        var display = pricing.display_breakdown && typeof pricing.display_breakdown === 'object'
            ? pricing.display_breakdown
            : (pricing.uiBreakdown && typeof pricing.uiBreakdown === 'object' ? pricing.uiBreakdown : {});

        var base = typeof pricing.base_price !== 'undefined' ? Number(pricing.base_price || 0) : null;
        if (base === null && typeof pricing.base !== 'undefined') { base = Number(pricing.base || 0); }
        if (base === null && typeof pricing.basePrice !== 'undefined') { base = Number(pricing.basePrice || 0); }
        if (base === null && typeof display.base_price !== 'undefined') { base = Number(display.base_price || 0); }
        if (base === null && typeof display.base !== 'undefined') { base = Number(display.base || 0); }
        if (base === null) { base = fallbackBase; }

        var total = typeof pricing.final_price !== 'undefined' ? Number(pricing.final_price || 0) : null;
        if (total === null && typeof pricing.total !== 'undefined') { total = Number(pricing.total || 0); }
        if (total === null && typeof display.final_price !== 'undefined') { total = Number(display.final_price || 0); }
        if (total === null && typeof display.total !== 'undefined') { total = Number(display.total || 0); }
        if (total === null) { total = base; }

        var adjustment = typeof pricing.adjustment_total !== 'undefined' ? Number(pricing.adjustment_total || 0) : null;
        if (adjustment === null && typeof pricing.adjustment !== 'undefined') { adjustment = Number(pricing.adjustment || 0); }
        if (adjustment === null && typeof display.adjustment_total !== 'undefined') { adjustment = Number(display.adjustment_total || 0); }
        if (adjustment === null && typeof display.adjustment !== 'undefined') { adjustment = Number(display.adjustment || 0); }
        if (adjustment === null) { adjustment = total - base; }

        var fixedFee = typeof pricing.fixed_fee !== 'undefined' ? Number(pricing.fixed_fee || 0) : Number(pricing.fixedFee || 0);
        var designerBase = typeof pricing.designer_base_price !== 'undefined' ? Number(pricing.designer_base_price || 0) : Number(pricing.designerBasePrice || pricing.designerBase || 0);
        var standard = typeof pricing.standard_price !== 'undefined' ? Number(pricing.standard_price || 0) : Number(pricing.standard || 0);
        var rules = typeof pricing.rules_total !== 'undefined' ? Number(pricing.rules_total || 0) : Number(pricing.rules || 0);
        var appliedRules = Array.isArray(pricing.applied_rules) ? pricing.applied_rules : (Array.isArray(pricing.appliedRules) ? pricing.appliedRules : []);

        return {
            payload_version: 1,
            success: typeof pricing.success === 'undefined' ? true : !!pricing.success,
            base_price: isFinite(base) ? base : fallbackBase,
            adjustment_total: isFinite(adjustment) ? adjustment : 0,
            final_price: isFinite(total) ? total : fallbackBase,
            fixed_fee: isFinite(fixedFee) ? fixedFee : 0,
            designer_base_price: isFinite(designerBase) ? designerBase : 0,
            standard_price: isFinite(standard) ? standard : 0,
            rules_total: isFinite(rules) ? rules : 0,
            display_breakdown: {
                base_price: isFinite(base) ? base : fallbackBase,
                fixed_fee: isFinite(fixedFee) ? fixedFee : 0,
                designer_base_price: isFinite(designerBase) ? designerBase : 0,
                standard_price: isFinite(standard) ? standard : 0,
                rules_total: isFinite(rules) ? rules : 0,
                adjustment_total: isFinite(adjustment) ? adjustment : 0,
                final_price: isFinite(total) ? total : fallbackBase
            },
            breakdown: Array.isArray(pricing.breakdown) ? pricing.breakdown : [],
            applied_rules: appliedRules,
            warnings: Array.isArray(pricing.warnings) ? pricing.warnings : [],
            base: isFinite(base) ? base : fallbackBase,
            basePrice: isFinite(base) ? base : fallbackBase,
            adjustment: isFinite(adjustment) ? adjustment : 0,
            total: isFinite(total) ? total : fallbackBase,
            fixedFee: isFinite(fixedFee) ? fixedFee : 0,
            designerBase: isFinite(designerBase) ? designerBase : 0,
            designerBasePrice: isFinite(designerBase) ? designerBase : 0,
            standard: isFinite(standard) ? standard : 0,
            rules: isFinite(rules) ? rules : 0,
            uiBreakdown: {
                base: isFinite(base) ? base : fallbackBase,
                designerBase: isFinite(designerBase) ? designerBase : 0,
                standard: isFinite(standard) ? standard : 0,
                rules: isFinite(rules) ? rules : 0,
                adjustment: isFinite(adjustment) ? adjustment : 0,
                total: isFinite(total) ? total : fallbackBase
            },
            appliedRules: appliedRules
        };
    }

    function getPriceTargets(root) {
        if (!root || !root.querySelectorAll) {
            return [];
        }

        var selectors = [
            '.summary > p.price',
            '.summary > span.price',
            '.woocommerce-variation-price .price',
            '.single_variation .price',
            '.wp-block-woocommerce-product-price .wc-block-components-product-price',
            '.wp-block-woocommerce-product-price .wc-block-components-product-price__value',
            '.wp-block-woocommerce-product-price'
        ];

        var targets = [];
        selectors.forEach(function (selector) {
            root.querySelectorAll(selector).forEach(function (node) {
                if (targets.indexOf(node) === -1) {
                    targets.push(node);
                }
            });
        });

        return targets;
    }

    function rememberCurrentDisplayedPrice(node, force) {
        var root = getProductRoot(node);
        var targets = getPriceTargets(root);
        targets.forEach(function (target) {
            if (force || !target.dataset.apdOriginalHtml) {
                target.dataset.apdOriginalHtml = target.innerHTML;
            }
        });
    }

    function getOrCreatePricingSummary(shell) {
        var root = getProductRoot(shell);
        if (!root || !root.querySelector) {
            return null;
        }

        var summary = root.querySelector('[data-apd-pricing-summary]');
        if (summary) {
            return summary;
        }

        summary = document.createElement('div');
        summary.className = 'apd-pricing-summary';
        summary.setAttribute('data-apd-pricing-summary', '1');
        summary.hidden = true;

        var targets = getPriceTargets(root);
        var anchor = targets.length ? targets[0] : null;
        if (anchor && anchor.parentNode) {
            if (anchor.nextSibling) {
                anchor.parentNode.insertBefore(summary, anchor.nextSibling);
            } else {
                anchor.parentNode.appendChild(summary);
            }
            return summary;
        }

        var form = getProductForm(shell);
        if (form && form.parentNode) {
            form.parentNode.insertBefore(summary, form);
            return summary;
        }

        root.appendChild(summary);
        return summary;
    }

    function hidePricingSummary(node) {
        var root = getProductRoot(node);
        if (!root || !root.querySelector) {
            return;
        }
        var summary = root.querySelector('[data-apd-pricing-summary]');
        if (!summary) {
            return;
        }
        summary.innerHTML = '';
        summary.hidden = true;
    }

    function humanizePricingHandler(handler) {
        var map = {
            textLength: runtimeLabel('pricingTextLength', 'Text length'),
            linesLength: runtimeLabel('pricingLinesLength', 'Lines length'),
            fontSize: runtimeLabel('pricingFontSize', 'Font size'),
            colorsLength: runtimeLabel('pricingColorsUsed', 'Colors used'),
            coverage: runtimeLabel('pricingCoverage', 'Coverage'),
            layersAmount: runtimeLabel('pricingLayersAmount', 'Layers amount'),
            layerSize: runtimeLabel('pricingLayerSize', 'Layer size'),
            scale: runtimeLabel('pricingScale', 'Scale')
        };
        var key = String(handler || '');
        return map[key] || (key ? key.replace(/([a-z])([A-Z])/g, '$1 $2') : runtimeLabel('pricingRule', 'Rule'));
    }

    function getPricingConditionMetric(rule) {
        var handler = String(rule && rule.handler || '');
        if (handler === 'textLength') { return runtimeLabel('pricingMetricChars', 'chars'); }
        if (handler === 'linesLength') { return runtimeLabel('pricingMetricLines', 'lines'); }
        if (handler === 'fontSize') { return runtimeLabel('pricingMetricPt', 'pt'); }
        if (handler === 'coverage') { return '%'; }
        if (handler === 'colorsLength') { return runtimeLabel('pricingMetricColors', 'colors'); }
        if (handler === 'layersAmount') { return runtimeLabel('pricingMetricLayers', 'layers'); }
        return '';
    }

    function describePricingCondition(rule) {
        var conditions = rule && Array.isArray(rule.conditions) ? rule.conditions : [];
        if (!conditions.length) {
            return runtimeLabel('pricingTriggeredByCurrentDesign', 'Triggered by current design');
        }

        var metric = getPricingConditionMetric(rule);
        return conditions.map(function (condition) {
            if (!condition || typeof condition !== 'object') {
                return '';
            }

            var operator = String(condition.operator || '>=');
            if (condition.width != null) {
                return runtimeLabel('pricingWidth', 'width') + ' ' + operator + ' ' + String(condition.width);
            }
            if (condition.height != null) {
                return runtimeLabel('pricingHeight', 'height') + ' ' + operator + ' ' + String(condition.height);
            }

            var value = condition.value;
            if (value == null && condition.threshold != null) {
                value = condition.threshold;
            }
            if (value == null && condition.amount != null) {
                value = condition.amount;
            }
            if (value == null && condition.size != null) {
                value = condition.size;
            }
            if (value == null) {
                return runtimeLabel('pricingConditionMatched', 'Condition matched');
            }

            return operator + ' ' + String(value) + (metric ? ' ' + metric : '');
        }).filter(Boolean).join(' · ');
    }

    function describePricingTarget(rule) {
        if (!rule || typeof rule !== 'object') {
            return '';
        }

        var segments = [];
        var types = Array.isArray(rule.targetObjectTypes) ? rule.targetObjectTypes : [];
        if (types.length) {
            segments.push(types.join(', '));
        }
        var viewIds = Array.isArray(rule.targetViewIds) ? rule.targetViewIds : [];
        if (viewIds.length) {
            segments.push(viewIds.join(', '));
        }
        var scope = rule.scope === 'first' ? runtimeLabel('pricingFirstMatch', 'first match') : (rule.scope === 'current' ? runtimeLabel('pricingCurrentView', 'current view') : (rule.scope === 'all' ? runtimeLabel('pricingWholeDocument', 'whole document') : ''));
        if (scope) {
            segments.push(scope);
        }
        return segments.join(' • ');
    }

    function buildPricingTable(headers, rows, modifierClass) {
        if (!rows.length) {
            return '';
        }

        var headHtml = '<tr>' + headers.map(function (header) {
            return '<th scope="col">' + escapeHtml(header) + '</th>';
        }).join('') + '</tr>';

        var bodyHtml = rows.map(function (row) {
            return '<tr>' + row.map(function (cell, index) {
                var tag = index === 0 ? 'th scope="row"' : 'td';
                if (cell == null) {
                    cell = '';
                }
                if (typeof cell === 'object' && cell && typeof cell.html === 'string') {
                    return '<' + tag + '>' + cell.html + '</' + tag.split(' ')[0] + '>';
                }
                return '<' + tag + '>' + escapeHtml(cell) + '</' + tag.split(' ')[0] + '>';
            }).join('') + '</tr>';
        }).join('');

        return '<div class="apd-pricing-summary__table-wrap' + (modifierClass ? ' ' + modifierClass : '') + '"><table class="apd-pricing-summary__table"><thead>' + headHtml + '</thead><tbody>' + bodyHtml + '</tbody></table></div>';
    }

    function getPricingRuleConditionPrices(rule) {
        var conditions = rule && Array.isArray(rule.conditions) ? rule.conditions : [];
        var prices = [];
        conditions.forEach(function (condition) {
            if (!condition || typeof condition !== 'object') {
                return;
            }
            var amount = null;
            if (condition.price != null) {
                amount = toNumber(condition.price, NaN);
            } else if (condition.amount != null) {
                amount = toNumber(condition.amount, NaN);
            }
            if (typeof amount === 'number' && isFinite(amount)) {
                prices.push(amount);
            }
        });
        return prices;
    }

    function buildPricingRuleRow(definition, amount, shell, options) {
        options = options || {};
        var propertyText = humanizePricingHandler(definition && definition.handler ? definition.handler : (definition && definition.label ? definition.label : runtimeLabel('pricingRule', 'Rule')));
        var conditionText = definition ? describePricingCondition(definition) : runtimeLabel('pricingMatchedCurrentDesign', 'Matched in current design');
        var targetText = definition ? describePricingTarget(definition) : '';
        if (targetText) {
            conditionText += ' • ' + targetText;
        }
        if (options.note) {
            conditionText += ' • ' + options.note;
        }
        var amountText = formatSignedPrice(amount, shell);
        if (options.inferred) {
            propertyText = {
                html: '<span>' + escapeHtml(propertyText) + '</span><span class="apd-pricing-summary__mini-badge">' + escapeHtml(runtimeLabel('pricingInferred', 'inferred')) + '</span>'
            };
        }
        return [propertyText, conditionText, amountText];
    }

    function buildFallbackPricingRuleRows(ruleDefinitions, rulesTotal, shell) {
        if (!ruleDefinitions.length || Math.abs(rulesTotal) <= 0.00001) {
            return [];
        }

        if (ruleDefinitions.length === 1) {
            return [buildPricingRuleRow(ruleDefinitions[0], rulesTotal, shell, { inferred: true })];
        }

        var matchingDefinitions = [];
        ruleDefinitions.forEach(function (definition) {
            var prices = getPricingRuleConditionPrices(definition);
            if (!prices.length) {
                return;
            }
            for (var i = 0; i < prices.length; i += 1) {
                if (Math.abs(prices[i] - rulesTotal) <= 0.00001) {
                    matchingDefinitions.push(definition);
                    break;
                }
            }
        });

        if (matchingDefinitions.length === 1) {
            return [buildPricingRuleRow(matchingDefinitions[0], rulesTotal, shell, { inferred: true })];
        }

        return [[
            runtimeLabel('pricingRulesTotal', 'Pricing rules total'),
            runtimeLabel('pricingDetailedRulesNotExposed', 'Detailed matched rules are not exposed by the current runtime breakdown.'),
            formatSignedPrice(rulesTotal, shell)
        ]];
    }

    function renderPricingSummary(shell, normalized) {
        var summary = getOrCreatePricingSummary(shell);
        if (!summary) {
            return;
        }

        var breakdown = normalized && normalized.breakdown && typeof normalized.breakdown === 'object' ? normalized.breakdown : {};
        var ui = breakdown.display_breakdown && typeof breakdown.display_breakdown === 'object'
            ? breakdown.display_breakdown
            : (breakdown.uiBreakdown && typeof breakdown.uiBreakdown === 'object' ? breakdown.uiBreakdown : {});
        var base = typeof ui.base_price !== 'undefined' ? Number(ui.base_price || 0) : (typeof ui.base !== 'undefined' ? Number(ui.base || 0) : Number(normalized.base || 0));
        var fixedFee = typeof ui.fixed_fee !== 'undefined' ? Number(ui.fixed_fee || 0) : Number((breakdown.fixed_fee || breakdown.fixedFee || 0));
        var designerBase = typeof ui.designer_base_price !== 'undefined' ? Number(ui.designer_base_price || 0) : (typeof ui.designerBase !== 'undefined' ? Number(ui.designerBase || 0) : Number((breakdown.designer_base_price || breakdown.designerBase || breakdown.designerBasePrice || 0)));
        var standard = typeof ui.standard_price !== 'undefined' ? Number(ui.standard_price || 0) : (typeof ui.standard !== 'undefined' ? Number(ui.standard || 0) : Number(breakdown.standard_price || breakdown.standard || 0));
        var rules = typeof ui.rules_total !== 'undefined' ? Number(ui.rules_total || 0) : (typeof ui.rules !== 'undefined' ? Number(ui.rules || 0) : Number(breakdown.rules_total || breakdown.rules || 0));
        var total = typeof ui.final_price !== 'undefined' ? Number(ui.final_price || 0) : (typeof ui.total !== 'undefined' ? Number(ui.total || 0) : Number(normalized.total || 0));
        var adjustment = typeof ui.adjustment_total !== 'undefined' ? Number(ui.adjustment_total || 0) : (typeof ui.adjustment !== 'undefined' ? Number(ui.adjustment || 0) : Number(normalized.adjustment || 0));
        var appliedRules = Array.isArray(normalized.appliedRules) ? normalized.appliedRules : [];
        var ruleDefinitions = getPricingRuleDefinitions(shell);

        var hasCustomRows = Math.abs(fixedFee) > 0.00001 || Math.abs(designerBase) > 0.00001 || Math.abs(standard) > 0.00001 || Math.abs(rules) > 0.00001 || appliedRules.length > 0 || Math.abs(adjustment) > 0.00001;
        if (!hasCustomRows) {
            hidePricingSummary(shell);
            return;
        }

        var detailRows = [];
        detailRows.push([runtimeLabel('pricingProductPrice', 'Product price'), runtimeLabel('pricingWooBasePrice', 'WooCommerce base price'), formatPrice(base, shell)]);
        if (Math.abs(fixedFee) > 0.00001) {
            detailRows.push([runtimeLabel('pricingSetupFee', 'Setup fee'), runtimeLabel('pricingOneTimeSetupCharge', 'One-time setup charge'), formatSignedPrice(fixedFee, shell)]);
        }
        if (Math.abs(designerBase) > 0.00001) {
            detailRows.push([runtimeLabel('pricingCustomProductBase', 'Custom product base'), runtimeLabel('pricingBaseAmountFromDesignerConfig', 'Base amount from designer configuration'), formatSignedPrice(designerBase, shell)]);
        }
        if (Math.abs(standard) > 0.00001) {
            detailRows.push([runtimeLabel('pricingStandardOptions', 'Standard options'), runtimeLabel('pricingDefaultOptionSurcharges', 'Default option surcharges'), formatSignedPrice(standard, shell)]);
        }
        if (Math.abs(rules) > 0.00001) {
            detailRows.push([runtimeLabel('pricingPricingRules', 'Pricing rules'), runtimeLabel('pricingDynamicRulesMatched', 'Dynamic rules matched by your design'), formatSignedPrice(rules, shell)]);
        }
        detailRows.push([runtimeLabel('pricingFinalPrice', 'Final price'), runtimeLabel('pricingProductCustomizationTotal', 'Product + customization total'), formatPrice(total, shell)]);

        var rulesRows = [];
        if (appliedRules.length) {
            rulesRows = appliedRules.map(function (rule) {
                var label = rule && rule.label ? String(rule.label) : runtimeLabel('pricingRule', 'Rule');
                var amount = rule && typeof rule.amount !== 'undefined' ? Number(rule.amount || 0) : 0;
                var definition = null;
                var ruleId = rule && rule.id ? String(rule.id) : '';
                for (var i = 0; i < ruleDefinitions.length; i++) {
                    var candidate = ruleDefinitions[i];
                    if (!candidate || typeof candidate !== 'object') {
                        continue;
                    }
                    if (ruleId && candidate.id && String(candidate.id) === ruleId) {
                        definition = candidate;
                        break;
                    }
                    if (!definition && rule && rule.handler && candidate.handler && String(candidate.handler) === String(rule.handler) && String(candidate.label || '') === label) {
                        definition = candidate;
                    }
                }

                if (definition) {
                    return buildPricingRuleRow(definition, amount, shell);
                }
                return [humanizePricingHandler(rule && rule.handler ? rule.handler : label), runtimeLabel('pricingMatchedCurrentDesign', 'Matched in current design'), formatSignedPrice(amount, shell)];
            });
        } else if (Math.abs(rules) > 0.00001) {
            rulesRows = buildFallbackPricingRuleRows(ruleDefinitions, rules, shell);
        }

        var rulesCountHtml = appliedRules.length ? '<span class="apd-pricing-summary__badge">' + escapeHtml(runtimePlural('pricingAppliedRuleCount', 'pricingAppliedRuleCountPlural', appliedRules.length, '{count} applied rule', '{count} applied rules')) + '</span>' : '';
        var metricsHtml =
            '<div class="apd-pricing-summary__metrics">' +
                '<div class="apd-pricing-summary__metric"><span class="apd-pricing-summary__metric-label">' + escapeHtml(runtimeLabel('pricingMetricProduct', 'Product')) + '</span><strong class="apd-pricing-summary__metric-value">' + escapeHtml(formatPrice(base, shell)) + '</strong></div>' +
                '<div class="apd-pricing-summary__metric apd-pricing-summary__metric--accent"><span class="apd-pricing-summary__metric-label">' + escapeHtml(runtimeLabel('pricingMetricAdded', 'Added')) + '</span><strong class="apd-pricing-summary__metric-value">' + escapeHtml(formatSignedPrice(adjustment, shell)) + '</strong></div>' +
                '<div class="apd-pricing-summary__metric"><span class="apd-pricing-summary__metric-label">' + escapeHtml(runtimeLabel('pricingMetricFinal', 'Final')) + '</span><strong class="apd-pricing-summary__metric-value">' + escapeHtml(formatPrice(total, shell)) + '</strong></div>' +
            '</div>';
        var detailsHtml = '<div class="apd-pricing-summary__details"><div class="apd-pricing-summary__subhead">' + escapeHtml(runtimeLabel('pricingBreakdown', 'Price breakdown')) + '</div>' + buildPricingTable([runtimeLabel('pricingColumnItem', 'Item'), runtimeLabel('pricingColumnDetails', 'Details'), runtimeLabel('pricingColumnAmount', 'Amount')], detailRows) + '</div>';
        var rulesHtml = rulesRows.length ? '<div class="apd-pricing-summary__details"><div class="apd-pricing-summary__subhead">' + escapeHtml(runtimeLabel('pricingAppliedRules', 'Applied rules')) + '</div>' + buildPricingTable([runtimeLabel('pricingColumnProperty', 'Property'), runtimeLabel('pricingColumnCondition', 'Condition'), runtimeLabel('pricingColumnAddPrice', '+Price')], rulesRows, 'apd-pricing-summary__table-wrap--rules') + '</div>' : '';

        summary.innerHTML =
            '<div class="apd-pricing-summary__top">' +
                '<div class="apd-pricing-summary__eyebrow">' + escapeHtml(runtimeLabel('pricingLivePricing', 'Live pricing')) + '</div>' +
                rulesCountHtml +
            '</div>' +
            '<div class="apd-pricing-summary__header">' + escapeHtml(runtimeLabel('pricingUpdatedFromCustomization', 'Price updated from your customization')) + '</div>' +
            metricsHtml +
            detailsHtml +
            rulesHtml;
        summary.hidden = false;
    }

    function updateDisplayedPrice(shell, pricing) {
        var root = getProductRoot(shell);
        var targets = getPriceTargets(root);
        var normalized = normalizePricingResult(pricing);
        var base = normalized.base;
        var total = normalized.total;
        var delta = total - base;

        if (!targets.length) {
            renderPricingSummary(shell, normalized);
            return;
        }

        targets.forEach(function (target) {
            if (!target.dataset.apdOriginalHtml) {
                target.dataset.apdOriginalHtml = target.innerHTML;
            }

            if (Math.abs(delta) < 0.00001) {
                target.innerHTML = target.dataset.apdOriginalHtml;
                return;
            }

            var formatted = formatPrice(total, shell);
            var html = '<span class="woocommerce-Price-amount amount"><bdi>' + escapeHtml(formatted) + '</bdi></span>';
            target.innerHTML = html;
        });

        renderPricingSummary(shell, normalized);
    }

    function restoreDisplayedPrice(node) {
        var root = getProductRoot(node);
        var targets = getPriceTargets(root);
        targets.forEach(function (target) {
            if (target.dataset && target.dataset.apdOriginalHtml) {
                target.innerHTML = target.dataset.apdOriginalHtml;
            }
        });
        hidePricingSummary(node);
    }

    function normalizePricingResult(pricing, fallbackBase) {
        var payload = normalizePricingPayload(pricing, fallbackBase);
        return {
            base: Number(payload.base_price || 0),
            total: Number(payload.final_price || 0),
            adjustment: Number(payload.adjustment_total || 0),
            breakdown: payload,
            appliedRules: Array.isArray(payload.applied_rules) ? payload.applied_rules : []
        };
    }

    function applyPricingToShell(shell, pricing, form) {
        if (!shell) {

            return normalizePricingResult(pricing);
        }

        var normalized = normalizePricingResult(pricing, getCurrentBasePrice(form || getProductForm(shell), shell));
        var payload = normalized && normalized.breakdown && typeof normalized.breakdown === 'object' ? normalized.breakdown : normalizePricingPayload(null, getCurrentBasePrice(form || getProductForm(shell), shell));
        var adjustmentField = shell.querySelector('[data-apd-price-adjustment]');
        var totalField = shell.querySelector('[data-apd-price-total]');
        var breakdownField = shell.querySelector('[data-apd-price-breakdown]');
        var pricingPayloadField = shell.querySelector('[data-apd-pricing-payload]');
        var payloadVersionField = shell.querySelector('[data-apd-payload-version]');

        if (adjustmentField) {
            adjustmentField.value = String(normalized.adjustment);
        }
        if (totalField) {
            totalField.value = String(normalized.total);
        }
        if (breakdownField) {
            breakdownField.value = JSON.stringify(payload || {});
        }
        if (pricingPayloadField) {
            pricingPayloadField.value = JSON.stringify(payload || {});
        }
        if (payloadVersionField) {
            payloadVersionField.value = String(Number(payload && payload.payload_version ? payload.payload_version : 1));
        }

        updateDisplayedPrice(shell, normalized);
        if (form) {
            syncFormPayloadFromShell(shell, form);
        }

        shell.__apdLastPricing = normalized;
        return normalized;
    }

    function getDesignerRuntimePricing(shell, basePrice, snapshot) {
        if (!shell) {
            return { pricing: null, source: 'missing-shell', total: null, breakdown: null };
        }

        var instance = shell.__apdInstance || null;
        var total = null;
        var breakdown = null;
        var totalSource = '';
        var breakdownSource = '';

        var totalCandidates = [
            function () { return instance && instance.api && typeof instance.api.getPrice === 'function' ? instance.api.getPrice(basePrice) : null; },
            function () { return instance && typeof instance.getPrice === 'function' ? instance.getPrice(basePrice) : null; },
            function () { return instance && instance.util && instance.util.pricing && typeof instance.util.pricing.getPrice === 'function' ? instance.util.pricing.getPrice(basePrice) : null; }
        ];

        var breakdownCandidates = [
            function () { return instance && instance.api && typeof instance.api.getPriceUiBreakdown === 'function' ? instance.api.getPriceUiBreakdown(basePrice) : null; },
            function () { return instance && typeof instance.getPriceUiBreakdown === 'function' ? instance.getPriceUiBreakdown(basePrice) : null; },
            function () { return instance && instance.util && instance.util.pricing && typeof instance.util.pricing.getPriceUiBreakdown === 'function' ? instance.util.pricing.getPriceUiBreakdown(basePrice) : null; }
        ];

        for (var i = 0; i < totalCandidates.length; i += 1) {
            try {
                var totalValue = totalCandidates[i]();
                if (typeof totalValue === 'number' && isFinite(totalValue)) {
                    total = Number(totalValue);
                    totalSource = i === 0 ? 'designer.api.getPrice' : (i === 1 ? 'designer.getPrice' : 'designer.util.pricing.getPrice');
                    break;
                }
            } catch (error) {}
        }

        for (var j = 0; j < breakdownCandidates.length; j += 1) {
            try {
                var breakdownValue = breakdownCandidates[j]();
                if (breakdownValue && typeof breakdownValue === 'object') {
                    breakdown = breakdownValue;
                    breakdownSource = j === 0 ? 'designer.api.getPriceUiBreakdown' : (j === 1 ? 'designer.getPriceUiBreakdown' : 'designer.util.pricing.getPriceUiBreakdown');
                    break;
                }
            } catch (error) {}
        }

        var pricing = null;
        if (breakdown && typeof breakdown === 'object') {
            pricing = Object.assign({}, breakdown);
        } else if (snapshot && snapshot.pricing && typeof snapshot.pricing === 'object') {
            pricing = Object.assign({}, snapshot.pricing);
            breakdownSource = 'runtime-bridge.syncShell';
        }

        if (!pricing) {
            return { pricing: null, source: totalSource || breakdownSource || 'unavailable', total: total, breakdown: breakdown };
        }

        if (typeof pricing.base === 'undefined' && typeof pricing.base_price === 'undefined') {
            pricing.base = Number(basePrice || 0);
            pricing.base_price = Number(basePrice || 0);
        }

        if (typeof pricing.total === 'undefined' && typeof pricing.final_price === 'undefined' && typeof total === 'number' && isFinite(total)) {
            pricing.total = total;
            pricing.final_price = total;
        }

        if (typeof pricing.final_price === 'undefined' && typeof pricing.total !== 'undefined') {
            pricing.final_price = Number(pricing.total || 0);
        }
        if (typeof pricing.total === 'undefined' && typeof pricing.final_price !== 'undefined') {
            pricing.total = Number(pricing.final_price || 0);
        }
        if (typeof pricing.base_price === 'undefined' && typeof pricing.base !== 'undefined') {
            pricing.base_price = Number(pricing.base || 0);
        }
        if (typeof pricing.base === 'undefined' && typeof pricing.base_price !== 'undefined') {
            pricing.base = Number(pricing.base_price || 0);
        }

        if ((typeof pricing.rules_total === 'undefined' && typeof pricing.rules !== 'undefined')) {
            pricing.rules_total = Number(pricing.rules || 0);
        }
        if ((typeof pricing.standard_price === 'undefined' && typeof pricing.standard !== 'undefined')) {
            pricing.standard_price = Number(pricing.standard || 0);
        }

        if (typeof pricing.adjustment_total === 'undefined') {
            pricing.adjustment_total = Number((pricing.final_price || 0) - (pricing.base_price || 0));
        }

        return {
            pricing: pricing,
            source: [totalSource, breakdownSource].filter(Boolean).join(' + ') || 'runtime',
            total: total,
            breakdown: breakdown
        };
    }

    function calculatePricing(shell, snapshot, productForm, options) {
        options = options || {};
        if (!shell) {
            return Promise.resolve(normalizePricingResult(null, 0));
        }

        var basePrice = getCurrentBasePrice(productForm, shell);
        var cacheKey = buildPricingCacheKey(shell, productForm, snapshot, basePrice);
        if (!options.force && shell.__apdLastPricing && shell.__apdLastPricingKey === cacheKey) {
            return Promise.resolve(shell.__apdLastPricing);
        }

        var runtimePricing = getDesignerRuntimePricing(shell, basePrice, snapshot || {});

        if (!runtimePricing.pricing) {
            return Promise.resolve(shell.__apdLastPricing || normalizePricingResult(null, basePrice));
        }

        var normalized = applyPricingToShell(shell, runtimePricing.pricing, productForm);
        shell.__apdLastPricingKey = cacheKey;
        return Promise.resolve(normalized);
    }

    function parsePriceFromText(text) {
        if (!text) {
            return null;
        }
        var cleaned = String(text)
            .replace(/[^0-9,.-]/g, ' ')
            .replace(/\s+/g, ' ')
            .trim();
        if (!cleaned) {
            return null;
        }

        var parts = cleaned.split(' ');
        var candidate = parts[parts.length - 1] || cleaned;
        var normalized = candidate;
        if (normalized.indexOf(',') !== -1 && normalized.indexOf('.') !== -1) {
            normalized = normalized.replace(/\./g, '').replace(',', '.');
        } else {
            normalized = normalized.replace(',', '.');
        }
        var parsed = Number(normalized);
        return isFinite(parsed) ? parsed : null;
    }

    function inferBasePrice(productForm, shell) {
        if (productForm && productForm.dataset.apdCurrentBasePrice) {
            return toNumber(productForm.dataset.apdCurrentBasePrice, 0);
        }

        var targets = getPriceTargets(getProductRoot(shell));
        for (var i = 0; i < targets.length; i += 1) {
            var parsed = parsePriceFromText(targets[i].textContent || '');
            if (parsed != null) {
                if (productForm) {
                    productForm.dataset.apdCurrentBasePrice = String(parsed);
                }
                return parsed;
            }
        }

        return 0;
    }

    function getCurrentBasePrice(productForm, shell) {
        if (productForm && productForm.dataset.apdCurrentBasePrice) {
            return toNumber(productForm.dataset.apdCurrentBasePrice, inferBasePrice(productForm, shell));
        }
        return inferBasePrice(productForm, shell);
    }

    function getSelectedVariationId(form) {
        if (!form) {
            return 0;
        }
        var explicit = form.querySelector('input[name="variation_id"]');
        return explicit ? parseInt(String(explicit.value || '0'), 10) || 0 : 0;
    }

    function collectVariationAttributes(form) {
        var attributes = {};
        if (!form || !form.querySelectorAll) {
            return attributes;
        }

        form.querySelectorAll('[name^="attribute_"]').forEach(function (field) {
            if (!field.name) {
                return;
            }
            var value = '';
            if (field.type === 'radio') {
                if (!field.checked) {
                    return;
                }
                value = field.value || '';
            } else {
                value = field.value || '';
            }
            attributes[field.name] = value;
        });

        return attributes;
    }

    function getFieldValue(shell, selector) {
        var field = shell && shell.querySelector ? shell.querySelector(selector) : null;
        return field ? String(field.value || '') : '';
    }

    function buildPricingCacheKey(shell, productForm, snapshot, basePrice) {
        return JSON.stringify({
            configId: Number(shell && shell.dataset ? shell.dataset.configId || 0 : 0),
            productId: Number(shell && shell.dataset ? shell.dataset.productId || 0 : 0),
            variationId: getSelectedVariationId(productForm),
            variationAttributes: collectVariationAttributes(productForm),
            basePrice: Number(basePrice || 0),
            design: getFieldValue(shell, '[data-apd-design-json]'),
            state: getFieldValue(shell, '[data-apd-state-json]')
        });
    }

    function updateVariationFields(shell, form) {
        if (!shell || !form) {
            return;
        }
        var variationField = shell.querySelector('[data-apd-variation-id]');
        var attributesField = shell.querySelector('[data-apd-variation-attributes]');
        if (variationField) {
            variationField.value = String(getSelectedVariationId(form) || '');
        }
        if (attributesField) {
            attributesField.value = JSON.stringify(collectVariationAttributes(form));
        }
    }

    function getShellConfig(shell) {
        var configNode = shell ? shell.querySelector('.apd-config') : null;
        if (!configNode) {
            return {};
        }
        try {
            var parsed = JSON.parse(configNode.textContent || '{}');
            return parsed && typeof parsed === 'object' ? parsed : {};
        } catch (error) {
            return {};
        }
    }

    function getFrontBehavior(shell) {
        var parsed = getShellConfig(shell);
        return parsed && typeof parsed.frontBehavior === 'object' ? parsed.frontBehavior : {};
    }

    function getPermissionConfig(shell) {
        var parsed = getShellConfig(shell);
        return parsed && typeof parsed.permissions === 'object' ? parsed.permissions : {};
    }

    function getPricingRuleDefinitions(shell) {
        var parsed = getShellConfig(shell);
        var pricing = parsed && parsed.pricing && typeof parsed.pricing === 'object' ? parsed.pricing : {};
        return extractPricingRules(pricing);
    }

    function normalizeObjectType(type) {
        var key = String(type || '').trim().toLowerCase();
        if (!key) {
            return '';
        }
        if (key === 'textbox' || key === 'itext' || key === 'text') {
            return 'text';
        }
        if (key === 'image') {
            return 'image';
        }
        if (key === 'rect' || key === 'circle' || key === 'triangle' || key === 'polygon' || key === 'ellipse' || key === 'path' || key === 'line') {
            return 'shape';
        }
        return key;
    }

    function collectDesignValidationStats(snapshot) {
        var design = snapshot && snapshot.design && typeof snapshot.design === 'object' ? snapshot.design : {};
        var views = design && design.views && Array.isArray(design.views.views) ? design.views.views : [];
        var viewMeta = {};
        views.forEach(function (view) {
            if (!view || typeof view !== 'object') {
                return;
            }
            var id = String(view.id || '');
            if (!id) {
                return;
            }
            viewMeta[id] = {
                id: id,
                name: String(view.name || id)
            };
        });

        var byView = design && design.objects && design.objects.byView && typeof design.objects.byView === 'object' ? design.objects.byView : {};
        if ((!byView || !Object.keys(byView).length) && design && design.snapshots && design.snapshots.snapshotsByView) {
            Object.keys(design.snapshots.snapshotsByView || {}).forEach(function (viewId) {
                var snapshotView = design.snapshots.snapshotsByView[viewId];
                if (snapshotView && Array.isArray(snapshotView.objects)) {
                    byView[viewId] = snapshotView.objects;
                }
            });
        }

        var stats = {
            totalObjects: 0,
            textObjects: 0,
            imageObjects: 0,
            totalTextLength: 0,
            objectTypes: {},
            countsByView: {},
            viewsWithObjects: 0,
            viewMeta: viewMeta,
            previewAvailable: !!(snapshot && (snapshot.preview || snapshot.previewUrl))
        };

        Object.keys(byView || {}).forEach(function (viewId) {
            var objects = Array.isArray(byView[viewId]) ? byView[viewId] : [];
            stats.countsByView[viewId] = objects.length;
            if (objects.length > 0) {
                stats.viewsWithObjects += 1;
            }
            objects.forEach(function (object) {
                if (!object || typeof object !== 'object') {
                    return;
                }
                stats.totalObjects += 1;
                var typeKey = normalizeObjectType(object.itemGroup || object.type || '');
                if (typeKey) {
                    stats.objectTypes[typeKey] = true;
                }
                if (typeKey === 'text') {
                    stats.textObjects += 1;
                    stats.totalTextLength += String(object.text || '').trim().length;
                }
                if (typeKey === 'image') {
                    stats.imageObjects += 1;
                }
            });
        });

        return stats;
    }

    function getBehaviorMessages(behavior) {
        if (!behavior || typeof behavior !== 'object') {
            return {};
        }
        if (behavior.messages && typeof behavior.messages === 'object') {
            return behavior.messages;
        }
        if (behavior.validationMessages && typeof behavior.validationMessages === 'object') {
            return behavior.validationMessages;
        }
        return {};
    }

    function readBehaviorNumber(behavior, camelKey, snakeKey) {
        if (!behavior || typeof behavior !== 'object') {
            return 0;
        }
        var value = behavior[camelKey];
        if (typeof value === 'undefined' && snakeKey) {
            value = behavior[snakeKey];
        }
        return parseInt(String(value != null ? value : 0), 10) || 0;
    }

    function readBehaviorBoolean(behavior, camelKey, snakeKey) {
        if (!behavior || typeof behavior !== 'object') {
            return false;
        }
        var value = behavior[camelKey];
        if (typeof value === 'undefined' && snakeKey) {
            value = behavior[snakeKey];
        }
        return !!value;
    }

    function readBehaviorList(behavior, camelKey, snakeKey) {
        if (!behavior || typeof behavior !== 'object') {
            return [];
        }
        var value = behavior[camelKey];
        if (typeof value === 'undefined' && snakeKey) {
            value = behavior[snakeKey];
        }
        if (!Array.isArray(value)) {
            return [];
        }
        return value.map(function (item) {
            return String(item || '').trim();
        }).filter(Boolean);
    }

    function formatBehaviorList(values) {
        return values.join(', ');
    }

    function getValidationMessage(behavior, key, fallback, replacements) {
        var messages = getBehaviorMessages(behavior);
        var message = '';
        if (messages && typeof messages[key] === 'string' && messages[key].trim()) {
            message = messages[key].trim();
        } else if (typeof behavior[key + 'Message'] === 'string' && behavior[key + 'Message'].trim()) {
            message = behavior[key + 'Message'].trim();
        } else {
            message = fallback;
        }
        replacements = replacements || {};
        Object.keys(replacements).forEach(function (token) {
            message = message.replace(new RegExp('\{' + token + '\}', 'g'), String(replacements[token]));
        });
        return message;
    }

    function getOrCreateValidationNotice(form, shell) {
        var root = form || getProductRoot(shell);
        if (!root || !root.querySelector) {
            return null;
        }
        var notice = root.querySelector('[data-apd-validation-notice]');
        if (notice) {
            return notice;
        }
        notice = document.createElement('div');
        notice.className = 'woocommerce-error apd-validation-notice';
        notice.setAttribute('data-apd-validation-notice', '1');
        notice.hidden = true;
        if (form && form.parentNode) {
            form.parentNode.insertBefore(notice, form);
        } else if (root.firstChild) {
            root.insertBefore(notice, root.firstChild);
        } else {
            root.appendChild(notice);
        }
        return notice;
    }

    function clearValidationMessage(form, shell) {
        var notice = getOrCreateValidationNotice(form, shell);
        if (!notice) {
            return;
        }
        notice.innerHTML = '';
        notice.hidden = true;
    }

    function showValidationMessage(form, shell, message) {
        var notice = getOrCreateValidationNotice(form, shell);
        if (!notice) {
            if (message) {
                window.alert(message);
            }
            return;
        }
        notice.innerHTML = '<p>' + escapeHtml(message) + '</p>';
        notice.hidden = false;
        if (typeof notice.scrollIntoView === 'function') {
            notice.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
        }
    }

    function countDesignObjects(snapshot) {
        var count = 0;
        var byView = snapshot && snapshot.design && snapshot.design.objects && snapshot.design.objects.byView ? snapshot.design.objects.byView : {};
        Object.keys(byView || {}).forEach(function (viewId) {
            if (Array.isArray(byView[viewId])) {
                count += byView[viewId].length;
            }
        });
        return count;
    }

    function validateBeforeSubmit(shell, snapshot, productForm) {
        var behavior = getFrontBehavior(shell);
        var permissions = getPermissionConfig(shell);
        if ((!behavior || typeof behavior !== 'object') && (!permissions || typeof permissions !== 'object')) {
            clearValidationMessage(productForm, shell);
            return true;
        }

        var stats = collectDesignValidationStats(snapshot || {});
        var requiresDesign = readBehaviorBoolean(behavior, 'requireDesign', 'require_design') || readBehaviorBoolean(behavior, 'requireCustomization', 'require_customization');
        var requirePreview = readBehaviorBoolean(behavior, 'requirePreview', 'require_preview');
        var requireText = readBehaviorBoolean(behavior, 'requireText', 'require_text');
        var requireEveryView = readBehaviorBoolean(behavior, 'requireEveryView', 'require_every_view');
        var minObjects = readBehaviorNumber(behavior, 'minObjects', 'min_objects');
        var maxObjects = readBehaviorNumber(behavior, 'maxObjects', 'max_objects');
        var minTextObjects = readBehaviorNumber(behavior, 'minTextObjects', 'min_text_objects');
        var maxTextObjects = readBehaviorNumber(behavior, 'maxTextObjects', 'max_text_objects');
        var minImageObjects = readBehaviorNumber(behavior, 'minImageObjects', 'min_image_objects');
        var maxImageObjects = readBehaviorNumber(behavior, 'maxImageObjects', 'max_image_objects');
        var minTextLength = readBehaviorNumber(behavior, 'minTextLength', 'min_text_length');
        var minObjectsPerView = readBehaviorNumber(behavior, 'minObjectsPerView', 'min_objects_per_view');
        var requiredViewsCount = readBehaviorNumber(behavior, 'requiredViewsCount', 'required_views_count');
        var allowedObjectTypes = readBehaviorList(behavior, 'allowedObjectTypes', 'allowed_object_types').map(normalizeObjectType).filter(Boolean);
        var forbiddenObjectTypes = readBehaviorList(behavior, 'forbiddenObjectTypes', 'forbidden_object_types').map(normalizeObjectType).filter(Boolean);
        var requiredObjectTypes = readBehaviorList(behavior, 'requiredObjectTypes', 'required_object_types').map(normalizeObjectType).filter(Boolean);
        var requiredViews = readBehaviorList(behavior, 'requiredViews', 'required_views');

        var message = '';
        if (requiresDesign && stats.totalObjects <= 0) {
            message = getValidationMessage(behavior, 'requireDesign', runtimeLabel('validationRequireDesign', 'Please complete your customization before adding this product to the cart.'));
        } else if (minObjects > 0 && stats.totalObjects < minObjects) {
            message = getValidationMessage(behavior, 'minObjects', runtimeLabel('validationMinObjects', 'Please add at least {min} customization element(s) before adding this product to the cart.', { min: minObjects }), { min: minObjects });
        } else if (maxObjects > 0 && stats.totalObjects > maxObjects) {
            message = getValidationMessage(behavior, 'maxObjects', runtimeLabel('validationMaxObjects', 'Please remove some customization elements before adding this product to the cart. Maximum allowed: {max}.', { max: maxObjects }), { max: maxObjects });
        } else if (minTextObjects > 0 && stats.textObjects < minTextObjects) {
            message = getValidationMessage(behavior, 'minTextObjects', runtimeLabel('validationMinTextObjects', 'Please add at least {min} text element(s) before adding this product to the cart.', { min: minTextObjects }), { min: minTextObjects });
        } else if (maxTextObjects > 0 && stats.textObjects > maxTextObjects) {
            message = getValidationMessage(behavior, 'maxTextObjects', runtimeLabel('validationMaxTextObjects', 'Please remove some text elements before adding this product to the cart. Maximum allowed: {max}.', { max: maxTextObjects }), { max: maxTextObjects });
        } else if (minImageObjects > 0 && stats.imageObjects < minImageObjects) {
            message = getValidationMessage(behavior, 'minImageObjects', runtimeLabel('validationMinImageObjects', 'Please add at least {min} image element(s) before adding this product to the cart.', { min: minImageObjects }), { min: minImageObjects });
        } else if (maxImageObjects > 0 && stats.imageObjects > maxImageObjects) {
            message = getValidationMessage(behavior, 'maxImageObjects', runtimeLabel('validationMaxImageObjects', 'Please remove some image elements before adding this product to the cart. Maximum allowed: {max}.', { max: maxImageObjects }), { max: maxImageObjects });
        } else if (requireText && stats.totalTextLength <= 0) {
            message = getValidationMessage(behavior, 'requireText', runtimeLabel('validationRequireText', 'Please add personalized text before adding this product to the cart.'));
        } else if (minTextLength > 0 && stats.totalTextLength < minTextLength) {
            message = getValidationMessage(behavior, 'minTextLength', runtimeLabel('validationMinTextLength', 'Please enter at least {min} text character(s) before adding this product to the cart.', { min: minTextLength }), { min: minTextLength });
        } else if (requirePreview && !stats.previewAvailable) {
            message = getValidationMessage(behavior, 'requirePreview', runtimeLabel('validationRequirePreview', 'A preview is required before adding this customized product to the cart.'));
        } else if (requiredViewsCount > 0 && stats.viewsWithObjects < requiredViewsCount) {
            message = getValidationMessage(behavior, 'requiredViewsCount', runtimeLabel('validationRequiredViewsCount', 'Please customize at least {count} view(s) before adding this product to the cart.', { count: requiredViewsCount }), { count: requiredViewsCount });
        } else if ((requireEveryView || minObjectsPerView > 0) && viewsNeedObjects(stats, minObjectsPerView > 0 ? minObjectsPerView : 1)) {
            message = getValidationMessage(behavior, 'requireEveryView', runtimeLabel('validationRequireEveryView', 'Please complete every required view before adding this product to the cart.'));
        } else if (requiredViews.length && !requiredViewsSatisfied(stats, requiredViews, minObjectsPerView > 0 ? minObjectsPerView : 1)) {
            message = getValidationMessage(behavior, 'requiredViews', runtimeLabel('validationRequiredViews', 'Please customize the required views before adding this product to the cart: {views}.', { views: formatBehaviorList(requiredViews) }), { views: formatBehaviorList(requiredViews) });
        } else if (allowedObjectTypes.length && hasDisallowedTypes(stats, allowedObjectTypes)) {
            message = getValidationMessage(behavior, 'allowedObjectTypes', runtimeLabel('validationAllowedObjectTypes', 'This customization contains unsupported element types for this product.'));
        } else if (forbiddenObjectTypes.length && hasForbiddenTypes(stats, forbiddenObjectTypes)) {
            message = getValidationMessage(behavior, 'forbiddenObjectTypes', runtimeLabel('validationForbiddenObjectTypes', 'Please remove the forbidden element types before adding this product to the cart.'));
        } else if (requiredObjectTypes.length && !hasRequiredTypes(stats, requiredObjectTypes)) {
            message = getValidationMessage(behavior, 'requiredObjectTypes', runtimeLabel('validationRequiredObjectTypes', 'This product requires the following element types: {types}.', { types: formatBehaviorList(requiredObjectTypes) }), { types: formatBehaviorList(requiredObjectTypes) });
        } else if (permissions && permissions.canAddText === false && stats.textObjects > 0) {
            message = getValidationMessage(behavior, 'textForbidden', runtimeLabel('validationTextForbidden', 'Text customization is not allowed for this product.'));
        } else if (permissions && permissions.canAddImage === false && stats.imageObjects > 0) {
            message = getValidationMessage(behavior, 'imageForbidden', runtimeLabel('validationImageForbidden', 'Image customization is not allowed for this product.'));
        }

        if (message) {
            showValidationMessage(productForm, shell, message);
            return false;
        }

        clearValidationMessage(productForm, shell);
        return true;
    }

    function viewsNeedObjects(stats, minimumPerView) {
        minimumPerView = minimumPerView || 1;
        var viewIds = Object.keys(stats.viewMeta || {});
        if (!viewIds.length) {
            viewIds = Object.keys(stats.countsByView || {});
        }
        for (var i = 0; i < viewIds.length; i += 1) {
            var viewId = viewIds[i];
            if ((stats.countsByView[viewId] || 0) < minimumPerView) {
                return true;
            }
        }
        return false;
    }

    function requiredViewsSatisfied(stats, requiredViews, minimumPerView) {
        minimumPerView = minimumPerView || 1;
        var lookup = {};
        requiredViews.forEach(function (value) {
            lookup[String(value).trim().toLowerCase()] = true;
        });
        var matched = 0;
        Object.keys(stats.viewMeta || {}).forEach(function (viewId) {
            var meta = stats.viewMeta[viewId] || { id: viewId, name: viewId };
            var idKey = String(meta.id || '').trim().toLowerCase();
            var nameKey = String(meta.name || '').trim().toLowerCase();
            if (!lookup[idKey] && !lookup[nameKey]) {
                return;
            }
            if ((stats.countsByView[viewId] || 0) >= minimumPerView) {
                matched += 1;
            }
        });
        return matched >= requiredViews.length;
    }

    function hasDisallowedTypes(stats, allowedTypes) {
        var allowed = {};
        allowedTypes.forEach(function (type) {
            allowed[type] = true;
        });
        return Object.keys(stats.objectTypes || {}).some(function (type) {
            return !allowed[type];
        });
    }

    function hasForbiddenTypes(stats, forbiddenTypes) {
        var forbidden = {};
        forbiddenTypes.forEach(function (type) {
            forbidden[type] = true;
        });
        return Object.keys(stats.objectTypes || {}).some(function (type) {
            return !!forbidden[type];
        });
    }

    function hasRequiredTypes(stats, requiredTypes) {
        return requiredTypes.every(function (type) {
            return !!stats.objectTypes[type];
        });
    }

    function applyResumeSelectionToForm(form, switcher) {
        if (!form || !switcher || form.dataset.apdResumeApplied === '1') {
            return;
        }

        var variationId = parseInt(String(switcher.dataset.apdResumeVariationId || '0'), 10) || 0;
        var rawAttributes = switcher.dataset.apdResumeAttributes || '';
        var attributes = {};
        if (rawAttributes) {
            try {
                attributes = JSON.parse(rawAttributes) || {};
            } catch (error) {
                attributes = {};
            }
        }

        if (!variationId && !Object.keys(attributes).length) {
            return;
        }

        Object.keys(attributes).forEach(function (name) {
            var field = form.querySelector('[name="' + CSS.escape(name) + '"]');
            if (!field) {
                return;
            }
            field.value = attributes[name];
            field.dispatchEvent(new Event('change', { bubbles: true }));
        });

        var variationField = form.querySelector('input[name="variation_id"]');
        if (variationField && variationId) {
            variationField.value = String(variationId);
        }

        form.dataset.apdResumeApplied = '1';

        if (window.jQuery && typeof window.jQuery === 'function') {
            var $form = window.jQuery(form);
            $form.trigger('check_variations');
            window.setTimeout(function () {
                $form.trigger('check_variations');
                if (variationId) {
                    $form.trigger('found_variation', [{ variation_id: variationId }]);
                }
            }, 60);
        }
    }

    function normalizeCartSnapshotForShell(shell, snapshot) {
        snapshot = snapshot && typeof snapshot === 'object' ? snapshot : {};
        if (!shell) {
            return {
                design: snapshot.design || {},
                state: snapshot.state || {},
                preview: snapshot.preview || '',
                pricing: snapshot.pricing || null
            };
        }
        var designField = shell.querySelector('[data-apd-design-json]');
        var stateField = shell.querySelector('[data-apd-state-json]');
        var fieldDesign = designField ? safeParseJson(designField.value || '{}', {}) : {};
        var fieldState = stateField ? safeParseJson(stateField.value || '{}', {}) : {};
        var stateDocument = snapshot.state && typeof snapshot.state === 'object' ? (snapshot.state.initialDocument || snapshot.state.document || snapshot.state.documentState || snapshot.state) : null;
        var exportedDocument = getCartDocumentFromState(snapshot.design);
        var documentSource = 'exportDocument';
        var bestDocument = cartDocumentHasContent(exportedDocument)
            ? clonePlainObject(exportedDocument)
            : null;

        // The official AsukaDesigner document export is authoritative. Do not
        // rebuild the submitted document from canvas.getObjects()/toObject() when
        // exportDocument() has already produced a restorable payload: the live
        // Fabric canvas may have been normalized/recentered by a restore/import
        // path, and saving it would persist those wrong coordinates.
        if (!cartDocumentHasContent(bestDocument)) {
            documentSource = 'fallback-document';
            bestDocument = pickBestCartDocument(
                stateDocument,
                fieldDesign,
                fieldState,
                shell.__apdLastCartDocument,
                shell.__apdLastCartState,
                getShellConfig(shell),
                buildCartDocumentFromLiveCanvas(shell)
            );
        }
        var previousState = snapshot.state && typeof snapshot.state === 'object' ? clonePlainObject(snapshot.state) : {};
        if (!previousState || !Object.keys(previousState).length) {
            previousState = fieldState && typeof fieldState === 'object' ? clonePlainObject(fieldState) : {};
        }
        if (!previousState || !Object.keys(previousState).length) {
            previousState = shell.__apdLastCartState && typeof shell.__apdLastCartState === 'object' ? clonePlainObject(shell.__apdLastCartState) : {};
        }
        if (bestDocument && cartDocumentHasContent(bestDocument)) {
            var bestState = buildCartStateFromDocument(bestDocument, previousState, getShellConfig(shell));
            setShellCartPayloadFields(shell, bestDocument, bestState, { force: true, reason: documentSource === 'exportDocument' ? 'syncShell-exportDocument' : 'syncShell-fallback-document' });
            snapshot.design = bestDocument;
            snapshot.state = bestState;
        } else {
            snapshot.design = snapshot.design || {};
            snapshot.state = snapshot.state || {};
        }
        snapshot.preview = snapshot.preview || '';
        snapshot.pricing = snapshot.pricing || null;
        return snapshot;
    }

    function syncShell(shell, options) {
        markShellAsCartSource(shell, options && options.reason ? options.reason : 'sync');
        var snapshot = { design: {}, state: {}, preview: '', pricing: null };
        if (window.APDRuntimeBridge) {
            snapshot = window.APDRuntimeBridge.syncShell(shell, options || {}) || snapshot;
        }
        return normalizeCartSnapshotForShell(shell, snapshot);
    }

    function canUseSessionStorage() {
        try {
            if (!window.sessionStorage) {
                return false;
            }
            var probeKey = '__apd_probe__';
            window.sessionStorage.setItem(probeKey, '1');
            window.sessionStorage.removeItem(probeKey);
            return true;
        } catch (error) {
            return false;
        }
    }

    function getPendingDraftStorageKey(shell) {
        if (!shell) {
            return '';
        }
        return [
            'apd-pending-draft',
            shell.dataset.productId || '0',
            shell.dataset.configId || '0',
            shell.dataset.apdShellKey || 'parent'
        ].join(':');
    }


    function clearPendingDraftForShell(shell) {
        if (!shell || !canUseSessionStorage()) {
            return;
        }
        var exactKey = getPendingDraftStorageKey(shell);
        if (exactKey) {
            try { window.sessionStorage.removeItem(exactKey); } catch (error) {}
        }
        var prefix = [
            'apd-pending-draft',
            shell.dataset.productId || '0',
            shell.dataset.configId || '0',
            ''
        ].join(':');
        try {
            var keys = [];
            for (var i = 0; i < window.sessionStorage.length; i += 1) {
                var key = window.sessionStorage.key(i);
                if (key && key.indexOf(prefix) === 0) {
                    keys.push(key);
                }
            }
            keys.forEach(function (key) {
                try { window.sessionStorage.removeItem(key); } catch (error) {}
            });
        } catch (error) {}
    }

    function readPendingDraftStorageItem(key) {
        if (!key || !canUseSessionStorage()) {
            return null;
        }
        var raw = '';
        try {
            raw = window.sessionStorage.getItem(key) || '';
        } catch (error) {
            raw = '';
        }
        if (!raw) {
            return null;
        }
        try {
            return JSON.parse(raw);
        } catch (error) {
            return null;
        }
    }

    function findPendingDraftForShell(shell) {
        var exactKey = getPendingDraftStorageKey(shell);
        var exactPayload = readPendingDraftStorageItem(exactKey);
        if (exactPayload && typeof exactPayload === 'object') {
            return { key: exactKey, payload: exactPayload };
        }

        if (!shell || !canUseSessionStorage()) {
            return { key: exactKey, payload: null };
        }

        var prefix = [
            'apd-pending-draft',
            shell.dataset.productId || '0',
            shell.dataset.configId || '0',
            ''
        ].join(':');
        var newest = null;
        try {
            for (var i = 0; i < window.sessionStorage.length; i += 1) {
                var key = window.sessionStorage.key(i);
                if (!key || key.indexOf(prefix) !== 0) {
                    continue;
                }
                var payload = readPendingDraftStorageItem(key);
                if (!payload || typeof payload !== 'object') {
                    continue;
                }
                if (!newest || Number(payload.savedAt || 0) > Number(newest.payload.savedAt || 0)) {
                    newest = { key: key, payload: payload };
                }
            }
        } catch (error) {}

        return newest || { key: exactKey, payload: null };
    }

    function teardownShell(shell, options) {
        if (!shell) {
            return;
        }

        options = options || {};

        if (shell.__apdPreviewObserver && typeof shell.__apdPreviewObserver.disconnect === 'function') {
            try {
                shell.__apdPreviewObserver.disconnect();
            } catch (error) {}
        }
        shell.__apdPreviewObserver = null;

        if (shell.__apdPreviewListenerPoll) {
            try {
                window.clearInterval(shell.__apdPreviewListenerPoll);
            } catch (error) {}
        }
        shell.__apdPreviewListenerPoll = null;

        if (shell.__apdPricingListenerPoll) {
            try {
                window.clearInterval(shell.__apdPricingListenerPoll);
            } catch (error) {}
        }
        shell.__apdPricingListenerPoll = null;

        if (shell.__apdRuntimeHookRegistry && typeof shell.__apdRuntimeHookRegistry === 'object') {
            Object.keys(shell.__apdRuntimeHookRegistry).forEach(function (registryKey) {
                var unsubscribe = shell.__apdRuntimeHookRegistry[registryKey];
                if (typeof unsubscribe === 'function') {
                    try {
                        unsubscribe();
                    } catch (error) {}
                }
            });
        }
        shell.__apdRuntimeHookRegistry = {};
        shell.__apdRuntimeHookSignatures = {};
        shell.__apdRuntimeHookCounters = {};

        if (shell.__apdPermissionKeydownHandler) {
            try {
                document.removeEventListener('keydown', shell.__apdPermissionKeydownHandler, true);
            } catch (error) {}
        }
        shell.__apdPermissionKeydownHandler = null;
        shell.__apdPermissionGuardsInstalled = false;

        if (shell.__apdInstance && typeof shell.__apdInstance.destroy === 'function') {
            try {
                shell.__apdInstance.destroy();
            } catch (error) {}
        }
        shell.__apdInstance = null;
        shell.__apdMountConfig = null;
        shell.__apdRawMountConfig = null;
        shell.__apdBootAppliedAtCreate = false;

        var mount = shell.querySelector('[data-apd-mount]');
        if (mount) {
            mount.dataset.apdMounted = '0';
            if (!options.preserveMarkup) {
                mount.innerHTML = '';
            }
        }

        if (!options.preservePreview) {
            restoreProductImagePreview(shell);
        }
    }

    function replaceRenderedShell(host, htmlFragment, options) {
        if (!host) {
            return null;
        }

        options = options || {};

        var existingShell = host.querySelector('[data-apd-shell]:not([hidden])');
        logApdVariationDebug('replaceRenderedShell:before', {
            hasHtmlFragment: !!htmlFragment,
            existingShell: summarizeShellDebug(existingShell)
        });
        if (existingShell) {
            teardownShell(existingShell, options);
        }

        host.innerHTML = '';

        if (!htmlFragment) {
            logApdVariationDebug('replaceRenderedShell:cleared', {});
            return null;
        }

        host.appendChild(htmlFragment);
        var nextShell = host.querySelector('[data-apd-shell]:not([hidden])');
        logApdVariationDebug('replaceRenderedShell:after', {
            nextShell: summarizeShellDebug(nextShell)
        });
        return nextShell;
    }

    function apdCartPayloadHasRestorableContent(value) {
        if (!value || typeof value !== 'object') {
            return false;
        }
        var summary = summarizeViewContainer(value && value.initialDocument ? value.initialDocument : (value && value.document ? value.document : (value && value.documentState ? value.documentState : value)));
        if ((summary.viewsCount || 0) > 0 || (summary.objectCount || 0) > 0 || (summary.snapshotCount || 0) > 0) {
            return true;
        }
        if (value.initialDocument && apdCartPayloadHasRestorableContent(value.initialDocument)) {
            return true;
        }
        if (value.document && apdCartPayloadHasRestorableContent(value.document)) {
            return true;
        }
        if (value.documentState && apdCartPayloadHasRestorableContent(value.documentState)) {
            return true;
        }
        if (value.state && apdCartPayloadHasRestorableContent(value.state)) {
            return true;
        }
        if (value.legacy && apdCartPayloadHasRestorableContent(value.legacy)) {
            return true;
        }
        return false;
    }

    function apdCartSnapshotHasRestorableContent(snapshot) {
        snapshot = snapshot && typeof snapshot === 'object' ? snapshot : {};
        return apdCartPayloadHasRestorableContent(snapshot.design || {}) || apdCartPayloadHasRestorableContent(snapshot.state || {});
    }

    function persistPendingDraft(shell, productForm, snapshot) {
        if (!shell || !snapshot || !canUseSessionStorage()) {
            return;
        }
        var key = getPendingDraftStorageKey(shell);
        if (!key) {
            return;
        }
        var payload = {
            productId: Number(shell.dataset.productId || 0),
            configId: Number(shell.dataset.configId || 0),
            variationId: getSelectedVariationId(productForm),
            variationAttributes: collectVariationAttributes(productForm),
            design: snapshot.design || {},
            state: snapshot.state || {},
            preview: snapshot.preview || '',
            pricing: snapshot.pricing || null,
            savedAt: Date.now()
        };
        if (!apdCartSnapshotHasRestorableContent(payload)) {
            try { window.sessionStorage.removeItem(key); } catch (error) {}
            return;
        }
        try {
            window.sessionStorage.setItem(key, JSON.stringify(payload));
        } catch (error) {
        }
    }

    function restorePendingDraft(shell, productForm) {
        if (!shell || !shell.__apdInstance || !canUseSessionStorage()) {
            logApdVariationDebug('restorePendingDraft:skip', {
                reason: !shell ? 'no-shell' : (!shell.__apdInstance ? 'no-instance' : 'no-session-storage'),
                shell: summarizeShellDebug(shell)
            });
            return false;
        }
        if (window.location.search && window.location.search.indexOf('apd_resume_design=') !== -1) {
            logApdVariationDebug('restorePendingDraft:skip', { reason: 'resume-design-query', shell: summarizeShellDebug(shell) });
            return false;
        }
        if (window.location.search && window.location.search.indexOf('apd_replace_cart_item_key=') !== -1) {
            logApdVariationDebug('restorePendingDraft:skip', { reason: 'cart-edit-query', shell: summarizeShellDebug(shell) });
            return false;
        }
        var designIdField = shell.querySelector('[data-apd-user-design-id]');
        if (designIdField && designIdField.value) {
            logApdVariationDebug('restorePendingDraft:skip', { reason: 'saved-design-id-present', shell: summarizeShellDebug(shell), designId: designIdField.value });
            return false;
        }
        var foundDraft = findPendingDraftForShell(shell);
        var key = foundDraft.key || getPendingDraftStorageKey(shell);
        if (!key) {
            logApdVariationDebug('restorePendingDraft:skip', { reason: 'no-storage-key', shell: summarizeShellDebug(shell) });
            return false;
        }
        var payload = foundDraft.payload || null;
        if (!payload) {
            logApdVariationDebug('restorePendingDraft:skip', { reason: 'no-stored-payload', key: key, shell: summarizeShellDebug(shell) });
            return false;
        }

        if (!payload || typeof payload !== 'object') {
            logApdVariationDebug('restorePendingDraft:invalid', { reason: 'invalid-json', key: key, shell: summarizeShellDebug(shell) });
            try { window.sessionStorage.removeItem(key); } catch (error) {}
            return false;
        }
        if (payload.savedAt && Date.now() - Number(payload.savedAt || 0) > 6 * 60 * 60 * 1000) {
            logApdVariationDebug('restorePendingDraft:expired', { key: key, shell: summarizeShellDebug(shell), payload: { variationId: payload.variationId || 0, configId: payload.configId || 0 } });
            try { window.sessionStorage.removeItem(key); } catch (error) {}
            return false;
        }
        if (!apdCartPayloadHasRestorableContent(payload.design || {}) && !apdCartPayloadHasRestorableContent(payload.state || {})) {
            logApdVariationDebug('restorePendingDraft:empty', { key: key, shell: summarizeShellDebug(shell) });
            try { window.sessionStorage.removeItem(key); } catch (error) {}
            return false;
        }

        var imported = false;
        var importMethod = '';
        var instance = shell.__apdInstance;
        logApdVariationDebug('restorePendingDraft:payload', {
            key: key,
            shell: summarizeShellDebug(shell),
            payload: {
                productId: Number(payload.productId || 0),
                configId: Number(payload.configId || 0),
                variationId: Number(payload.variationId || 0),
                variationAttributes: payload.variationAttributes || {},
                design: summarizeViewContainer(payload.design),
                state: summarizeViewContainer(payload.state && typeof payload.state === 'object' ? (payload.state.initialDocument || payload.state.document || payload.state) : null)
            }
        });
        try {
            if (instance && instance.util && instance.util.state) {
                if (payload.state && payload.state.format === 'asuka-state' && Number(payload.state.schemaVersion) === 2 && typeof instance.util.state.importFull === 'function') {
                    instance.util.state.importFull(payload.state, { replaceViews: true, replaceSnapshots: true });
                    importMethod = 'util.state.importFull';
                    imported = true;
                } else if (payload.design && typeof instance.util.state.importPart === 'function') {
                    var canonicalDocument = buildCanonicalDocumentState(payload.design);
                    if (canonicalDocument) {
                        instance.util.state.importPart('document', canonicalDocument, { replaceViews: true, replaceSnapshots: true });
                        importMethod = 'util.state.importPart(document)';
                        imported = true;
                    }
                }
            }
        } catch (error) {
            imported = false;
        }

        if (!imported) {
            logApdVariationDebug('restorePendingDraft:not-imported', {
                key: key,
                shell: summarizeShellDebug(shell)
            });
            return false;
        }

        logApdVariationDebug('restorePendingDraft:imported', {
            key: key,
            method: importMethod,
            shell: summarizeShellDebug(shell)
        });
        try { window.sessionStorage.removeItem(key); } catch (error) {}
        updateVariationFields(shell, productForm);
        syncFormPayloadFromShell(shell, productForm);
        window.setTimeout(function () {
            var basePrice = getCurrentBasePrice(productForm, shell);
            var snapshot = syncShell(shell, { basePrice: basePrice });
            logApdVariationDebug('restorePendingDraft:post-sync', {
                shell: summarizeShellDebug(shell),
                snapshot: {
                    design: summarizeViewContainer(snapshot && snapshot.design),
                    state: summarizeViewContainer(snapshot && snapshot.state && typeof snapshot.state === 'object' ? (snapshot.state.initialDocument || snapshot.state.document || snapshot.state) : null)
                }
            });
            if (snapshot && snapshot.preview && isModalShell(shell)) {
                updateProductImagePreview(shell, snapshot.preview);
            }
            if (snapshot && snapshot.pricing) {
                updateDisplayedPrice(shell, snapshot.pricing);
            }
        }, 30);
        return true;
    }

    function getDisplayModeForShell(shell) {
        var node = shell;
        while (node) {
            if (node.dataset && node.dataset.apdDisplayMode) {
                return String(node.dataset.apdDisplayMode || '');
            }
            node = node.parentElement;
        }
        return '';
    }

    function isModalShell(shell) {
        return getDisplayModeForShell(shell) === 'modal' || !!shell.closest('[data-apd-modal]');
    }

    function updateImageNodePreview(img, previewData) {
        if (!img || !previewData) {
            return;
        }
        if (!img.dataset.apdOriginalSrc) {
            img.dataset.apdOriginalSrc = img.getAttribute('src') || '';
            img.dataset.apdOriginalSrcset = img.getAttribute('srcset') || '';
            img.dataset.apdOriginalSizes = img.getAttribute('sizes') || '';
        }
        img.setAttribute('src', previewData);
        img.setAttribute('srcset', previewData + ' 1x');
        img.setAttribute('sizes', '100vw');
        img.removeAttribute('loading');
        img.removeAttribute('decoding');
        if (img.closest('.woocommerce-product-gallery__image, .woocommerce-product-gallery__wrapper, .wp-block-woocommerce-product-image-gallery')) {
            img.style.width = '100%';
            img.style.height = 'auto';
            img.style.maxWidth = '100%';
        }
    }

    function restoreImageNodePreview(img) {
        if (!img || typeof img.dataset.apdOriginalSrc === 'undefined') {
            return;
        }
        if (img.dataset.apdOriginalSrc) {
            img.setAttribute('src', img.dataset.apdOriginalSrc);
        } else {
            img.removeAttribute('src');
        }
        if (img.dataset.apdOriginalSrcset) {
            img.setAttribute('srcset', img.dataset.apdOriginalSrcset);
        } else {
            img.removeAttribute('srcset');
        }
        if (img.dataset.apdOriginalSizes) {
            img.setAttribute('sizes', img.dataset.apdOriginalSizes);
        } else {
            img.removeAttribute('sizes');
        }
        img.style.width = '';
        img.style.height = '';
        img.style.maxWidth = '';
    }

    function restoreProductImagePreview(shell) {
        var root = getProductRoot(shell);
        var selectors = [
            '.woocommerce-product-gallery img',
            '.wp-block-woocommerce-product-image-gallery img',
            '.woocommerce-product-gallery__wrapper img',
            '.woocommerce-product-gallery__image img',
            'img.wp-post-image'
        ];
        var seen = [];
        selectors.forEach(function (selector) {
            root.querySelectorAll(selector).forEach(function (img) {
                if (img.closest('[data-apd-modal]') || img.closest('[data-apd-shell]')) {
                    return;
                }
                if (seen.indexOf(img) !== -1) {
                    return;
                }
                seen.push(img);
            });
        });
        seen.forEach(restoreImageNodePreview);
        if (root && root.dataset) {
            delete root.dataset.apdLatestPreview;
        }
    }

    function updateProductImagePreview(shell, previewData) {
        if (!previewData) {
            return;
        }

        var root = getProductRoot(shell);
        if ((!root || !root.dataset) && document.body && document.body.dataset) {
            root = document.body;
        }
        if (root && root.dataset && root.dataset.apdLatestPreview === previewData) {
            return;
        }
        if (root && root.dataset) {
            root.dataset.apdLatestPreview = previewData;
        }
        var selectors = [
            '.woocommerce-product-gallery img',
            '.wp-block-woocommerce-product-image-gallery img',
            '.woocommerce-product-gallery__wrapper img',
            '.woocommerce-product-gallery__image img',
            'img.wp-post-image'
        ];
        var seen = [];
        selectors.forEach(function (selector) {
            root.querySelectorAll(selector).forEach(function (img) {
                if (img.closest('[data-apd-modal]') || img.closest('[data-apd-shell]')) {
                    return;
                }
                if (seen.indexOf(img) !== -1) {
                    return;
                }
                seen.push(img);
            });
        });

        if (!seen.length) {
            return;
        }

        seen.forEach(function (img, index) {
            if (index < 2 || img.closest('.flex-control-thumbs, .wc-block-product-gallery-thumbnails, .woocommerce-product-gallery__wrapper, .woocommerce-product-gallery__image')) {
                updateImageNodePreview(img, previewData);
            }
        });
    }

    function getDesignerDocumentSignature(shell) {
        var instance = shell && shell.__apdInstance ? shell.__apdInstance : null;
        if (!instance) {
            return '';
        }

        var exporters = [
            function () {
                return instance.util && instance.util.state && typeof instance.util.state.exportPart === 'function'
                    ? instance.util.state.exportPart('document')
                    : null;
            }
        ];

        for (var index = 0; index < exporters.length; index += 1) {
            try {
                var exported = exporters[index]();
                if (exported) {
                    return JSON.stringify(exported);
                }
            } catch (error) {}
        }

        return '';
    }

    function attachAsukaRuntimeChangeHooks(shell, options) {
        if (!shell) {
            return false;
        }

        options = options || {};

        var instance = shell.__apdInstance || null;
        var registryKey = String(options.registryKey || 'default');
        var callback = typeof options.onChange === 'function' ? options.onChange : function () {};
        var useDocumentSignature = !!options.useDocumentSignature;

        shell.__apdRuntimeHookRegistry = shell.__apdRuntimeHookRegistry || {};
        shell.__apdRuntimeHookSignatures = shell.__apdRuntimeHookSignatures || {};
        shell.__apdRuntimeHookCounters = shell.__apdRuntimeHookCounters || {};
        if (shell.__apdRuntimeHookRegistry[registryKey]) {
            return true;
        }

        if (!instance || !instance.util || typeof instance.util.subscribe !== 'function') {
            return false;
        }

        try {
            shell.__apdRuntimeHookSignatures[registryKey] = getDesignerDocumentSignature(shell);
        } catch (error) {
            shell.__apdRuntimeHookSignatures[registryKey] = '';
        }

        shell.__apdRuntimeHookCounters[registryKey] = 0;

        var unsubscribe = null;

        try {
            unsubscribe = instance.util.subscribe(function (state, previousState) {
                shell.__apdRuntimeHookCounters[registryKey] = (shell.__apdRuntimeHookCounters[registryKey] || 0) + 1;
                var now = Date.now ? Date.now() : (new Date()).getTime();
                if (shell.__apdInternalSyncInProgress || (shell.__apdSuppressRuntimeHookUntil && now < shell.__apdSuppressRuntimeHookUntil)) {
                    return;
                }
                var nextSignature = getDesignerDocumentSignature(shell);
                var previousSignature = shell.__apdRuntimeHookSignatures[registryKey] || '';

                if (useDocumentSignature) {
                    if (!nextSignature || nextSignature === previousSignature) {
                        return;
                    }
                    shell.__apdRuntimeHookSignatures[registryKey] = nextSignature;
                } else if (nextSignature) {
                    shell.__apdRuntimeHookSignatures[registryKey] = nextSignature;
                }

                markShellAsCartSource(shell, 'runtime:' + registryKey);
                callback('util.subscribe', {
                    state: state || null,
                    previousState: previousState || null,
                    signature: nextSignature,
                    previousSignature: previousSignature,
                    counter: shell.__apdRuntimeHookCounters[registryKey] || 0,
                    filteredBySignature: useDocumentSignature
                });
            });
        } catch (error) {
            return false;
        }

        shell.__apdRuntimeHookRegistry[registryKey] = function () {
            if (typeof unsubscribe === 'function') {
                try {
                    unsubscribe();
                } catch (error) {}
            }
        };

        return true;
    }

    function attachPreviewSync(shell, productForm) {
        if (!shell || shell.dataset.apdPreviewBound === '1' || !isModalShell(shell)) {
            return;
        }
        shell.dataset.apdPreviewBound = '1';

        var root = getProductRoot(shell);
        if (!shell.__apdPreviewReadyBound) {
            shell.__apdPreviewReadyBound = true;
            shell.addEventListener('apd:preview-ready', function (event) {
                var preview = event && event.detail && event.detail.preview ? String(event.detail.preview) : '';
                if (!preview) {
                    return;
                }
                updateProductImagePreview(shell, preview);
                syncFormPayloadFromShell(shell, productForm);
            });
        }
        var refreshPreview = debounce(function () {
            var basePrice = getCurrentBasePrice(productForm, shell);
            var snapshot = syncShell(shell, { basePrice: basePrice });
            syncFormPayloadFromShell(shell, productForm);
            if (snapshot && snapshot.preview) {
                updateProductImagePreview(shell, snapshot.preview);
            }
        }, 140);

        function queuePreviewRefresh(source) {
            shell.__apdPreviewTriggerSource = source || 'dom';
            refreshPreview();
            window.setTimeout(refreshPreview, 180);
        }

        shell.__apdRefreshPreview = queuePreviewRefresh;

        if (!attachAsukaRuntimeChangeHooks(shell, {
            registryKey: 'preview',
            debugName: 'Preview',
            onChange: function (source) {
                queuePreviewRefresh(source);
            }
        })) {
            var previewAttempts = 0;
            var previewPoll = window.setInterval(function () {
                previewAttempts += 1;
                if (attachAsukaRuntimeChangeHooks(shell, {
                    registryKey: 'preview',
                    debugName: 'Preview',
                    onChange: function (source) {
                        queuePreviewRefresh(source);
                    }
                }) || previewAttempts > 20) {
                    window.clearInterval(previewPoll);
                }
            }, 150);
            shell.__apdPreviewListenerPoll = previewPoll;
        }

        if (root && typeof MutationObserver !== 'undefined') {
            var observerRoot = root.querySelector('.woocommerce-product-gallery, .wp-block-woocommerce-product-image-gallery, .woocommerce-product-gallery__wrapper') || root;
            var observer = new MutationObserver(debounce(function () {
                if (root.dataset && root.dataset.apdLatestPreview) {
                    updateProductImagePreview(shell, root.dataset.apdLatestPreview);
                }
            }, 120));
            observer.observe(observerRoot, { childList: true, subtree: true });
            shell.__apdPreviewObserver = observer;
        }

        queuePreviewRefresh('initial');
    }

    function attachPricingSync(shell, productForm) {
        if (!shell || shell.dataset.apdPricingBound === '1') {
            return;
        }
        shell.dataset.apdPricingBound = '1';

        var refreshPrice = debounce(function () {
            var basePrice = getCurrentBasePrice(productForm, shell);
            var snapshot = syncShell(shell, { basePrice: basePrice });
            syncFormPayloadFromShell(shell, productForm);
            calculatePricing(shell, snapshot, productForm, { force: true, triggerSource: shell.__apdPricingTriggerSource || 'unknown' });
        }, 180);

        function queuePriceRefresh(source) {
            shell.__apdPricingTriggerSource = source || 'util.subscribe';
            refreshPrice();
        }

        shell.__apdRefreshPrice = queuePriceRefresh;

        function ensureDesignerListener() {
            return attachAsukaRuntimeChangeHooks(shell, {
                registryKey: 'pricing',
                debugName: 'Pricing',
                useDocumentSignature: false,
                onChange: function (source) {
                    queuePriceRefresh(source);
                }
            });
        }

        if (!ensureDesignerListener()) {
            var attempts = 0;
            var poll = window.setInterval(function () {
                attempts += 1;
                if (ensureDesignerListener() || attempts > 20) {
                    window.clearInterval(poll);
                }
            }, 150);
            shell.__apdPricingListenerPoll = poll;
        }

        queuePriceRefresh('initial');
    }

    function bindShell(shell) {
        if (!shell || shell.dataset.apdShellBound === '1') {
            return;
        }
        shell.dataset.apdShellBound = '1';

        var saveButton = shell.querySelector('[data-apd-save-design]');
        var previewButton = shell.querySelector('[data-apd-generate-preview]');
        var syncButton = shell.querySelector('[data-apd-sync-design]');
        var designIdField = shell.querySelector('[data-apd-user-design-id]');
        var previewUrlField = shell.querySelector('[data-apd-preview-url]');

        if (!shell.dataset.apdShellKey) {
            shell.dataset.apdShellKey = shell.dataset.configId ? 'config:' + String(shell.dataset.configId) : 'parent';
        }

        if (shell.dataset.apdCartSourceBound !== '1') {
            shell.dataset.apdCartSourceBound = '1';
            ['pointerdown', 'mousedown', 'touchstart', 'focusin', 'input', 'change', 'keydown'].forEach(function (eventName) {
                shell.addEventListener(eventName, function () {
                    markShellAsCartSource(shell, 'dom:' + eventName);
                }, true);
            });
        }

        var productForm = getProductForm(shell);
        seedShellCartDocumentFromConfig(shell, 'bind-shell');

        if (syncButton) {
            syncButton.addEventListener('click', function () {
                syncShell(shell, { basePrice: getCurrentBasePrice(productForm, shell) });
            });
        }

        if (previewButton) {
            previewButton.addEventListener('click', function () {
                var snapshot = syncShell(shell, { basePrice: getCurrentBasePrice(productForm, shell) });
                if (!snapshot.preview) {
                    setStatus(shell, runtimeLabel('statusNoPreview', 'No preview could be generated yet.'));
                    return;
                }

                setStatus(shell, runtimeLabel('statusStoringPreview', 'Storing preview...'));
                request('preview/generate', {
                    configId: Number(shell.dataset.configId || 0),
                    productId: Number(shell.dataset.productId || 0),
                    preview: snapshot.preview
                }).then(function (json) {
                    if (json && json.success && json.previewUrl && previewUrlField) {
                        previewUrlField.value = json.previewUrl;
                    }
                    setStatus(shell, json && json.message ? json.message : runtimeLabel('statusPreviewStored', 'Preview stored.'));
                }).catch(function () {
                    setStatus(shell, runtimeLabel('statusPreviewFailed', 'Preview storage failed.'));
                });
            });
        }

        if (saveButton) {
            saveButton.addEventListener('click', function () {
                var snapshot = syncShell(shell, { basePrice: getCurrentBasePrice(productForm, shell) });

                setStatus(shell, runtimeLabel('statusSavingDesign', 'Saving design...'));
                request('design/save', {
                    configId: Number(shell.dataset.configId || 0),
                    productId: Number(shell.dataset.productId || 0),
                    title: runtimeLabel('savedDesignTitle', 'Saved design'),
                    design: snapshot.design,
                    state: snapshot.state || {},
                    preview: snapshot.preview,
                    pricing: snapshot.pricing || null
                }).then(function (json) {
                    if (json && json.success && designIdField && json.id) {
                        designIdField.value = json.id;
                    }

                    if (json && json.previewUrl && previewUrlField) {
                        previewUrlField.value = json.previewUrl;
                    }

                    setStatus(shell, json && json.message ? json.message : runtimeLabel('statusDesignSaved', 'Design saved.'));
                }).catch(function () {
                    setStatus(shell, runtimeLabel('statusDesignSaveFailed', 'Design save failed.'));
                });
            });
        }

        if (productForm) {
            updateVariationFields(shell, productForm);
            syncFormPayloadFromShell(shell, productForm);
            updateCartEditSubmitUi(productForm, shell);
        }

        logApdVariationDebug('bindShell', {
            shell: summarizeShellDebug(shell),
            productFormPresent: !!productForm
        });

        restorePendingDraft(shell, productForm);

        var bindConfigScript = shell.querySelector ? shell.querySelector('script.apd-config') : null;

        if (productForm && !productForm.dataset.apdShellSubmitBound) {
            productForm.dataset.apdShellSubmitBound = '1';

            productForm.addEventListener('click', function (event) {
                var target = event.target && event.target.closest ? event.target.closest('button, input') : null;
                if (!target || (String(target.type || '').toLowerCase() !== 'submit' && target.name !== 'add-to-cart')) {
                    return;
                }
                var clickShell = getActiveShellForForm(productForm);
                if (!clickShell) {
                    apdSubmitDebugLog('submitter-click:no-shell', { form: summarizeCartFormPayload(productForm), duplicates: summarizeDuplicateFormFields(productForm) });
                    return;
                }
                var clickSnapshot = syncShell(clickShell, { basePrice: getCurrentBasePrice(productForm, clickShell), reason: 'submitter-click' });
                updateVariationFields(clickShell, productForm);
                syncFormPayloadFromShell(clickShell, productForm);
                persistPendingDraft(clickShell, productForm, clickSnapshot);
                apdSubmitDebugLog('submitter-click:synced', {
                    submitter: { name: target.name || '', value: target.value || '', type: target.type || '' },
                    shell: summarizeShellDebug(clickShell),
                    liveCanvas: summarizeLiveCanvasForSubmit(clickShell),
                    snapshot: summarizeCartSnapshot(clickSnapshot),
                    form: summarizeCartFormPayload(productForm),
                    duplicates: summarizeDuplicateFormFields(productForm)
                });
            }, true);

            productForm.addEventListener('formdata', function (event) {
                var formDataShell = getActiveShellForForm(productForm);
                if (!formDataShell || !event.formData) {
                    return;
                }
                var formDataSnapshot = syncShell(formDataShell, { basePrice: getCurrentBasePrice(productForm, formDataShell), reason: 'formdata' });
                updateVariationFields(formDataShell, productForm);
                syncFormPayloadFromShell(formDataShell, productForm);
                var fields = ensureFormPayloadFields(productForm);
                APD_FORM_FIELD_NAMES.forEach(function (name) {
                    if (fields[name]) {
                        event.formData.set(name, fields[name].value || '');
                    }
                });
                var productId = parseInt(String(fields.apd_product_id ? fields.apd_product_id.value || '0' : '0'), 10) || resolveProductId(productForm);
                if (productId > 0) {
                    event.formData.set('add-to-cart', String(productId));
                }
                apdSubmitDebugLog('formdata:synced', {
                    shell: summarizeShellDebug(formDataShell),
                    liveCanvas: summarizeLiveCanvasForSubmit(formDataShell),
                    snapshot: summarizeCartSnapshot(formDataSnapshot),
                    form: summarizeCartFormPayload(productForm),
                    duplicates: summarizeDuplicateFormFields(productForm)
                });
            });

            productForm.addEventListener('submit', function (event) {
                var activeShell = getActiveShellForForm(productForm);
                if (!activeShell) {
                    apdSubmitDebugLog('submit:no-active-shell', {
                        form: summarizeCartFormPayload(productForm),
                        duplicates: summarizeDuplicateFormFields(productForm)
                    });
                    return;
                }

                var bypassPreviewStorage = productForm.dataset.apdBypassPreviewStorageOnce === '1';
                if (bypassPreviewStorage) {
                    productForm.dataset.apdBypassPreviewStorageOnce = '0';
                }

                apdSubmitDebugLog('submit:start', {
                    bypassPreviewStorage: bypassPreviewStorage,
                    selectedShell: summarizeShellDebug(activeShell),
                    liveCanvasBeforeSync: summarizeLiveCanvasForSubmit(activeShell),
                    formBeforeSync: summarizeCartFormPayload(productForm),
                    duplicatesBeforeSync: summarizeDuplicateFormFields(productForm)
                });

                var snapshot = syncShell(activeShell, { basePrice: getCurrentBasePrice(productForm, activeShell), reason: 'submit' });
                updateVariationFields(activeShell, productForm);
                syncFormPayloadFromShell(activeShell, productForm);
                persistPendingDraft(activeShell, productForm, snapshot);

                apdSubmitDebugLog('submit:after-sync', {
                    bypassPreviewStorage: bypassPreviewStorage,
                    shell: summarizeShellDebug(activeShell),
                    liveCanvasAfterSync: summarizeLiveCanvasForSubmit(activeShell),
                    snapshot: summarizeCartSnapshot(snapshot),
                    formAfterSync: summarizeCartFormPayload(productForm),
                    duplicatesAfterSync: summarizeDuplicateFormFields(productForm)
                });

                if (!validateBeforeSubmit(activeShell, snapshot, productForm)) {
                    event.preventDefault();
                    event.stopPropagation();
                    return;
                }

                if (bypassPreviewStorage) {
                    // The pending draft only exists to survive the async preview
                    // storage/resubmit hop. Once the real WooCommerce submit is
                    // allowed to leave the page, do not auto-import that draft on
                    // the next product page visit: it would make a fresh product
                    // look like it has resumed an older cart design.
                    clearPendingDraftForShell(activeShell);
                }

                if (!bypassPreviewStorage) {
                    event.preventDefault();
                    event.stopPropagation();

                    ensurePreviewStored(activeShell, snapshot).then(function () {
                        syncFormPayloadFromShell(activeShell, productForm);
                        apdSubmitDebugLog('submit:preview-stored:before-resubmit', {
                            shell: summarizeShellDebug(activeShell),
                            form: summarizeCartFormPayload(productForm),
                            duplicates: summarizeDuplicateFormFields(productForm)
                        });
                        productForm.dataset.apdBypassPreviewStorageOnce = '1';
                        if (typeof productForm.requestSubmit === 'function') {
                            try {
                                if (event.submitter) {
                                    productForm.requestSubmit(event.submitter);
                                } else {
                                    productForm.requestSubmit();
                                }
                                return;
                            } catch (error) {}
                        }
                        HTMLFormElement.prototype.submit.call(productForm);
                    }).catch(function (error) {
                        syncFormPayloadFromShell(activeShell, productForm);
                        apdSubmitDebugLog('submit:preview-failed:before-resubmit', {
                            error: error && error.message ? error.message : String(error || ''),
                            shell: summarizeShellDebug(activeShell),
                            form: summarizeCartFormPayload(productForm),
                            duplicates: summarizeDuplicateFormFields(productForm)
                        });
                        productForm.dataset.apdBypassPreviewStorageOnce = '1';
                        if (typeof productForm.requestSubmit === 'function') {
                            try {
                                if (event.submitter) {
                                    productForm.requestSubmit(event.submitter);
                                } else {
                                    productForm.requestSubmit();
                                }
                                return;
                            } catch (error) {}
                        }
                        HTMLFormElement.prototype.submit.call(productForm);
                    });
                    return;
                }

                try {
                    calculatePricing(activeShell, snapshot, productForm, { force: true });
                    syncFormPayloadFromShell(activeShell, productForm);
                } catch (error) {
                    if (window.console && typeof window.console.error === 'function') {
                        window.console.error('[APD] Submit pricing sync failed.', error);
                    }
                }
            });
        }

        attachPricingSync(shell, productForm);
        attachPreviewSync(shell, productForm);
    }

    function shouldSkipShellForAutoMount(shell) {
        if (!shell || typeof shell.closest !== 'function') {
            return false;
        }
        return !!shell.closest('[data-apd-condensed-source][hidden]');
    }

    function getMountableShells(scope) {
        scope = scope || document;
        if (!scope.querySelectorAll) {
            return [];
        }
        return Array.prototype.filter.call(scope.querySelectorAll('[data-apd-shell]'), function (shell) {
            return !shouldSkipShellForAutoMount(shell);
        });
    }

    function mountAndBind(scope) {
        scope = scope || document;
        var allShells = scope.querySelectorAll ? scope.querySelectorAll('[data-apd-shell]') : [];
        var shells = getMountableShells(scope);
        logApdVariationDebug('mountAndBind:start', {
            shellCount: allShells.length || 0,
            mountableShellCount: shells.length,
            skippedShells: Array.prototype.map.call(allShells, function (shell) {
                return shouldSkipShellForAutoMount(shell) ? summarizeShellDebug(shell) : null;
            }).filter(Boolean)
        });
        if (window.APDRuntimeBridge && typeof window.APDRuntimeBridge.mountOne === 'function') {
            shells.forEach(function (shell) {
                window.APDRuntimeBridge.mountOne(shell);
            });
        } else if (window.APDRuntimeBridge && typeof window.APDRuntimeBridge.mountAll === 'function') {
            window.APDRuntimeBridge.mountAll(scope);
        }
        shells.forEach(bindShell);
        logApdVariationDebug('mountAndBind:end', {
            shells: shells.map(summarizeShellDebug)
        });
    }

    function initVariationPricing(scope) {
        scope = scope || document;
        scope.querySelectorAll('form.variations_form, form.cart').forEach(function (form) {
            if (form.dataset.apdVariationPricingBound === '1') {
                return;
            }
            form.dataset.apdVariationPricingBound = '1';

            if (!form.dataset.apdCurrentBasePrice) {
                form.dataset.apdCurrentBasePrice = String(inferBasePrice(form, form));
            }
            if (!form.dataset.apdDefaultBasePrice) {
                form.dataset.apdDefaultBasePrice = form.dataset.apdCurrentBasePrice || '0';
            }
            rememberCurrentDisplayedPrice(form, true);

            function refreshActiveShell() {
                var activeShell = getActiveShellForForm(form);
                if (activeShell) {
                    clearValidationMessage(form, activeShell);
                    updateVariationFields(activeShell, form);
                    syncFormPayloadFromShell(activeShell, form);
                    updateCartEditSubmitUi(form, activeShell);
                } else {
                    clearFormPayloadFields(form);
                    restoreProductImagePreview(form);
                    restoreDisplayedPrice(form);
                }
                if (activeShell && typeof activeShell.__apdRefreshPrice === 'function') {
                    window.setTimeout(function () {
                        activeShell.__apdRefreshPrice();
                    }, 30);
                }
            }

            function scheduleRefreshAfterPriceUpdate() {
                window.setTimeout(function () {
                    rememberCurrentDisplayedPrice(form, true);
                    refreshActiveShell();
                }, 30);
            }

            form.addEventListener('found_variation', function (event) {
                var variation = event && event.detail ? event.detail.variation : null;
                if (variation && typeof variation.display_price !== 'undefined') {
                    form.dataset.apdCurrentBasePrice = String(variation.display_price);
                }
                scheduleRefreshAfterPriceUpdate();
            });

            form.addEventListener('reset_data', function () {
                form.dataset.apdCurrentBasePrice = String(form.dataset.apdDefaultBasePrice || '0');
                scheduleRefreshAfterPriceUpdate();
            });

            form.addEventListener('hide_variation', function () {
                form.dataset.apdCurrentBasePrice = String(form.dataset.apdDefaultBasePrice || '0');
                scheduleRefreshAfterPriceUpdate();
            });

            if (window.jQuery && typeof window.jQuery === 'function') {
                var $form = window.jQuery(form);
                $form.on('found_variation', function (event, variation) {
                    if (variation && typeof variation.display_price !== 'undefined') {
                        form.dataset.apdCurrentBasePrice = String(variation.display_price);
                    }
                    scheduleRefreshAfterPriceUpdate();
                });
                $form.on('reset_data hide_variation', function () {
                    form.dataset.apdCurrentBasePrice = String(form.dataset.apdDefaultBasePrice || '0');
                    scheduleRefreshAfterPriceUpdate();
                });
            }
        });
    }

    function initShellSwitchers(scope) {
        scope = scope || document;
        scope.querySelectorAll('[data-apd-shell-switcher]').forEach(function (switcher) {
            if (switcher.closest && switcher.closest('[data-apd-condensed-source]')) {
                return;
            }
            if (switcher.dataset.apdGalleryBound === '1') {
                return;
            }
            switcher.dataset.apdGalleryBound = '1';

            var host = switcher.querySelector('[data-apd-active-shell]');
            var form = getProductForm(switcher);
            var renderedKey = null;
            var initialExistingShell = host ? host.querySelector('[data-apd-shell]:not([hidden])') : null;
            var payloadRegistry = getShellPayloadRegistryMap(switcher);
            logApdTemplateCheck('shellSwitcher:init', {
                defaultKey: switcher.getAttribute('data-default-key') || '',
                registryId: switcher.getAttribute('data-apd-registry-id') || '',
                registryKeys: payloadRegistry && typeof payloadRegistry === 'object' ? Object.keys(payloadRegistry) : [],
                registry: summarizeRegistryMapDebug(payloadRegistry),
                initialShell: summarizeShellDebug(initialExistingShell)
            });

            if (form) {
                applyResumeSelectionToForm(form, switcher);
            }

            if (host) {
                getShellBlueprint(switcher, host);
            }

            if (host && initialExistingShell) {
                var initialDefaultKey = switcher.getAttribute('data-default-key') || '';
                if (initialDefaultKey) {
                    renderedKey = initialDefaultKey;
                    initialExistingShell.dataset.apdShellKey = initialDefaultKey;
                    logApdVariationDebug('shellSwitcher:hydrate-existing-default-shell', {
                        key: initialDefaultKey,
                        shell: summarizeShellDebug(initialExistingShell)
                    });
                }
            }

            function renderKey(key) {
                if (!host) {
                    return;
                }
                payloadRegistry = getShellPayloadRegistryMap(switcher);
                logApdVariationDebug('shellSwitcher:renderKey:requested', {
                    requestedKey: key,
                    previousKey: renderedKey,
                    defaultKey: switcher.getAttribute('data-default-key') || '',
                    switcherKeys: Array.prototype.map.call(switcher.querySelectorAll('template[data-apd-shell-template]'), function (node) {
                        return node.getAttribute('data-apd-shell-template') || '';
                    }),
                    registryKeys: payloadRegistry && typeof payloadRegistry === 'object' ? Object.keys(payloadRegistry) : []
                });
                logApdTemplateCheck('shellSwitcher:select-key', {
                    requestedKey: key,
                    previousKey: renderedKey,
                    defaultKey: switcher.getAttribute('data-default-key') || '',
                    registryKeys: payloadRegistry && typeof payloadRegistry === 'object' ? Object.keys(payloadRegistry) : [],
                    selectedRegistryPayload: summarizeRegistryPayloadDebug(payloadRegistry && payloadRegistry[key] ? payloadRegistry[key] : null),
                    currentShellBeforeSwitch: summarizeShellDebug(host.querySelector('[data-apd-shell]:not([hidden])')),
                    runtimeBeforeSwitch: getRuntimeShellDebugState(host.querySelector('[data-apd-shell]:not([hidden])'))
                });
                if (key === renderedKey) {
                    logApdVariationDebug('shellSwitcher:renderKey:skip-same-key', { key: key });
                    return;
                }

                var liveRegistryPayload = payloadRegistry && typeof payloadRegistry === 'object' && payloadRegistry[key] && typeof payloadRegistry[key] === 'object'
                    ? payloadRegistry[key]
                    : null;
                var liveShell = host.querySelector('[data-apd-shell]:not([hidden])');
                var liveFullState = liveRegistryPayload ? getRegistryFullState(liveRegistryPayload) : null;
                if (liveShell && liveShell.__apdInstance && liveFullState && window.APDRuntimeBridge && typeof window.APDRuntimeBridge.importFullProductStateToShell === 'function') {
                    renderedKey = key;
                    updateLiveShellRegistryPayloadFields(liveShell, liveRegistryPayload, key);
                    var liveDocumentState = getRegistryDocumentState(liveRegistryPayload);
                    var importedFullState = !!window.APDRuntimeBridge.importFullProductStateToShell(liveShell, liveFullState, liveDocumentState, {
                        source: 'woocommerce-variation-registry:hot-switch-importFull',
                        key: key || '',
                        replaceViews: true,
                        replaceSnapshots: true,
                        importDocumentFallback: true
                    });
                    logApdVariationDebug('shellSwitcher:renderKey:hot-switch-importFull', {
                        key: key,
                        importedFullState: importedFullState,
                        fullStateKeys: liveFullState && typeof liveFullState === 'object' ? safeObjectKeys(liveFullState) : [],
                        document: summarizeViewContainer(liveDocumentState),
                        shell: summarizeShellDebug(liveShell)
                    });
                    logApdTemplateCheck('shellSwitcher:after-hot-switch-importFull', {
                        key: key,
                        importedFullState: importedFullState,
                        selectedRegistryPayload: summarizeRegistryPayloadDebug(liveRegistryPayload),
                        shell: summarizeShellDebug(liveShell),
                        runtimeAfterImport: getRuntimeShellDebugState(liveShell)
                    });
                    bindShell(liveShell);
                    if (form && liveShell) {
                        updateVariationFields(liveShell, form);
                        syncFormPayloadFromShell(liveShell, form);
                    }
                    return;
                }

                renderedKey = key;
                replaceRenderedShell(host, null, { preservePreview: false });
                if (!key) {
                    host.innerHTML = '<div class="apd-product-gallery-placeholder" data-apd-gallery-placeholder>' + escapeHtml(runtimeLabel('galleryChooseVariation', 'Choose a variation to load the linked custom product designer.')) + '</div>';
                    if (form) {
                        clearFormPayloadFields(form);
                    }
                    return;
                }

                var mountedShell = null;
                if (payloadRegistry && typeof payloadRegistry === 'object' && payloadRegistry[key] && typeof payloadRegistry[key] === 'object') {
                    var registryShell = buildShellFromRegistryPayload(switcher, host, payloadRegistry[key], key);
                    if (registryShell) {
                        var registryFragment = document.createDocumentFragment();
                        registryFragment.appendChild(registryShell);
                        mountedShell = replaceRenderedShell(host, registryFragment, { preservePreview: false });
                        logApdVariationDebug('shellSwitcher:renderKey:mounted-shell-registry', {
                            key: key,
                            payload: summarizeMountPayload(payloadRegistry[key].config || {}),
                            shell: summarizeShellDebug(mountedShell)
                        });
                        logApdTemplateCheck('shellSwitcher:mounted-shell-registry', {
                            key: key,
                            selectedRegistryPayload: summarizeRegistryPayloadDebug(payloadRegistry[key]),
                            shell: summarizeShellDebug(mountedShell)
                        });
                    }
                }

                if (!mountedShell) {
                    var template = switcher.querySelector('template[data-apd-shell-template="' + key + '"]');
                    if (!template) {
                        logApdVariationDebug('shellSwitcher:renderKey:missing-template', { key: key });
                        var fallback = switcher.getAttribute('data-default-key') || '';
                        if (fallback && fallback !== key) {
                            renderKey(fallback);
                            return;
                        }
                        host.innerHTML = '<div class="apd-product-gallery-placeholder" data-apd-gallery-placeholder>' + escapeHtml(runtimeLabel('galleryNoLinkedCustomProduct', 'No custom product is linked to this variation.')) + '</div>';
                        if (form) {
                            clearFormPayloadFields(form);
                        }
                        return;
                    }
                    mountedShell = replaceRenderedShell(host, template.content.cloneNode(true), { preservePreview: false });
                    if (mountedShell) {
                        mountedShell.dataset.apdShellKey = key;
                    }
                    logApdVariationDebug('shellSwitcher:renderKey:mounted-shell-template', {
                        key: key,
                        shell: summarizeShellDebug(mountedShell)
                    });
                }

                if (payloadRegistry && payloadRegistry[key] && typeof payloadRegistry[key] === 'object') {
                    mountAndBindRegistryShell(host, mountedShell, payloadRegistry[key], key);
                } else {
                    mountAndBind(host);
                }
                logApdVariationDebug('shellSwitcher:renderKey:after-mount', {
                    key: key,
                    shell: summarizeShellDebug(mountedShell)
                });
                logApdTemplateCheck('shellSwitcher:after-mount', {
                    key: key,
                    selectedRegistryPayload: summarizeRegistryPayloadDebug(payloadRegistry && payloadRegistry[key] ? payloadRegistry[key] : null),
                    shell: summarizeShellDebug(mountedShell),
                    runtimeAfterMount: getRuntimeShellDebugState(mountedShell)
                });
                if (form && mountedShell) {
                    updateVariationFields(mountedShell, form);
                    syncFormPayloadFromShell(mountedShell, form);
                }
            }

            if (!renderedKey) {
                renderKey(switcher.getAttribute('data-default-key') || '');
            }

            if (!form) {
                return;
            }

            form.addEventListener('found_variation', function (event) {
                var variation = event.detail && event.detail.variation ? event.detail.variation : null;
                var variationId = variation && variation.variation_id ? String(variation.variation_id) : '';
                logApdVariationDebug('shellSwitcher:event:found_variation', {
                    source: 'native',
                    variationId: variationId,
                    variation: variation || null
                });
                if (variationId) {
                    renderKey('variation:' + variationId);
                }
            });
            form.addEventListener('reset_data', function () {
                logApdVariationDebug('shellSwitcher:event:reset_data', { source: 'native' });
                renderKey(switcher.getAttribute('data-default-key') || '');
            });
            form.addEventListener('hide_variation', function () {
                logApdVariationDebug('shellSwitcher:event:hide_variation', { source: 'native' });
                renderKey(switcher.getAttribute('data-default-key') || '');
            });

            if (window.jQuery && typeof window.jQuery === 'function') {
                var $form = window.jQuery(form);
                $form.on('found_variation', function (event, variation) {
                    var variationId = variation && variation.variation_id ? String(variation.variation_id) : '';
                    logApdVariationDebug('shellSwitcher:event:found_variation', {
                        source: 'jquery',
                        variationId: variationId,
                        variation: variation || null
                    });
                    if (variationId) {
                        renderKey('variation:' + variationId);
                    }
                });
                $form.on('reset_data hide_variation', function (event) {
                    logApdVariationDebug('shellSwitcher:event:' + String(event.type || 'unknown'), { source: 'jquery' });
                    renderKey(switcher.getAttribute('data-default-key') || '');
                });
            }
        });
    }

    function findNearestCommonColumns(leftColumn, rightColumn) {
        var current = leftColumn;
        while (current) {
            if (current.classList && current.classList.contains('wp-block-columns') && current.contains(rightColumn)) {
                return current;
            }
            current = current.parentElement;
        }

        return null;
    }

    function findSummaryColumn(blockColumns, mediaColumn) {
        var selectors = [
            '.wp-block-woocommerce-product-price',
            '.wp-block-post-title',
            '.wp-block-woocommerce-product-meta'
        ];

        for (var i = 0; i < selectors.length; i += 1) {
            var nodes = blockColumns.querySelectorAll(selectors[i]);
            for (var j = 0; j < nodes.length; j += 1) {
                var candidate = nodes[j].closest('.wp-block-column');
                if (candidate && candidate !== mediaColumn) {
                    return candidate;
                }
            }
        }

        return null;
    }

    function applyFullWidthLayout(source, target) {
        if (!source || !target || source.dataset.apdDisplayMode !== 'full_width') {
            return;
        }

        document.body.classList.add('apd-mode-full-width');
        target.classList.add('apd-gallery-replaced--full-width');

        var galleryBlock = target.closest('.wp-block-woocommerce-product-image-gallery');
        if (!galleryBlock) {
            return;
        }

        var mediaColumn = galleryBlock.closest('.wp-block-column');
        if (!mediaColumn) {
            return;
        }

        var blockColumns = galleryBlock.closest('.wp-block-columns');
        if (!blockColumns) {
            return;
        }

        var summaryColumn = findSummaryColumn(blockColumns, mediaColumn);
        if (!summaryColumn) {
            return;
        }

        var commonColumns = findNearestCommonColumns(mediaColumn, summaryColumn);
        if (!commonColumns) {
            return;
        }

        commonColumns.classList.add('apd-fullwidth-stack');
        mediaColumn.classList.add('apd-fullwidth-stack__media');
        summaryColumn.classList.add('apd-fullwidth-stack__summary');
    }

    function createFallbackProductGalleryTarget() {
        var summary = document.querySelector(
            '.single-product div.product .summary, ' +
            '.single-product div.product .entry-summary, ' +
            '.single-product .wp-block-woocommerce-product-summary'
        );
        if (!summary || !summary.parentNode) {
            return null;
        }

        var target = document.createElement('div');
        target.className = 'images apd-product-gallery-fallback';
        target.setAttribute('data-product-gallery', 'apd-generated');
        target.setAttribute('data-apd-generated-gallery', '1');
        summary.parentNode.insertBefore(target, summary);

        return target;
    }

    function initCondensedReplacement(scope) {
        scope = scope || document;
        scope.querySelectorAll('[data-apd-condensed-source]').forEach(function (source) {
            if (source.dataset.apdCondensedProcessed === '1') {
                return;
            }
            var switcher = source.querySelector('[data-apd-shell-switcher]');
            if (!switcher) {
                return;
            }
            var target = document.querySelector('.woocommerce-product-gallery, .single-product div.product div.images, .product .images, [data-product-gallery]');
            if (!target) {
                target = createFallbackProductGalleryTarget();
            }
            if (!target) {
                source.hidden = false;
                source.classList.add('apd-condensed-source--inline-fallback');
                source.dataset.apdCondensedProcessed = '1';
                return;
            }

            source.dataset.apdCondensedProcessed = '1';

            var form = getProductForm(switcher);
            var defaultKey = switcher.getAttribute('data-default-key') || '';
            var targetInitialHtml = target.innerHTML;
            var targetInitialClassName = target.className;
            var targetInitialGalleryBound = target.getAttribute('data-apd-gallery-bound');
            var galleryReplacedInitial = target.classList.contains('apd-gallery-replaced');
            var galleryBlock = target.closest('.wp-block-woocommerce-product-image-gallery');
            var mediaColumn = galleryBlock ? galleryBlock.closest('.wp-block-column') : null;
            var columnsRoot = null;
            var summaryColumn = null;

            if (galleryBlock && mediaColumn) {
                var blockColumns = galleryBlock.closest('.wp-block-columns');
                if (blockColumns) {
                    summaryColumn = findSummaryColumn(blockColumns, mediaColumn);
                    if (summaryColumn) {
                        columnsRoot = findNearestCommonColumns(mediaColumn, summaryColumn);
                    }
                }
            }

            var renderedKey = null;
            var payloadRegistry = getShellPayloadRegistryMap(switcher);
            logApdTemplateCheck('condensedSwitcher:init', {
                defaultKey: defaultKey,
                registryId: switcher.getAttribute('data-apd-registry-id') || '',
                registryKeys: payloadRegistry && typeof payloadRegistry === 'object' ? Object.keys(payloadRegistry) : [],
                registry: summarizeRegistryMapDebug(payloadRegistry)
            });

            function cleanupFullWidthClasses() {
                target.classList.remove('apd-gallery-replaced--full-width');
                if (columnsRoot) {
                    columnsRoot.classList.remove('apd-fullwidth-stack');
                }
                if (mediaColumn) {
                    mediaColumn.classList.remove('apd-fullwidth-stack__media');
                }
                if (summaryColumn) {
                    summaryColumn.classList.remove('apd-fullwidth-stack__summary');
                }
            }

            function restoreOriginalGallery() {
                cleanupFullWidthClasses();
                logApdVariationDebug('condensedSwitcher:restoreOriginalGallery', {
                    renderedKey: renderedKey,
                    defaultKey: defaultKey
                });
                renderedKey = null;
                var existingShell = switcher.querySelector('[data-apd-active-shell] [data-apd-shell]:not([hidden])');
                if (existingShell) {
                    teardownShell(existingShell, { preservePreview: false });
                }
                target.innerHTML = targetInitialHtml;
                target.className = targetInitialClassName;
                if (targetInitialGalleryBound !== null) {
                    target.setAttribute('data-apd-gallery-bound', targetInitialGalleryBound);
                } else {
                    target.removeAttribute('data-apd-gallery-bound');
                }
                if (!galleryReplacedInitial) {
                    target.classList.remove('apd-gallery-replaced');
                }
                restoreProductImagePreview(target);
            }

            function ensureSwitcherMounted() {
                if (switcher.parentElement === target) {
                    return;
                }
                while (target.firstChild) {
                    target.removeChild(target.firstChild);
                }
                target.classList.add('apd-gallery-replaced');
                target.appendChild(switcher);
            }

            function renderKey(key) {
                if (!switcher || !target) {
                    return;
                }
                logApdVariationDebug('condensedSwitcher:renderKey:requested', {
                    requestedKey: key,
                    previousKey: renderedKey,
                    defaultKey: defaultKey,
                    switcherKeys: Array.prototype.map.call(switcher.querySelectorAll('template[data-apd-shell-template]'), function (node) {
                        return node.getAttribute('data-apd-shell-template') || '';
                    })
                });
                logApdTemplateCheck('condensedSwitcher:select-key', {
                    requestedKey: key,
                    previousKey: renderedKey,
                    defaultKey: defaultKey,
                    registryKeys: payloadRegistry && typeof payloadRegistry === 'object' ? Object.keys(payloadRegistry) : [],
                    selectedRegistryPayload: summarizeRegistryPayloadDebug(payloadRegistry && payloadRegistry[key] ? payloadRegistry[key] : null),
                    currentShellBeforeSwitch: summarizeShellDebug(switcher.querySelector('[data-apd-active-shell] [data-apd-shell]:not([hidden])')),
                    runtimeBeforeSwitch: getRuntimeShellDebugState(switcher.querySelector('[data-apd-active-shell] [data-apd-shell]:not([hidden])'))
                });
                if (!key) {
                    restoreOriginalGallery();
                    return;
                }
                if (key === renderedKey && switcher.parentElement === target) {
                    logApdVariationDebug('condensedSwitcher:renderKey:skip-same-key', { key: key });
                    return;
                }
                payloadRegistry = getShellPayloadRegistryMap(switcher);
                renderedKey = key;
                ensureSwitcherMounted();
                var host = switcher.querySelector('[data-apd-active-shell]');
                if (!host) {
                    return;
                }
                var mountedShell = null;
                if (payloadRegistry && typeof payloadRegistry === 'object' && payloadRegistry[key] && typeof payloadRegistry[key] === 'object') {
                    var registryShell = buildShellFromRegistryPayload(switcher, host, payloadRegistry[key], key);
                    if (registryShell) {
                        var registryFragment = document.createDocumentFragment();
                        registryFragment.appendChild(registryShell);
                        mountedShell = replaceRenderedShell(host, registryFragment, { preservePreview: false });
                        logApdVariationDebug('condensedSwitcher:renderKey:mounted-shell-registry', {
                            key: key,
                            payload: summarizeMountPayload(payloadRegistry[key].config || {}),
                            shell: summarizeShellDebug(mountedShell)
                        });
                        logApdTemplateCheck('condensedSwitcher:mounted-shell-registry', {
                            key: key,
                            selectedRegistryPayload: summarizeRegistryPayloadDebug(payloadRegistry[key]),
                            shell: summarizeShellDebug(mountedShell)
                        });
                    }
                }
                if (!mountedShell) {
                    var template = switcher.querySelector('template[data-apd-shell-template="' + key + '"]');
                    if (!template) {
                        logApdVariationDebug('condensedSwitcher:renderKey:missing-template', { key: key });
                        if (defaultKey && defaultKey !== key) {
                            renderKey(defaultKey);
                            return;
                        }
                        restoreOriginalGallery();
                        return;
                    }
                    mountedShell = replaceRenderedShell(host, template.content.cloneNode(true), { preservePreview: false });
                    if (mountedShell) {
                        mountedShell.dataset.apdShellKey = key;
                    }
                    logApdVariationDebug('condensedSwitcher:renderKey:mounted-shell-template', {
                        key: key,
                        shell: summarizeShellDebug(mountedShell)
                    });
                }
                applyFullWidthLayout(source, target);
                if (payloadRegistry && payloadRegistry[key] && typeof payloadRegistry[key] === 'object') {
                    mountAndBindRegistryShell(target, mountedShell, payloadRegistry[key], key);
                } else {
                    mountAndBind(target);
                }
                logApdVariationDebug('condensedSwitcher:renderKey:after-mount', {
                    key: key,
                    shell: summarizeShellDebug(mountedShell)
                });
                logApdTemplateCheck('condensedSwitcher:after-mount', {
                    key: key,
                    selectedRegistryPayload: summarizeRegistryPayloadDebug(payloadRegistry && payloadRegistry[key] ? payloadRegistry[key] : null),
                    shell: summarizeShellDebug(mountedShell),
                    runtimeAfterMount: getRuntimeShellDebugState(mountedShell)
                });
            }

            if (defaultKey) {
                renderKey(defaultKey);
            } else {
                restoreOriginalGallery();
            }

            source.remove();

            if (!form) {
                return;
            }

            form.addEventListener('found_variation', function (event) {
                var variation = event.detail && event.detail.variation ? event.detail.variation : null;
                var variationId = variation && variation.variation_id ? String(variation.variation_id) : '';
                logApdVariationDebug('condensedSwitcher:event:found_variation', {
                    source: 'native',
                    variationId: variationId,
                    variation: variation || null
                });
                if (variationId) {
                    renderKey('variation:' + variationId);
                } else if (defaultKey) {
                    renderKey(defaultKey);
                } else {
                    restoreOriginalGallery();
                }
            });

            form.addEventListener('reset_data', function () {
                logApdVariationDebug('condensedSwitcher:event:reset_data', { source: 'native' });
                if (defaultKey) {
                    renderKey(defaultKey);
                } else {
                    restoreOriginalGallery();
                }
            });

            form.addEventListener('hide_variation', function () {
                logApdVariationDebug('condensedSwitcher:event:hide_variation', { source: 'native' });
                if (defaultKey) {
                    renderKey(defaultKey);
                } else {
                    restoreOriginalGallery();
                }
            });

            if (window.jQuery && typeof window.jQuery === 'function') {
                var $form = window.jQuery(form);
                $form.on('found_variation', function (event, variation) {
                    var variationId = variation && variation.variation_id ? String(variation.variation_id) : '';
                    logApdVariationDebug('condensedSwitcher:event:found_variation', {
                        source: 'jquery',
                        variationId: variationId,
                        variation: variation || null
                    });
                    if (variationId) {
                        renderKey('variation:' + variationId);
                    } else if (defaultKey) {
                        renderKey(defaultKey);
                    } else {
                        restoreOriginalGallery();
                    }
                });
                $form.on('reset_data hide_variation', function (event) {
                    logApdVariationDebug('condensedSwitcher:event:' + String(event.type || 'unknown'), { source: 'jquery' });
                    if (defaultKey) {
                        renderKey(defaultKey);
                    } else {
                        restoreOriginalGallery();
                    }
                });
            }
        });
    }

    function initDesignerModals(scope) {
        scope = scope || document;
        scope.querySelectorAll('[data-apd-modal]').forEach(function (modal) {
            if (modal.dataset.apdModalBound === '1') {
                return;
            }
            modal.dataset.apdModalBound = '1';

            function openModal() {
                modal.hidden = false;
                document.documentElement.classList.add('apd-modal-open');
                document.body.classList.add('apd-modal-open');

                var activeShell = modal.querySelector('[data-apd-shell]:not([hidden])');
                if (activeShell) {
                    markShellAsCartSource(activeShell, 'modal:open');
                }
                if (activeShell && typeof activeShell.__apdRefreshPreview === 'function') {
                    activeShell.__apdRefreshPreview();
                }
                if (activeShell && typeof activeShell.__apdRefreshPrice === 'function') {
                    activeShell.__apdRefreshPrice();
                }
            }

            function closeModal() {
                modal.hidden = true;
                document.documentElement.classList.remove('apd-modal-open');
                document.body.classList.remove('apd-modal-open');
            }

            document.querySelectorAll('[data-apd-open-modal]').forEach(function (button) {
                if (button.dataset.apdModalButtonBound === '1') {
                    return;
                }
                button.dataset.apdModalButtonBound = '1';
                button.addEventListener('click', openModal);
            });

            modal.querySelectorAll('[data-apd-close-modal]').forEach(function (button) {
                button.addEventListener('click', closeModal);
            });

            if (modal.dataset.apdAutoOpen === '1') {
                window.setTimeout(openModal, 60);
            }

            document.addEventListener('keydown', function (event) {
                if (event.key === 'Escape' && !modal.hidden) {
                    closeModal();
                }
            });
        });
    }

    var summaryPortalOrderingObserver = null;
    var summaryPortalOrderingFrame = 0;

    function orderSummaryPortalHosts(scope) {
        scope = scope || document;
        scope.querySelectorAll(
            '.summary.entry-summary > .ask-page-module-host[data-asuka-portal-host="element-variation-picker"]'
        ).forEach(function (host) {
            var summary = host.parentElement;
            var price = summary ? summary.querySelector(':scope > .price') : null;
            if (!price || price.nextElementSibling === host) {
                return;
            }
            price.insertAdjacentElement('afterend', host);
        });
    }

    function initSummaryPortalOrdering(scope) {
        orderSummaryPortalHosts(scope || document);
        if (summaryPortalOrderingObserver || typeof MutationObserver === 'undefined' || !document.body) {
            return;
        }

        summaryPortalOrderingObserver = new MutationObserver(function (mutations) {
            var portalChanged = mutations.some(function (mutation) {
                if (mutation.target instanceof Element && mutation.target.matches('.summary.entry-summary')) {
                    return true;
                }
                return Array.prototype.some.call(mutation.addedNodes || [], function (node) {
                    return node instanceof Element && (
                        node.matches('[data-asuka-portal-host="element-variation-picker"]') ||
                        node.querySelector('[data-asuka-portal-host="element-variation-picker"]')
                    );
                });
            });
            if (!portalChanged) {
                return;
            }
            if (summaryPortalOrderingFrame) {
                return;
            }
            summaryPortalOrderingFrame = window.requestAnimationFrame(function () {
                summaryPortalOrderingFrame = 0;
                orderSummaryPortalHosts(document);
            });
        });
        summaryPortalOrderingObserver.observe(document.body, { childList: true, subtree: true });
    }

    function boot(scope) {
        mountAndBind(scope || document);
        initVariationPricing(scope || document);
        initShellSwitchers(scope || document);
        initCondensedReplacement(scope || document);
        initDesignerModals(scope || document);
        initSummaryPortalOrdering(scope || document);
    }

    if (window.__APD_TEST_HOOKS__ && typeof window.__APD_TEST_HOOKS__ === 'object') {
        window.__APD_TEST_HOOKS__.normalizeCartDocumentPayload = normalizeCartDocumentPayload;
        window.__APD_TEST_HOOKS__.cartDocumentScore = cartDocumentScore;
    }

    window.APDFrontApp = {
        boot: boot,
        bindShell: bindShell,
        syncShell: syncShell,
        debugCart: function () {
            return null;
        }
    };

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', function () { boot(document); });
    } else {
        boot(document);
    }
})();
