/* ScanVault Label Designer — Main JS */
/* global svld_params, wp */

(function ($) {
    'use strict';

    const MM_TO_PX = 3.7795; // 1mm at 96dpi
    let elementCounter = 1000; // For unique element IDs

    // Measurement unit configuration
    let currentUnit = 'mm';
    let unitToMmFactor = 1.0;
    let unitLabel = 'mm';

    // Conversion factors from various units to mm
    const UNIT_CONVERSIONS = {
        'mm': 1.0,      // 1 mm = 1 mm
        'cm': 10.0,     // 1 cm = 10 mm
        'in': 25.4,     // 1 inch = 25.4 mm
        'pt': 0.352778  // 1 point = 0.352778 mm
    };

    // Unit labels for display
    const UNIT_LABELS = {
        'mm': 'mm',
        'cm': 'cm',
        'in': 'in',
        'pt': 'pt'
    };

    /**
     * Scan the current layout and advance elementCounter so it is always
     * higher than any existing element's numeric suffix.
     * Must be called every time `layout` is replaced (on load, template load, reset).
     */
    function syncElementCounter() {
        let maxNum = 999;
        layout.forEach(function (el) {
            const parts = (el.id || '').split('_');
            const num   = parseInt( parts[ parts.length - 1 ], 10 );
            if ( !isNaN(num) && num > maxNum ) maxNum = num;
        });
        elementCounter = maxNum + 1;
    }

    // =========================================================================
    // Pro Feature Tooltip
    // =========================================================================
    function showProTooltip($target) {
        // Remove existing tooltips
        $('.svld-pro-tooltip').remove();

        const upgradeUrl = (typeof svld_params !== 'undefined' && svld_params.upgrade_url)
            ? svld_params.upgrade_url : '#';
        const proTooltip = (typeof svld_params !== 'undefined' && svld_params.pro_tooltip)
            ? svld_params.pro_tooltip : '🔒 Pro feature — Upgrade to unlock';

        const offset = $target.offset();
        const tooltip = $(
            '<div class="svld-pro-tooltip">' +
                '<span class="svld-pro-icon">🔒</span>' +
                '<div class="svld-pro-text">' +
                    '<strong>Pro Feature</strong>' +
                    '<p>Upgrade to add elements and save templates</p>' +
                '</div>' +
                '<a href="' + upgradeUrl + '" target="_blank" class="svld-pro-btn">Upgrade to Pro</a>' +
            '</div>'
        );

        tooltip.css({
            top: offset.top + $target.outerHeight() + 8,
            left: offset.left
        });

        $('body').append(tooltip);

        // Auto-hide after 4 seconds
        setTimeout(function() {
            tooltip.fadeOut(300, function() {
                tooltip.remove();
            });
        }, 4000);
    }

    // State - with better error handling
    let layout = [];
    let settings = {};
    const isPro = true;

    try {
        if (typeof svld_params !== 'undefined') {
            layout = svld_params.layout || [];
            settings = svld_params.settings || {};

            // Initialize measurement unit - prioritize localStorage over server setting
            const savedUnit = localStorage.getItem('svld_measurement_unit');
            currentUnit = savedUnit || svld_params.measurement_unit || 'mm';
            unitToMmFactor = UNIT_CONVERSIONS[currentUnit] || 1.0;
            unitLabel = UNIT_LABELS[currentUnit] || 'mm';

            // Save to localStorage if it wasn't there
            if (!savedUnit && currentUnit) {
                localStorage.setItem('svld_measurement_unit', currentUnit);
            }

            // Normalize layout elements to ensure all required properties exist and are correct types
            if (Array.isArray(layout)) {
                layout.forEach(function(el) {
                    // Ensure boolean properties - use strict boolean check
                    el.multiLine = el.multiLine === true;
                    el.proportional = el.proportional === true;
                    el.visible = el.visible !== false; // Default to true
                    el.bold = el.bold === true;
                    el.showText = el.showText !== false;

                    // Ensure numeric values for position and size (convert from string if needed)
                    el.x = parseFloat(el.x) || 0;
                    el.y = parseFloat(el.y) || 0;
                    el.width = parseFloat(el.width) || 30;
                    el.height = parseFloat(el.height) || 10;
                    el.fontSize = parseInt(el.fontSize) || 10;

                    // Ensure string values
                    if (el.align && typeof el.align !== 'string') {
                        el.align = String(el.align);
                    }

                    // Ensure barcode/QR/image type properties exist
                    if (el.type === 'barcode') {
                        el.barcodeType = el.barcodeType || 'C128';
                    }
                    if (el.type === 'qr') {
                        el.qrType = el.qrType || 'QRCODE,H';
                    }
                    if (el.type === 'image') {
                        el.imageDataSource = el.imageDataSource || 'custom';
                    }
                    if (!el.dataSource) {
                        el.dataSource = el.type === 'barcode' ? 'product_sku' : (el.type === 'qr' ? 'product_link' : 'product_name');
                    }
                });
            } else {
                layout = [];
            }
        } else {
            layout = [];
        }

        // Ensure measurement unit is always set (fallback if svld_params is missing)
        if (!currentUnit || !UNIT_CONVERSIONS[currentUnit]) {
            currentUnit = 'mm';
            unitToMmFactor = 1.0;
            unitLabel = 'mm';
        }
    } catch (error) {
        layout = [];
        settings = {};
        // isPro is already true, no need to reset
        // Ensure measurement unit is set even on error
        currentUnit = 'mm';
        unitToMmFactor = 1.0;
        unitLabel = 'mm';
    }
    syncElementCounter(); // ensure new elements never get IDs that collide with loaded ones
    let labelW         = settings.label_width  || 100;
    let labelH         = settings.label_height || 50;
    let selectedId     = null;
    let currentTemplateId = 'current';
    let isDragging     = false;
    let isResizing     = false;
    let dragOffset     = { x: 0, y: 0 };
    let resizeEl       = null;
    let resizeStart    = {};
    let canvasZoom     = 1; // CSS transform scale applied to #svld-canvas

    // ---- Multi-select state ----
    let multiSelected  = new Set(); // IDs of all currently selected elements

    // ---- Rubber-band state ----
    let isRubberBanding = false;
    let rubberStart     = { x: 0, y: 0 };

    // ---- Toolbar toggles ----
    let showGrid    = false;
    let snapEnabled = false;
    let showBounds  = false;

    // ---- Space / middle-mouse pan state ----
    let spacePressed = false;
    let isPanning    = false;
    let panStart     = {};

    // ---- Rubber-band selection state ----
    let justFinishedRubberBand = false; // Flag to prevent deselect after rubber-band

    // ---- Undo/Redo state ----
    let historyStack = [];
    let historyIndex = -1;
    let maxHistorySize = 50;
    let isUndoRedoAction = false;

    // =========================================================================
    // Init
    // =========================================================================
    let initialized = false;

    function initDesigner() {
        if (initialized) return;
        initialized = true;

        // Update all unit labels in the UI
        updateUnitLabels();

        // Draw rulers with current unit
        drawRulers();

        // Initialize label size inputs with values in current unit
        $('#svld-label-width').val(mmToDisplayUnit(labelW));
        $('#svld-label-height').val(mmToDisplayUnit(labelH));

        renderCanvas();
        syncElementPanel();
        setupEventHandlers();
        initToolbarHandlers();
        setTimeout(fitCanvasToWrapper, 50);
        initDragDrop();
        initKeyboardNudge();
        loadTemplatesList();
        initHistory();
        drawRulers(); // Ensure rulers are drawn on initial load
        initCollapsiblePanels();
        initFloatingMode();
        initQuickProperties();

        // --- Free tier canvas restrictions ---
        if (!isPro) {
            // 1. Disable "Add Element" buttons in panel
            document.querySelectorAll('.svld-add-element-btn').forEach(function(btn) {
                btn.disabled = true;
                btn.title = svld_params.pro_tooltip || '🔒 Pro feature — Upgrade to unlock';
                btn.style.opacity = '0.5';
                btn.style.cursor = 'not-allowed';
            });

            // 2. Add pro-locked class to element items
            document.querySelectorAll('.svld-element-item').forEach(function(item) {
                item.classList.add('svld-pro-locked');
            });

            // 3. Show free notice above canvas
            const upgradeUrl = (typeof svld_params !== 'undefined' && svld_params.upgrade_url)
                ? svld_params.upgrade_url : '#';
            const notice = document.createElement('div');
            notice.id = 'svld-free-notice';
            notice.style.cssText = 'padding:10px 14px;background:#eff6ff;border:1px solid #93c5fd;border-radius:6px;margin-bottom:12px;font-size:13px;color:#1e40af;';
            notice.innerHTML = '<strong>Free version</strong> — You can move and resize elements. <a href="' + upgradeUrl + '" target="_blank">Upgrade to Pro</a> to add elements, save templates, and unlock all features.';
            const canvasArea = document.getElementById('svld-canvas-area');
            if (canvasArea) canvasArea.prepend(notice);

            // 4. Hide "Save as Template" button
            const saveTemplateBtn = document.getElementById('svld-save-template');
            if (saveTemplateBtn) saveTemplateBtn.remove();

            // 5. Hide template selector bar
            const templateSelect = document.getElementById('svld-template-select');
            if (templateSelect) {
                const templateSection = templateSelect.closest('.svld-template-section');
                if (templateSection) templateSection.remove();
            }

            // 6. Block Delete/Backspace key from deleting elements (use tooltip instead of alert)
            document.addEventListener('keydown', function(e) {
                if ((e.key === 'Delete' || e.key === 'Backspace') && selectedId) {
                    const tag = document.activeElement ? document.activeElement.tagName : '';
                    if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return;
                    e.preventDefault();
                    // Show tooltip near the selected element
                    const $selectedEl = $('.svld-el[data-id="' + selectedId + '"]');
                    if ($selectedEl.length) {
                        showProTooltip($selectedEl);
                    }
                }
            });

            // 7. Add visual disabled state to Clear button
            const clearBtn = document.getElementById('svld-reset-layout');
            if (clearBtn) {
                clearBtn.title = svld_params.pro_tooltip || '🔒 Pro feature — Upgrade to unlock';
            }

            // 8. Add visual disabled state to Preset button
            const presetBtn = document.getElementById('svld-new-preset');
            if (presetBtn) {
                presetBtn.title = svld_params.pro_tooltip || '🔒 Pro feature — Upgrade to unlock';
                presetBtn.style.opacity = '0.6';
                presetBtn.style.cursor = 'not-allowed';
            }

            // 9. Add visual disabled state to duplicate/remove buttons in properties panel
            const duplicateBtn = document.getElementById('svld-prop-duplicate');
            const removeBtn = document.getElementById('svld-prop-remove');
            if (duplicateBtn) {
                duplicateBtn.title = svld_params.pro_tooltip || '🔒 Pro feature — Upgrade to unlock';
                duplicateBtn.style.opacity = '0.6';
                duplicateBtn.style.cursor = 'not-allowed';
            }
            if (removeBtn) {
                removeBtn.title = svld_params.pro_tooltip || '🔒 Pro feature — Upgrade to unlock';
                removeBtn.style.opacity = '0.6';
                removeBtn.style.cursor = 'not-allowed';
            }
        }
        // --- End free tier restrictions ---
    }

    // =========================================================================
    // Collapsible Panels (for small screens)
    // =========================================================================
    function initCollapsiblePanels() {
        const storageKey = 'svld_collapsed_panels';

        // Load saved state from localStorage
        let collapsedPanels = JSON.parse(localStorage.getItem(storageKey) || '{}');

        // Add collapse buttons to panel titles (excluding canvas panel)
        $('.svld-panel-title').each(function() {
            const $title = $(this);
            const $panel = $title.closest('.svld-panel');
            const panelMatch = $panel.attr('class').match(/svld-\w+-panel/);
            const panelId = panelMatch ? panelMatch[0] : null;

            if (!panelId || $panel.hasClass('svld-canvas-panel')) return;

            // Add collapse button if not already present
            if (!$title.find('.svld-panel-collapse').length) {
                const $collapseBtn = $('<button class="svld-panel-collapse" type="button" aria-label="Toggle panel">')
                    .html('<span class="dashicons dashicons-arrow-up-alt2"></span>');
                $title.append($collapseBtn);

                // Wrap the rest of the panel content (excluding the title itself)
                const $content = $panel.children().not($title);
                if ($content.length && !$content.parent().hasClass('svld-panel-content')) {
                    $content.wrapAll('<div class="svld-panel-content">');
                }

                // Apply saved state
                if (collapsedPanels[panelId]) {
                    $panel.addClass('svld-panel-collapsed');
                }
            }
        });

        // Handle collapse button clicks
        $(document).on('click', '.svld-panel-collapse', function(e) {
            e.preventDefault();
            const $btn = $(this);
            const $panel = $btn.closest('.svld-panel');
            const panelMatch = $panel.attr('class').match(/svld-\w+-panel/);
            const panelId = panelMatch ? panelMatch[0] : null;

            if (!panelId) return;

            $panel.toggleClass('svld-panel-collapsed');

            // Update localStorage
            collapsedPanels[panelId] = $panel.hasClass('svld-panel-collapsed');
            localStorage.setItem(storageKey, JSON.stringify(collapsedPanels));
        });

        // Auto-collapse panels on small screens
        function checkScreenSize() {
            if (window.innerWidth <= 782) {
                // On mobile, collapse all panels by default (except canvas)
                $('.svld-panel').not('.svld-canvas-panel').addClass('svld-panel-collapsed');
            } else {
                // On desktop, restore saved state
                Object.keys(collapsedPanels).forEach(function(panelId) {
                    const $panel = $('.' + panelId);
                    if (collapsedPanels[panelId]) {
                        $panel.addClass('svld-panel-collapsed');
                    } else {
                        $panel.removeClass('svld-panel-collapsed');
                    }
                });
            }
        }

        // Run on load and debounced resize
        let resizeTimer;
        $(window).on('resize', function() {
            clearTimeout(resizeTimer);
            resizeTimer = setTimeout(checkScreenSize, 150);
        });

        // Initial check
        checkScreenSize();
    }

    // =========================================================================
    // Floating Mode — Maximum Canvas Space
    // =========================================================================
    function initFloatingMode() {
        // Add floating mode toggle button
        if (!$('.svld-toggle-float-mode').length) {
            $('<button class="svld-toggle-float-mode" title="Toggle floating panels mode">' +
                '<span class="dashicons dashicons-editor-expand"></span></button>')
                .appendTo('.svld-designer-wrap');
        }

        // Add panel triggers
        if (!$('.svld-panel-trigger-left').length) {
            $('<button class="svld-panel-trigger svld-panel-trigger-left">Elements</button>')
                .appendTo('.svld-designer-wrap');
            $('<button class="svld-panel-trigger svld-panel-trigger-right">Properties</button>')
                .appendTo('.svld-designer-wrap');
        }

        // Add pin buttons to panels
        $('.svld-elements-panel .svld-panel-title, .svld-properties-panel .svld-panel-title').each(function() {
            if (!$(this).find('.svld-panel-pin').length) {
                $(this).append('<button class="svld-panel-pin" title="Pin panel open">' +
                    '<span class="dashicons dashicons-admin-post"></span></button>');
            }
        });

        // Toggle floating mode
        $(document).off('click', '.svld-toggle-float-mode').on('click', '.svld-toggle-float-mode', function() {
            $('body').toggleClass('svld-floating-mode');
            const isFloating = $('body').hasClass('svld-floating-mode');
            localStorage.setItem('svld_floating_mode', isFloating);

            // Update icon
            $(this).find('.dashicons')
                .toggleClass('dashicons-editor-expand', !isFloating)
                .toggleClass('dashicons-editor-contract', isFloating);

            setTimeout(fitCanvasToWrapper, 100);
        });

        // Panel triggers show panels
        $(document).off('click', '.svld-panel-trigger-left').on('click', '.svld-panel-trigger-left', function() {
            $('.svld-elements-panel').addClass('svld-panel-pinned');
            setTimeout(() => $('.svld-elements-panel').removeClass('svld-panel-pinned'), 3000);
        });

        $(document).off('click', '.svld-panel-trigger-right').on('click', '.svld-panel-trigger-right', function() {
            $('.svld-properties-panel').addClass('svld-panel-pinned');
        });

        // Pin buttons
        $(document).off('click', '.svld-panel-pin').on('click', '.svld-panel-pin', function(e) {
            e.stopPropagation();
            $(this).toggleClass('pinned');
            $(this).closest('.svld-panel').toggleClass('svld-panel-pinned');
        });

        // Show properties panel when element is selected
        $(document).on('svld:element-selected', function() {
            if ($('body').hasClass('svld-floating-mode')) {
                $('.svld-properties-panel').addClass('svld-panel-active');
            }
        });

        $(document).on('svld:element-deselected', function() {
            $('.svld-properties-panel').removeClass('svld-panel-active');
        });

        // Restore floating mode from localStorage
        if (localStorage.getItem('svld_floating_mode') === 'true') {
            $('body').addClass('svld-floating-mode');
            $('.svld-toggle-float-mode').find('.dashicons')
                .removeClass('dashicons-editor-expand')
                .addClass('dashicons-editor-contract');
        }

        // Auto-enable floating mode on small screens
        if (window.innerWidth <= 1200 && localStorage.getItem('svld_floating_mode') === null) {
            $('body').addClass('svld-floating-mode');
            $('.svld-toggle-float-mode').find('.dashicons')
                .removeClass('dashicons-editor-expand')
                .addClass('dashicons-editor-contract');
        }
    }

    // =========================================================================
    // Double-click to show Properties panel
    // =========================================================================
    function initQuickProperties() {
        // Double-click on element shows Properties panel
        $(document).off('dblclick', '.svld-el').on('dblclick', '.svld-el', function(e) {
            e.stopPropagation();
            const id = $(this).data('id');
            if (!id) return;

            selectElement(id);

            // Show and pin the Properties panel
            $('.svld-properties-panel').addClass('svld-panel-pinned svld-panel-active');
        });
    }

    // Update all unit labels in the UI based on current unit setting
    function updateUnitLabels() {
        // Validate currentUnit and get label with fallback
        // Sanitize currentUnit to prevent any corrupted values from localStorage
        if (!UNIT_LABELS[currentUnit]) {
            console.warn('Invalid measurement unit:', currentUnit, '- falling back to mm');
            currentUnit = 'mm';
            unitToMmFactor = UNIT_CONVERSIONS['mm'];
            localStorage.setItem('svld_measurement_unit', 'mm');
        }
        const label = UNIT_LABELS[currentUnit] || 'mm';
        $('.svld-unit-label').text(label);

        // Update preset dropdown labels to show sizes in current unit
        // Store original values in data attributes to prevent accumulation
        $('#svld-size-preset option').each(function() {
            const $opt = $(this);
            const w = $opt.data('w');
            const h = $opt.data('h');
            let desc = $opt.data('desc') || '';
            // Clean description - remove parentheses and trim
            desc = desc.replace(/[\(\)]/g, '').trim();
            if (w && h) {
                const dw = mmToDisplayUnit(w).toFixed(0);
                const dh = mmToDisplayUnit(h).toFixed(0);
                // Build clean text - dimensions, unit, then optional description
                let text = dw + '×' + dh + ' ' + label;
                if (desc) {
                    text += ' - ' + desc;
                }
                $opt.text(text);
            }
        });

        // Update dimension input fields to show current canvas size (always in mm for inputs)
        $('#svld-label-width').val(labelW.toFixed(0));
        $('#svld-label-height').val(labelH.toFixed(0));
    }

    // Initialize when DOM is ready
    jQuery(document).ready(initDesigner);

    // =========================================================================
    // Render canvas from layout array
    // =========================================================================
    function renderCanvas() {
        const $canvas = $('#svld-canvas');
        if (!$canvas.length) return;

        $canvas.find('.svld-el').remove();
        $canvas.find('.svld-canvas-placeholder').toggle(layout.length === 0);

        // Render elements in array order, but use their independent zIndex property
        layout.forEach(function (el, index) {
            if (!el.visible) return;
            const $el = buildElement(el);
            // Use element's zIndex property, default to array position + 1 if not set
            const zIndex = (el.zIndex !== undefined) ? el.zIndex : (index + 1);
            $el.css('z-index', zIndex);
            $canvas.append($el);
        });

        if (selectedId) {
            $canvas.find('[data-id="' + selectedId + '"]').addClass('svld-selected');
            // Note: we DON'T change z-index on select - element stays in its layer
        }

        renderLayersList();
    }

    function buildElement(el) {
        const x = mmToPx(el.x);
        const y = mmToPx(el.y);
        const w = mmToPx(el.width);
        const h = mmToPx(el.height);

        let $el = $('<div>', {
            'class':    'svld-el svld-el-' + el.type,
            'data-id':  el.id,
            'data-type': el.type,
            'data-source': el.dataSource || '', // Add data-source for CSS targeting
        }).css({
            left:   x + 'px',
            top:    y + 'px',
            width:  w + 'px',
            height: h + 'px',
        });

        switch (el.type) {
            case 'title':
            case 'sku':
            case 'price':
            case 'text':
            case 'website':
                let fontSize = el.fontSize || 10;
                const text = getElementText(el);

                // Add a content wrapper div to handle overflow while keeping resize handle visible
                const $content = $('<div class="svld-el-content">');

                // Auto-scale font size if "Fit to Width" is enabled
                if (el.fitWidth) {
                    const maxWidthPx = Math.max(10, w - 4);
                    const maxHeightPx = Math.max(10, h - 4);

                    if (el.multiLine) {
                        // Multi-line mode: calculate font size to fit both width and height
                        // Use off-screen container that's completely isolated from layout
                        let $measureContainer = $('#svld-text-measure-container');
                        if (!$measureContainer.length) {
                            $measureContainer = $('<div id="svld-text-measure-container">').css({
                                position: 'absolute',
                                left: '0',
                                top: '0',
                                visibility: 'hidden',
                                pointerEvents: 'none',
                                zIndex: '-9999',
                                position: 'fixed',
                                left: '-10000px',
                                top: '-10000px',
                                width: '1px',
                                height: '1px',
                                overflow: 'hidden'
                            }).appendTo('#svld-canvas-scale-host');
                        }

                        const $temp = $('<div>').css({
                            whiteSpace: 'pre-wrap',
                            wordBreak: 'break-word',
                            overflowWrap: 'break-word',
                            fontFamily: 'Arial, sans-serif',
                            fontWeight: el.bold ? 'bold' : 'normal',
                            fontSize: fontSize + 'pt',
                            width: maxWidthPx + 'px',
                            lineHeight: '1.2',
                            padding: '2px',
                            position: 'absolute',
                            visibility: 'hidden'
                        }).text(text).appendTo($measureContainer);

                        const tempHeight = $temp[0].getBoundingClientRect().height;
                        $temp.remove();

                        if (tempHeight > maxHeightPx) {
                            const scale = maxHeightPx / tempHeight;
                            const elementSizePx = Math.min(maxWidthPx, maxHeightPx);
                            const minFontSize = Math.max(1, Math.floor(elementSizePx / 8));
                            fontSize = Math.max(minFontSize, Math.floor(fontSize * scale));
                        }

                        $content.css({
                            fontSize: fontSize + 'pt',
                            fontWeight: el.bold ? 'bold' : 'normal',
                            justifyContent: el.align === 'center' ? 'center' : (el.align === 'right' ? 'flex-end' : 'flex-start'),
                            alignItems: el.align === 'center' ? 'center' : (el.align === 'right' ? 'flex-end' : 'flex-start'),
                            textAlign: el.align,
                            fontFamily: 'Arial, sans-serif',
                            whiteSpace: 'pre-wrap',
                            wordBreak: 'break-word',
                            overflowWrap: 'break-word',
                            lineHeight: '1.2',
                            padding: '2px',
                            overflow: 'hidden',
                            display: 'flex',
                            flexDirection: 'column',
                            width: '100%',
                            height: '100%',
                        });
                    } else {
                        // Single-line mode: only fit to width
                        // Use off-screen container that's completely isolated from layout
                        let $measureContainer = $('#svld-text-measure-container');
                        if (!$measureContainer.length) {
                            $measureContainer = $('<div id="svld-text-measure-container">').css({
                                position: 'absolute',
                                left: '0',
                                top: '0',
                                visibility: 'hidden',
                                pointerEvents: 'none',
                                zIndex: '-9999',
                                position: 'fixed',
                                left: '-10000px',
                                top: '-10000px',
                                width: '1px',
                                height: '1px',
                                overflow: 'hidden'
                            }).appendTo('#svld-canvas-scale-host');
                        }

                        const $temp = $('<div>').css({
                            whiteSpace: 'nowrap',
                            fontFamily: 'Arial, sans-serif',
                            fontWeight: el.bold ? 'bold' : 'normal',
                            fontSize: fontSize + 'pt',
                            position: 'absolute',
                            visibility: 'hidden'
                        }).text(text).appendTo($measureContainer);

                        const textWidth = $temp[0].getBoundingClientRect().width;
                        $temp.remove();

                        if (textWidth > maxWidthPx) {
                            const scale = maxWidthPx / textWidth;
                            const minFontSize = Math.max(1, Math.floor(w / 10));
                            fontSize = Math.max(minFontSize, Math.floor(fontSize * scale));
                        }

                        $content.css({
                            fontSize: fontSize + 'pt',
                            fontWeight: el.bold ? 'bold' : 'normal',
                            justifyContent: el.align === 'center' ? 'center' : (el.align === 'right' ? 'flex-end' : 'flex-start'),
                            fontFamily: 'Arial, sans-serif',
                            whiteSpace: 'nowrap',
                            overflow: 'hidden',
                            width: '100%',
                            height: '100%',
                        });
                    }
                } else {
                    $content.css({
                        fontSize: fontSize + 'pt',
                        fontWeight: el.bold ? 'bold' : 'normal',
                        justifyContent: el.align === 'center' ? 'center' : (el.align === 'right' ? 'flex-end' : 'flex-start'),
                        fontFamily: 'Arial, sans-serif',
                        whiteSpace: el.multiLine ? 'normal' : 'nowrap',
                        overflow: 'hidden',
                        width: '100%',
                        height: '100%',
                    });
                }
                // Invoice data source returns HTML — use .html(); all others use .text() for XSS safety
                if ((el.dataSource || el.type) === 'order_invoice_full') {
                    $content.html(text);
                } else {
                    $content.text(text);
                }
                $el.append($content);
                break;

            case 'barcode':
                $el.addClass('svld-el-barcode').html(buildBarcodeHtml(el));
                break;

            case 'qr':
                $el.addClass('svld-el-qr').html(buildQrHtml(el));
                break;

            case 'image':
                $el.addClass('svld-el-image');
                let imgSrc = el.imageUrl || el.customText || 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="100" height="100"%3E%3Crect width="100" height="100" fill="%23e2e8f0"/%3E%3Ctext x="50" y="55" text-anchor="middle" font-size="12" fill="%2394a3b8"%3EImage%3C/text%3E%3C/svg%3E';

                // If image data source is product_image, use placeholder in preview
                // (actual product image will be fetched in PDF renderer)
                if (el.imageDataSource === 'product_image') {
                    imgSrc = 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="200" height="200"%3E%3Crect width="200" height="200" fill="%23e2e8f0"/%3E%3Ctext x="100" y="105" text-anchor="middle" font-size="14" fill="%2394a3b8"%3EProduct Image%3C/text%3E%3C/svg%3E';
                }

                // For "Fit to Width", image fills the element dimensions
                const imgStyle = el.fitWidth
                    ? 'width:100%;height:100%;object-fit:contain;'
                    : 'max-width:100%;max-height:100%;object-fit:contain;';
                $el.html('<img src="' + imgSrc + '" style="' + imgStyle + '" />');
                break;
        }

        $el.append('<div class="svld-el-resize"></div>');

        return $el;
    }

    function getElementText(el) {
        // Get text based on data source
        const dataSource = el.dataSource || el.type;

        switch (dataSource) {
            // Product Data
            case 'product_name': return 'Product Name';
            case 'product_id': return 'ID: 1234';
            case 'product_sku': return 'SKU: ABC-123';
            case 'product_price': return '29.99 MAD';
            case 'product_link': return 'View Product';
            case 'product_image': return '[Product Image]';

            // Product Attributes
            case 'product_stock': return '15';
            case 'product_weight': return '1.5 kg';
            case 'product_length': return '20 cm';
            case 'product_width': return '15 cm';
            case 'product_height': return '10 cm';
            case 'product_dimensions': return '20 x 15 x 10 cm';
            case 'product_categories': return 'Clothing, Men';
            case 'product_tags': return 'New, Summer, Sale';
            case 'product_short_description': return 'A great product for...';
            case 'product_total_sales': return '42';

            // Order Data
            case 'order_number': return '#12345';
            case 'order_date': return '2024-01-15';
            case 'order_total': return '170.00 MAD';
            case 'order_subtotal': return '150.00 MAD';
            case 'order_tax': return '20.00 MAD';
            case 'order_shipping_cost': return '10.00 MAD';
            case 'order_discount': return '0.00 MAD';
            case 'order_status': return 'Processing';
            case 'order_item_count': return '3';
            case 'order_items_list': return 'Product A ×2, Product B ×1';
            case 'order_items_table': {
                const showQty   = el.showItemQty   !== false;
                const showPrice = el.showItemPrice !== false;
                const showImage = el.showItemImage === true;
                const cols = [showImage ? '[IMG]' : '', 'Product', showQty ? 'Qty' : '', showPrice ? 'Price' : ''].filter(Boolean);
                const header = cols.join('   ');
                const sep    = '-'.repeat(header.length + 10);
                const row1   = [showImage ? '[IMG]' : '', 'Product A', showQty ? 'x2' : '', showPrice ? '100.00 MAD' : ''].filter(Boolean).join('   ');
                const row2   = [showImage ? '[IMG]' : '', 'Product B', showQty ? 'x1' : '', showPrice ? '50.00 MAD' : ''].filter(Boolean).join('   ');
                const total  = ['', 'Total', '', showPrice ? '150.00 MAD' : ''].filter(Boolean).join('   ');
                return [header, sep, row1, row2, sep, total].join('\n');
            }

            case 'order_invoice_table': {
                const showSubtotal  = el.showSubtotal  !== false;
                const showTax       = el.showTax       !== false;
                const showShipping  = el.showShipping  !== false;
                const showTotal     = el.showTotal     !== false;
                const showPayment   = el.showPayment   === true;
                const showShippingVia = el.showShippingVia === true;

                const lines = [];
                if (showSubtotal) lines.push('Subtotal:      100.00 MAD');
                if (showTax) lines.push('Tax:             20.00 MAD');
                if (showShipping) lines.push('Shipping:       15.00 MAD');
                if (showTotal) {
                    lines.push('---------------------');
                    lines.push('TOTAL:          135.00 MAD');
                }
                if (showPayment) lines.push('\nPayment:        Cash on Delivery');
                if (showShippingVia) lines.push('Shipping via:   Flat Rate');
                return lines.join('\n');
            }

            case 'order_invoice_full': {
                // Items table — rendered as HTML for canvas preview
                const showImage       = el.showItemImage === true;
                const showQty         = el.showItemQty   !== false;
                const showPrice       = el.showItemPrice !== false;
                const showDiscount    = el.showDiscount  === true;
                const showSubtotal    = el.showSubtotal  !== false;
                const showTax         = el.showTax       !== false;
                const showShipping    = el.showShipping  !== false;
                const showTotal       = el.showTotal     !== false;
                const showPayment     = el.showPayment   === true;
                const showShippingVia = el.showShippingVia === true;

                const fs = (el.fontSize || 7) + 'pt';
                const tdStyle = 'border:1px solid #ccc;padding:1px 3px;white-space:nowrap;';
                const thStyle = 'border:1px solid #ccc;padding:1px 3px;background:#f0f0f0;font-weight:bold;white-space:nowrap;';

                let cols = '';
                if (showImage) cols += '<th style="' + thStyle + '">Img</th>';
                cols += '<th style="' + thStyle + 'width:40%">Product</th>';
                if (showQty)   cols += '<th style="' + thStyle + 'text-align:center">Qty</th>';
                if (showPrice) cols += '<th style="' + thStyle + 'text-align:right">Price</th>';
                cols += '<th style="' + thStyle + 'text-align:right">Total</th>';

                const items = [
                    {name: 'Product A', qty: 'x2', price: '100.00', discount: '10.00', total: '190.00 MAD'},
                    {name: 'Product B', qty: 'x1', price: '50.00',  discount: '',      total: '50.00 MAD'},
                ];

                let rows = '';
                items.forEach(item => {
                    let r = '<tr>';
                    if (showImage) r += '<td style="' + tdStyle + '">&#128247;</td>';
                    r += '<td style="' + tdStyle + '">' + item.name + '</td>';
                    if (showQty)   r += '<td style="' + tdStyle + 'text-align:center">' + item.qty + '</td>';
                    if (showPrice) r += '<td style="' + tdStyle + 'text-align:right">' + item.price + '</td>';
                    r += '<td style="' + tdStyle + 'text-align:right">' + item.total + '</td>';
                    r += '</tr>';
                    rows += r;
                    if (showDiscount && item.discount) {
                        const span = (showImage ? 1 : 0) + 1 + (showQty ? 1 : 0);
                        rows += '<tr><td colspan="' + span + '" style="border:none"></td>'
                              + (showPrice ? '<td style="' + tdStyle + 'text-align:right;color:#c00">-' + item.discount + '</td>' : '')
                              + '<td style="' + tdStyle + 'text-align:right"></td></tr>';
                    }
                });

                let totalsHtml = '<table style="width:100%;border-collapse:collapse;margin-top:3px;font-size:' + fs + '">';
                if (showSubtotal)  totalsHtml += '<tr><td style="padding:1px 2px">Subtotal</td><td style="padding:1px 2px;text-align:right">250.00 MAD</td></tr>';
                if (showTax)       totalsHtml += '<tr><td style="padding:1px 2px">Tax</td><td style="padding:1px 2px;text-align:right">30.00 MAD</td></tr>';
                if (showShipping)  totalsHtml += '<tr><td style="padding:1px 2px">Shipping</td><td style="padding:1px 2px;text-align:right">15.00 MAD</td></tr>';
                if (showDiscount)  totalsHtml += '<tr><td style="padding:1px 2px;color:#c00"></td><td style="padding:1px 2px;text-align:right;color:#c00">-10.00 MAD</td></tr>';
                if (showTotal)     totalsHtml += '<tr style="border-top:2px solid #333"><td style="padding:1px 2px;font-weight:bold">TOTAL</td><td style="padding:1px 2px;text-align:right;font-weight:bold">185.00 MAD</td></tr>';
                if (showPayment)   totalsHtml += '<tr><td colspan="2" style="padding:2px 2px;font-size:90%">Payment: Cash on Delivery</td></tr>';
                if (showShippingVia) totalsHtml += '<tr><td colspan="2" style="padding:1px 2px;font-size:90%">Shipping: Flat Rate</td></tr>';
                totalsHtml += '</table>';

                const dir = el.textDirection || 'ltr';
                return '<div style="font-size:' + fs + ';font-family:Arial,sans-serif;width:100%;height:100%;overflow:hidden;direction:' + dir + '">'
                     + '<table style="width:100%;border-collapse:collapse;font-size:' + fs + '">'
                     + '<thead><tr>' + cols + '</tr></thead>'
                     + '<tbody>' + rows + '</tbody>'
                     + '</table>'
                     + totalsHtml
                     + '</div>';
            }

            // Customer
            case 'customer_name':
            case 'customer_full_name': return 'John Doe';
            case 'customer_first_name': return 'John';
            case 'customer_last_name': return 'Doe';
            case 'customer_email': return 'john@example.com';
            case 'customer_phone': return '+212 600 000 000';
            case 'customer_company': return 'ACME Corp';

            // Addresses
            case 'shipping_address':
            case 'billing_address': return '123 Main St, City, Country';
            case 'billing_address_1':
            case 'shipping_address_1': return '123 Main St';
            case 'billing_city':
            case 'shipping_city': return 'Casablanca';
            case 'billing_postcode':
            case 'shipping_postcode': return '20000';
            case 'billing_country':
            case 'shipping_country': return 'Morocco';

            // Payment
            case 'payment_method': return 'Cash on Delivery';
            case 'shipping_method': return 'Flat Rate';

            // Shop Info
            case 'shop_name': return svld_params.site_url ? new URL(svld_params.site_url).hostname : 'My Shop';
            case 'shop_email': return 'shop@example.com';
            case 'shop_phone': return '+212 500 000 000';
            case 'shop_address': return '1 Commerce St';
            case 'shop_city': return 'Casablanca';
            case 'shop_postcode': return '20000';
            case 'shop_country': return 'Morocco';

            // Other
            case 'site_url':
                const site = new URL(svld_params.site_url).hostname;
                return site;
            case 'current_date':
                return new Date().toLocaleDateString();
            case 'custom':
                return el.customText || 'Custom Text';
            default:
                if (el.type === 'title') return 'Product Name';
                if (el.type === 'sku') return 'SKU: ABC-123';
                if (el.type === 'price') return '29.99 MAD';
                if (el.type === 'text') return 'Custom Text';
                if (el.type === 'website') return new URL(svld_params.site_url).hostname;
                return dataSource;
        }
    }

    function buildBarcodeHtml(el) {
        const bars = [3,1,2,1,3,2,1,1,3,1,2,3,1,2,1,1,2,3,1,1,3,2,1,2];
        let html = '<div class="svld-barcode-bars" style="';
        if (el.fitWidth) {
            html += 'width:100%;height:100%;';
        }
        html += '">';
        bars.forEach(function (w, i) {
            html += '<span style="flex:' + w + ';background:' + (i % 2 === 0 ? '#000' : '#fff') + ';"></span>';
        });
        html += '</div>';
        if (el.showText !== false) {
            const text = el.customText || (el.dataSource === 'product_sku' ? 'SKU-ABC123' : '123456789012');
            html += '<div class="svld-barcode-text">' + text + '</div>';
        }
        return html;
    }

    function buildQrHtml(el) {
        const size = Math.round(mmToPx(el.width)) - 8;
        const cells = [
            1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,
            1,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0,1,
            1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,
            1,0,1,1,1,0,1,0,0,1,0,0,1,0,1,1,1,0,1,
            1,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,
            1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,
            0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,
            1,1,0,1,1,0,1,0,0,1,0,1,0,1,0,1,1,0,1,
            0,1,1,0,0,1,0,1,1,0,1,0,1,0,0,1,0,1,0,
        ];
        const cols = 19;

        let qrStyle = 'display:grid;grid-template-columns:repeat(' + cols + ',1fr);';
        if (el.fitWidth) {
            // Make QR fill the entire element when "Fit to Width" is enabled
            qrStyle += 'width:100%;height:100%;padding:4px;box-sizing:border-box;';
        } else {
            qrStyle += 'width:' + size + 'px;height:' + size + 'px;';
        }

        let html = '<div style="' + qrStyle + '">';
        cells.forEach(function (c) {
            html += '<div style="background:' + (c ? '#000' : '#fff') + ';"></div>';
        });
        html += '</div>';
        return html;
    }

    // =========================================================================
    // Sync elements panel
    // =========================================================================
    function syncElementPanel() {
        // Get all element types currently on canvas
        const existingTypes = new Set();
        layout.forEach(function(el) {
            if (el.type) {
                existingTypes.add(el.type);
            }
        });

        // Enable/disable element buttons based on what's already on canvas
        $('.svld-element-item').each(function() {
            const $item = $(this);
            const type = $item.data('type');
            const $btn = $item.find('.svld-add-element-btn');

            if (existingTypes.has(type)) {
                // Element type already exists on canvas - disable it
                $item.addClass('svld-element-type-exists');
                $btn.prop('disabled', true).attr('title', type.charAt(0).toUpperCase() + type.slice(1) + ' already on canvas');
            } else {
                // Element type not on canvas - enable it
                $item.removeClass('svld-element-type-exists');
                $btn.prop('disabled', false).attr('title', 'Click to add at center');
            }
        });
    }

    // =========================================================================
    // Event handlers
    // =========================================================================
    function setupEventHandlers() {
        // Measurement unit dropdown handler (settings page)
        $('#svld_measurement_unit').on('change', function() {
            const newUnit = $(this).val();
            if (newUnit && UNIT_CONVERSIONS[newUnit]) {
                // Save to localStorage for immediate persistence
                localStorage.setItem('svld_measurement_unit', newUnit);
                console.log('Measurement unit changed to:', newUnit);
            }
        });

        // Drag and drop from sidebar to canvas
        let draggedElementType = null;

        // Drag start on element items
        $(document).on('dragstart', '.svld-draggable-element', function(e) {
            draggedElementType = $(this).data('type');
            e.originalEvent.dataTransfer.effectAllowed = 'copy';
            e.originalEvent.dataTransfer.setData('text/plain', draggedElementType);
            $(this).addClass('svld-dragging');
        });

        $(document).on('dragend', '.svld-draggable-element', function(e) {
            $(this).removeClass('svld-dragging');
            draggedElementType = null;
        });

        // Make canvas a drop target
        $('#svld-canvas').on('dragover', function(e) {
            e.preventDefault();
            e.originalEvent.dataTransfer.dropEffect = 'copy';
            $(this).addClass('svld-drag-over');
        });

        $('#svld-canvas').on('dragleave', function(e) {
            $(this).removeClass('svld-drag-over');
        });

        $('#svld-canvas').on('drop', function(e) {
            e.preventDefault();
            $(this).removeClass('svld-drag-over');

            const type = e.originalEvent.dataTransfer.getData('text/plain');
            if (type) {
                // Calculate drop position in canvas coordinates
                const canvasRect = this.getBoundingClientRect();
                const offsetX = (e.originalEvent.clientX - canvasRect.left) / canvasZoom;
                const offsetY = (e.originalEvent.clientY - canvasRect.top) / canvasZoom;

                // Convert to mm and add element at drop position
                const posX = pxToMm(offsetX);
                const posY = pxToMm(offsetY);

                addNewElement(type, posX, posY);
            }
        });

        // Make entire element row clickable (both div and button)
        $(document).on('click', '.svld-element-item, .svld-add-element-btn', function (e) {
            const $item = $(this).closest('.svld-element-item');

            // Pro check for adding elements
            if (!isPro) {
                e.preventDefault();
                e.stopPropagation();
                showProTooltip($item);
                return false;
            }

            if ($item.hasClass('svld-element-locked')) return;

            let type = $(this).attr('data-type');
            if (!type) type = $item.attr('data-type');

            if (type) addNewElement(type);
        });

        // Canvas element click → select
        $(document).on('click', '.svld-el', function (e) {
            e.stopPropagation();
            const id = $(this).data('id');

            if (e.shiftKey) {
                // Shift+Click: always use toggleMultiSelect for multi-selection
                toggleMultiSelect(id);
            } else {
                // Normal click: select only this element
                selectElement(id);
            }
        });

        // Deselect on canvas click (but not when clicking on elements)
        $('#svld-canvas').on('click', function (e) {
            // Don't deselect if a rubber-band selection just completed
            if (justFinishedRubberBand) {
                justFinishedRubberBand = false;
                return;
            }
            // Don't deselect if click was on an element (or its children)
            if ($(e.target).closest('.svld-el').length) {
                return;
            }
            // Don't deselect if click was on the scale-host background (grey zone outside canvas)
            if ($(e.target).is('#svld-canvas-scale-host') || $(e.target).closest('#svld-canvas-scale-host').is('#svld-canvas-scale-host')) {
                return;
            }
            deselectElement();
        });

        // Properties form changes - Apply button removed, all properties apply in real-time
        $('#svld-prop-duplicate').on('click', function() {
            if (!isPro) {
                showProTooltip($(this));
                return;
            }
            duplicateSelected();
        });
        $('#svld-prop-remove').on('click', function() {
            if (!isPro) {
                showProTooltip($(this));
                return;
            }
            removeSelected();
        });

        // Right-click context menu on canvas elements
        $(document).on('contextmenu', '.svld-el', function(e) {
            e.preventDefault();
            e.stopPropagation();
            const id = $(this).data('id');
            selectElement(id);
            showContextMenu(e.clientX, e.clientY, id);
        });

        // Close context menu on outside click / Escape
        $(document).on('click', hideContextMenu);
        $(document).on('keydown', function(e) { if (e.key === 'Escape') hideContextMenu(); });

        // Save layout button
        $('#svld-save-layout').on('click', saveLayout);

        // Clear canvas
        $('#svld-reset-layout').on('click', function () {
            // Pro check for clearing canvas
            if (!isPro) {
                showProTooltip($(this));
                return;
            }

            if (!confirm('Clear all elements from canvas? This cannot be undone.')) return;

            // Clear all elements
            layout = [];

            // Reset element counter
            elementCounter = 1000;

            // Re-render canvas (will show placeholder)
            renderCanvas();
            syncElementPanel();
            deselectElement();
        });

        // Canvas size apply — auto-fit after resize so label fills the viewport nicely
        $('#svld-apply-size').on('click', function () {
            labelW = displayUnitToMm(Math.max(20, parseInt($('#svld-label-width').val()) || 100));
            labelH = displayUnitToMm(Math.max(10, parseInt($('#svld-label-height').val()) || 50));
            fitCanvasToWrapper();
        });

        // Zoom controls — ±10% steps for fine control
        $('#svld-zoom-in').on('click', function () {
            canvasZoom = Math.min(+(canvasZoom + 0.1).toFixed(2), 4.0);
            updateCanvasSize();
        });
        $('#svld-zoom-out').on('click', function () {
            canvasZoom = Math.max(+(canvasZoom - 0.1).toFixed(2), 0.1);
            updateCanvasSize();
        });
        $('#svld-zoom-reset').on('click', function () {
            fitCanvasToWrapper(); // Fit to window instead of hard 100%
        });

        // Ctrl+scroll = zoom, plain scroll = pan (native browser scroll)
        $('.svld-canvas-wrapper').on('wheel', function (e) {
            if ( !e.originalEvent.ctrlKey && !e.originalEvent.metaKey ) return; // let browser scroll
            e.preventDefault();
            const delta = e.originalEvent.deltaY > 0 ? -0.1 : 0.1;
            canvasZoom = Math.max(0.1, Math.min(+(canvasZoom + delta).toFixed(2), 4.0));
            updateCanvasSize();
        });

        // Test print
        $('#svld-test-print').on('click', function () {
            const $btn = $(this);
            $btn.prop('disabled', true).text('Searching for product…');

            // First, search for any published product to use as sample
            $.post(svld_params.ajax_url, {
                action: 'svld_search_products',
                nonce: svld_params.nonce,
                term: '', // Empty search to get any products
            }, function(searchRes) {
                if (searchRes.success && searchRes.data && searchRes.data.length > 0) {
                    // Use the first product found
                    const sampleProduct = searchRes.data[0];
                    $btn.text('Generating PDF…');

                    $.post(svld_params.ajax_url, {
                        action: 'svld_test_print',
                        nonce: svld_params.nonce,
                        product_id: sampleProduct.id,
                        layout: JSON.stringify(layout),
                        label_width: labelW,
                        label_height: labelH,
                    }, function(res) {
                        $btn.prop('disabled', false).text('Test Print (Sample)');
                        if (res.success && res.data.pdf_url) {
                            window.open(res.data.pdf_url, '_blank');
                        } else {
                            alert('Error: ' + (res.data && res.data.message ? res.data.message : 'PDF generation failed'));
                        }
                    }).fail(function() {
                        $btn.prop('disabled', false).text('Test Print (Sample)');
                        alert('Server error. Please try again.');
                    });
                } else {
                    $btn.prop('disabled', false).text('Test Print (Sample)');
                    alert('No products found. Please create at least one product in WooCommerce before testing the print feature.');
                }
            }).fail(function() {
                $btn.prop('disabled', false).text('Test Print (Sample)');
                alert('Could not search for products. Please try again.');
            });
        });

        // Live property preview - all properties apply in real-time
        $('#svld-prop-visible, #svld-prop-font-size, #svld-prop-customtext, #svld-prop-imageurl, #svld-prop-fit-width, #svld-prop-multi-line, #svld-prop-proportional, #svld-prop-x, #svld-prop-y, #svld-prop-width, #svld-prop-height, #svld-prop-show-text, #svld-prop-barcode-type, #svld-prop-qr-type').on('change input', previewPropertyChange);

        // Text style buttons
        $('#svld-prop-bold').on('click', function() {
            if (!selectedId) return;
            const el = layout.find(e => e.id === selectedId);
            if (!el) return;
            el.bold = !el.bold;
            $(this).toggleClass('active', el.bold);
            previewPropertyChange();
            saveToHistory('Toggle Bold');
        });

        $('#svld-prop-italic').on('click', function() {
            if (!selectedId) return;
            const el = layout.find(e => e.id === selectedId);
            if (!el) return;
            el.italic = !el.italic;
            $(this).toggleClass('active', el.italic);
            previewPropertyChange();
            saveToHistory('Toggle Italic');
        });

        $('#svld-prop-underline').on('click', function() {
            if (!selectedId) return;
            const el = layout.find(e => e.id === selectedId);
            if (!el) return;
            el.underline = !el.underline;
            $(this).toggleClass('active', el.underline);
            previewPropertyChange();
            saveToHistory('Toggle Underline');
        });

        // Alignment buttons
        $('.svld-align-buttons .svld-style-btn').on('click', function() {
            if (!selectedId) return;
            const el = layout.find(e => e.id === selectedId);
            if (!el) return;
            const align = $(this).data('align');
            el.align = align;
            $('.svld-align-buttons .svld-style-btn').removeClass('active');
            $(this).addClass('active');
            previewPropertyChange();
            saveToHistory('Change Alignment');
        });

        // Show/hide multi-line option based on fit-width state AND text type
        $('#svld-prop-fit-width').on('change', function() {
            if (!selectedId) return;
            const el = layout.find(e => e.id === selectedId);
            if (!el) return;
            const isText = ['text', 'title', 'sku', 'price', 'website'].includes(el.type);
            $('#svld-prop-multi-line-group').toggle($(this).is(':checked') && isText);
        });

        // Data source change — update UI toggles AND immediately rebuild element preview
        $('#svld-prop-datasource').on('change', function() {
            const val = $(this).val();
            const isInv = val === 'order_invoice_full';
            $('.svld-customtext-props').toggle(val === 'custom');
            $('.svld-invoice-props').toggle(isInv);
            $('.svld-invoice-direction-props').toggle(isInv);
            // For invoice: hide regular text-style controls; show them otherwise
            $('.svld-text-props').toggle(!isInv);
            $('#svld-prop-fit-width-group').toggle(!isInv || true); // show for all text, including invoice
            $('#svld-prop-multi-line-group').hide(); // always hide on source change

            if (!selectedId) { previewPropertyChange(); return; }
            const el = layout.find(e => e.id === selectedId);
            if (!el) { previewPropertyChange(); return; }

            // Commit datasource to element immediately
            el.dataSource = val;

            // For text elements: rebuild the inner content directly so the preview
            // always reflects the new datasource without relying on cursor state.
            const $el = $('#svld-canvas [data-id="' + selectedId + '"]');
            if ($el.length && el.type === 'text') {
                const newText = getElementText(el);
                const $content = $el.find('.svld-el-content');
                if ($content.length) {
                    if (val === 'order_invoice_full') {
                        $content.html(newText);
                    } else {
                        $content.text(newText);
                    }
                }
                // Update data-source attribute so CSS rules re-apply correctly
                $el.attr('data-source', val);
            }

            // For barcode/QR: full re-render is handled by previewPropertyChange
            previewPropertyChange();
        });

        // Direction (RTL/LTR) toggle buttons for invoice elements
        $(document).on('click', '.svld-dir-btn', function() {
            if (!selectedId) return;
            const el = layout.find(e => e.id === selectedId);
            if (!el) return;
            const newDir = $(this).data('dir');
            el.textDirection = newDir;
            $('.svld-dir-btn').removeClass('active');
            $(this).addClass('active');
            previewPropertyChange();
            saveToHistory('Change Text Direction');
        });

        // Image data source change
        $('#svld-prop-image-datasource').on('change', function() {
            if (!selectedId) return;
            const el = layout.find(e => e.id === selectedId);
            if (!el) return;

            // CRITICAL: Store current position BEFORE any changes
            const preservedPosition = {
                x: el.x,
                y: el.y,
                width: el.width,
                height: el.height
            };

            // Update data source
            const newSource = $(this).val();
            el.imageDataSource = newSource;

            // Handle URL field visibility
            if (newSource === 'product_image' || newSource === 'shop_logo') {
                // Hide URL input, clear URL value
                $('.svld-image-url-props').hide();
                $('.svld-product-image-props').show();
                // Don't clear imageUrl - keep it in case user switches back
            } else {
                // Show URL input for custom
                $('.svld-image-url-props').show();
                $('.svld-product-image-props').hide();
            }

            // CRITICAL: Restore position after change
            el.x = preservedPosition.x;
            el.y = preservedPosition.y;
            el.width = preservedPosition.width;
            el.height = preservedPosition.height;

            // Update canvas element position explicitly
            const $el = $('#svld-canvas [data-id="' + selectedId + '"]');
            $el.css({
                left: mmToPx(el.x) + 'px',
                top: mmToPx(el.y) + 'px',
                width: mmToPx(el.width) + 'px',
                height: mmToPx(el.height) + 'px'
            });

            // Update properties panel inputs
            $('#svld-prop-x').val(mmToDisplayUnit(el.x).toFixed(2));
            $('#svld-prop-y').val(mmToDisplayUnit(el.y).toFixed(2));
            $('#svld-prop-width').val(mmToDisplayUnit(el.width).toFixed(2));
            $('#svld-prop-height').val(mmToDisplayUnit(el.height).toFixed(2));

            // Update preview (but position is already set, so it won't jump)
            updateImagePreview(el);

            // Save to history
            saveToHistory('Change Image Source');
        });

        // Invoice props toggles
        $('#svld-prop-show-item-image, #svld-prop-show-item-qty, #svld-prop-show-item-price, #svld-prop-show-subtotal, #svld-prop-show-tax, #svld-prop-show-shipping, #svld-prop-show-discount, #svld-prop-show-total, #svld-prop-show-payment, #svld-prop-show-shipping-via').on('change', previewPropertyChange);

        // Media library button for image element
        let mediaUploader = null;
        $('#svld-prop-select-image').on('click', function(e) {
            e.preventDefault();

            // If media uploader already exists, reopen it
            if (mediaUploader) {
                mediaUploader.open();
                return;
            }

            // Create new media uploader
            mediaUploader = wp.media({
                title: 'Select Image',
                button: { text: 'Use Image' },
                multiple: false
            });

            // When image is selected
            mediaUploader.on('select', function() {
                const attachment = mediaUploader.state().get('selection').first().toJSON();

                // Use full size URL for best quality
                const imageUrl = attachment.sizes && attachment.sizes.full ? attachment.sizes.full.url : attachment.url;

                $('#svld-prop-imageurl').val(imageUrl);

                // Update the selected element
                if (selectedId) {
                    const el = layout.find(e => e.id === selectedId);
                    if (el) {
                        el.imageUrl = imageUrl;
                        el.customText = ''; // Clear customText when using media library
                        renderCanvas();

                        // Verify the image appeared
                        setTimeout(function() {
                            const $imgEl = $('#svld-canvas [data-id="' + selectedId + '"] img');
                            if (!$imgEl.length || $imgEl.attr('src') !== imageUrl) {
                                console.error('Image failed to render');
                            }
                        }, 100);
                    }
                }
            });

            mediaUploader.open();
        });

        // Paper size preset
        $('#svld-size-preset').on('change', function() {
            const val = $(this).val();
            if (!val) return;
            const parts = val.split('x');
            const w = parseInt(parts[0]) || 100;
            const h = parseInt(parts[1]) || 50;
            $('#svld-label-width').val(w);
            $('#svld-label-height').val(h);
            labelW = w;
            labelH = h;
            updateCanvasSize();
            $(this).val(''); // reset to placeholder
        });

        // Template management
        $('#svld-new-preset').on('click', openPresetChooser);
        $('#svld-save-template').on('click', openSaveTemplateModal);
        $('#svld-manage-templates').on('click', openTemplateManager);
        $('#svld-load-template').on('click', loadSelectedTemplate);
        $('#svld-template-select').on('change', function() {
            $('#svld-load-template').prop('disabled', $(this).val() === 'current');
        });
    }

    // =========================================================================
    // Toolbar: Grid, Snap, Bounds
    // =========================================================================
    function initToolbarHandlers() {
        // Grid overlay toggle
        $('#svld-toggle-grid').on('click', function () {
            showGrid = !showGrid;
            $(this).toggleClass('active', showGrid);
            drawGrid();
        });

        // Snap-to-0.5mm toggle - DISABLED per user request
        $('#svld-toggle-snap').on('click', function () {
            snapEnabled = !snapEnabled;
            $(this).toggleClass('active', snapEnabled);
            // Visual feedback - show/hide snap indicator on all elements
            if (snapEnabled) {
                $('#svld-canvas').addClass('svld-snap-enabled');
            } else {
                $('#svld-canvas').removeClass('svld-snap-enabled');
                $('#svld-canvas .svld-el').removeClass('svld-snapping');
            }
        });

        // Show element bounds toggle
        $('#svld-toggle-bounds').on('click', function () {
            showBounds = !showBounds;
            $(this).toggleClass('active', showBounds);
            $('#svld-canvas').toggleClass('svld-show-bounds', showBounds);
        });

        // Undo/Redo buttons
        $('#svld-undo').on('click', performUndo);
        $('#svld-redo').on('click', performRedo);
    }

    // =========================================================================
    // Undo/Redo System
    // =========================================================================
    function saveToHistory(action) {
        if (isUndoRedoAction) return;

        // Create a deep copy of the current layout
        const layoutCopy = JSON.parse(JSON.stringify(layout));

        // Remove any future history if we're not at the end
        if (historyIndex < historyStack.length - 1) {
            historyStack = historyStack.slice(0, historyIndex + 1);
        }

        // Add current state to history
        historyStack.push({
            layout: layoutCopy,
            action: action,
            timestamp: Date.now()
        });

        // Limit history size
        if (historyStack.length > maxHistorySize) {
            historyStack.shift();
        } else {
            historyIndex++;
        }

        updateUndoRedoButtons();
    }

    function performUndo() {
        if (historyIndex <= 0) return;

        isUndoRedoAction = true;
        historyIndex--;

        const state = historyStack[historyIndex];
        layout = JSON.parse(JSON.stringify(state.layout));
        selectedId = null;

        renderCanvas();
        syncElementPanel();
        updateUndoRedoButtons();

        setTimeout(() => { isUndoRedoAction = false; }, 100);
    }

    function performRedo() {
        if (historyIndex >= historyStack.length - 1) return;

        isUndoRedoAction = true;
        historyIndex++;

        const state = historyStack[historyIndex];
        layout = JSON.parse(JSON.stringify(state.layout));
        selectedId = null;

        renderCanvas();
        syncElementPanel();
        updateUndoRedoButtons();

        setTimeout(() => { isUndoRedoAction = false; }, 100);
    }

    function updateUndoRedoButtons() {
        $('#svld-undo').prop('disabled', historyIndex <= 0);
        $('#svld-redo').prop('disabled', historyIndex >= historyStack.length - 1);
    }

    function initHistory() {
        // Save initial state
        saveToHistory('Initial State');
    }

    // =========================================================================
    // Add new element
    // =========================================================================
    function addNewElement(type, dropX, dropY) {
        // Pro check for adding elements
        if (!isPro) {
            // Show tooltip near the elements panel
            const $elementsPanel = $('.svld-elements-panel');
            if ($elementsPanel.length) {
                showProTooltip($elementsPanel);
            }
            return;
        }

        try {
            console.log('addNewElement called with type:', type, 'dropX:', dropX, 'dropY:', dropY);

            if (!type) {
                console.error('addNewElement: No type provided');
                return;
            }

            const newElement = {
                id: type + '_' + (elementCounter++),
                type: type,
                label: type,
                x: 10,
                y: 10,
                width: type === 'qr' ? 20 : (type === 'image' ? 25 : 60),
                height: type === 'qr' ? 20 : (type === 'image' ? 25 : 35),
                fontSize: 10,
                bold: false,
                align: 'left',
                visible: true,
                showText: true,
                barcodeType: type === 'barcode' ? 'C128' : '',
                qrType: type === 'qr' ? 'QRCODE,H' : '',
                dataSource: type === 'barcode' ? 'product_sku' : (type === 'qr' ? 'product_link' : 'product_name'),
                customText: '',
                imageUrl: '',
                imageDataSource: type === 'image' ? 'custom' : '',
                multiLine: false,
                proportional: false,
                // Invoice table properties (all with defaults)
                showItemQty: true,
                showItemPrice: true,
                showItemImage: false,
                showSubtotal: true,
                showTax: true,
                showShipping: true,
                showDiscount: false,
                showTotal: true,
                showPayment: false,
                showShippingVia: false,
                zIndex: layout.length + 1, // Independent z-index, not tied to array position
            };

            // Special handling for invoice elements - set larger default size
            if (type === 'text') {
                // Text elements will be modified to invoice after adding
                // Set reasonable default size for invoice tables
                newElement.width = 80;
                newElement.height = 50;
                newElement.multiLine = true;
            }

            // Use drop position if provided (drag-and-drop), otherwise auto-position
            if (dropX !== undefined && dropY !== undefined) {
                // Center the element on the drop position (allow negative positions)
                newElement.x = dropX - (newElement.width / 2);
                newElement.y = dropY - (newElement.height / 2);
            } else {
                // Position new elements to avoid overlap with elements of the same type
                const sameTypeElements = layout.filter(el => el.type === type && el.visible !== false);
                let posX = 5;
                let posY = 5;

                if (sameTypeElements.length > 0) {
                    let maxX = 0;
                    let maxY = 0;
                    sameTypeElements.forEach(el => {
                        const rightEdge  = (Number(el.x) || 0) + (Number(el.width) || 30);
                        const bottomEdge = (Number(el.y) || 0) + (Number(el.height) || 10);
                        if (rightEdge  > maxX) maxX = rightEdge;
                        if (bottomEdge > maxY) maxY = bottomEdge;
                    });

                    posX = maxX + 5;
                    posY = 5;

                    if (posX + (Number(newElement.width) || 30) > (Number(labelW) || 100)) {
                        posX = 5;
                        posY = maxY + 5;
                    }
                }

                newElement.x = posX;
                newElement.y = posY;
            }

            layout.push(newElement);
            // Render only the new element to avoid reflow issues
            const $canvas = $('#svld-canvas');
            $canvas.find('.svld-canvas-placeholder').hide();
            const $el = buildElement(newElement);
            $el.css('z-index', layout.length); // New element goes on top
            $canvas.append($el);
            renderLayersList();
            syncElementPanel(); // Update element panel to disable this type
            selectElement(newElement.id);
            saveToHistory('Add ' + type);
            console.log('Element added successfully:', newElement.id);
        } catch (error) {
            console.error('Error in addNewElement:', error);
            console.error('Error stack:', error.stack);
        }
    }

    // =========================================================================
    // Selection
    // =========================================================================
    function selectElement(id) {
        selectedId = id;
        const $canvas = $('#svld-canvas');

        // Clear multi-selection when selecting a single element
        multiSelected.clear();
        $canvas.find('.svld-el').removeClass('svld-multi-selected');

        // Restore each element's own zIndex, then elevate selected element
        $canvas.find('.svld-el').each(function () {
            const elId = $(this).data('id');
            const el   = layout.find(e => e.id === elId);
            const zIndex = (el && el.zIndex !== undefined) ? el.zIndex : 1;
            $(this).removeClass('svld-selected').css('z-index', zIndex);
        });

        // Elevate selected element above all for interaction, but preserve its actual zIndex
        $canvas.find('[data-id="' + id + '"]').addClass('svld-selected').css('z-index', 9999);

        // Sync element panel to show which types are on canvas
        syncElementPanel();

        showProperties(id);
        $('#svld-layers-list .svld-layer-item').removeClass('svld-layer-selected');
        $('#svld-layers-list [data-id="' + id + '"]').addClass('svld-layer-selected');

        // Trigger custom event for floating mode
        $(document).trigger('svld:element-selected', [id]);
    }

    function deselectElement() {
        selectedId = null;
        multiSelected.clear();
        const $canvas = $('#svld-canvas');

        // Restore each element's own zIndex when deselecting
        $canvas.find('.svld-el').each(function () {
            const elId = $(this).data('id');
            const el   = layout.find(e => e.id === elId);
            const zIndex = (el && el.zIndex !== undefined) ? el.zIndex : 1;
            $(this).removeClass('svld-selected svld-multi-selected').css('z-index', zIndex);
        });

        $('#svld-properties-form').hide();
        $('#svld-no-selection').show();
        $('#svld-layers-list .svld-layer-item').removeClass('svld-layer-selected');

        // Sync element panel to show which types are on canvas
        syncElementPanel();

        // CRITICAL: Unpin the properties panel when deselecting
        $('.svld-properties-panel').removeClass('svld-panel-pinned');

        // Trigger custom event for floating mode
        $(document).trigger('svld:element-deselected');
    }

    function showProperties(id) {
        const el = layout.find(e => e.id === id);
        if (!el) return;

        const isText    = ['text', 'title', 'sku', 'price', 'website'].includes(el.type);
        const isBarcode = el.type === 'barcode';
        const isQR      = el.type === 'qr';
        const isImage   = el.type === 'image';

        $('#svld-no-selection').hide();
        $('#svld-properties-form').show();

        $('#svld-prop-visible').prop('checked', el.visible !== false);
        $('#svld-prop-font-size').val(el.fontSize || 10);
        $('#svld-prop-fit-width').prop('checked', !!el.fitWidth);
        $('#svld-prop-multi-line').prop('checked', !!el.multiLine);

        // Text style buttons - set active state
        $('#svld-prop-bold').toggleClass('active', !!el.bold);
        $('#svld-prop-italic').toggleClass('active', !!el.italic);
        $('#svld-prop-underline').toggleClass('active', !!el.underline);

        // Alignment buttons - set active state
        $('.svld-align-buttons .svld-style-btn').removeClass('active');
        const alignBtn = $('.svld-align-buttons .svld-style-btn[data-align="' + (el.align || 'left') + '"]');
        if (alignBtn.length) alignBtn.addClass('active');

        $('#svld-prop-x').val(mmToDisplayUnit(el.x || 0));
        $('#svld-prop-y').val(mmToDisplayUnit(el.y || 0));
        $('#svld-prop-width').val(mmToDisplayUnit(el.width || 30));
        $('#svld-prop-height').val(mmToDisplayUnit(el.height || 10));
        $('#svld-prop-proportional').prop('checked', !!el.proportional);
        $('#svld-prop-show-text').prop('checked', el.showText !== false);

        // Barcode type - ensure it's properly set
        const barcodeType = el.barcodeType || 'C128';
        $('#svld-prop-barcode-type').val(barcodeType);

        // QR code type - ensure it's properly set
        const qrType = el.qrType || 'QRCODE,H';
        $('#svld-prop-qr-type').val(qrType);

        // Data source for QR/barcode/text
        const ds = el.type === 'image'
            ? (el.imageDataSource || 'custom')
            : (el.dataSource || 'product_name');
        $('#svld-prop-datasource').val(ds);
        $('#svld-prop-customtext').val(el.customText || '');

        // Invoice options (merged items table + totals)
        $('#svld-prop-show-item-image').prop('checked', el.showItemImage === true);
        $('#svld-prop-show-item-qty').prop('checked', el.showItemQty !== false);
        $('#svld-prop-show-item-price').prop('checked', el.showItemPrice !== false);
        $('#svld-prop-show-subtotal').prop('checked', el.showSubtotal !== false);
        $('#svld-prop-show-tax').prop('checked', el.showTax !== false);
        $('#svld-prop-show-shipping').prop('checked', el.showShipping !== false);
        $('#svld-prop-show-discount').prop('checked', el.showDiscount === true);
        $('#svld-prop-show-total').prop('checked', el.showTotal !== false);
        $('#svld-prop-show-payment').prop('checked', el.showPayment === true);
        $('#svld-prop-show-shipping-via').prop('checked', el.showShippingVia === true);

        // Image data source and URL
        const imgDs = el.imageDataSource || 'custom';
        $('#svld-prop-image-datasource').val(imgDs);
        $('#svld-prop-imageurl').val(el.imageUrl || el.customText || '');

        // Invoice element (order_invoice_full datasource) only shows direction toggle,
        // not the regular text-style controls (bold/italic/etc are irrelevant for HTML tables).
        const isInvoice = isText && ds === 'order_invoice_full';

        // Set direction toggle active state
        const dir = el.textDirection || 'ltr';
        $('.svld-dir-btn').removeClass('active');
        $('.svld-dir-btn[data-dir="' + dir + '"]').addClass('active');

        // Show/hide property groups
        $('.svld-text-props').toggle(isText && !isInvoice);
        $('.svld-barcode-props').toggle(isBarcode);
        $('.svld-qr-props').toggle(isQR);
        $('.svld-datasource-props').toggle(isQR || isBarcode || isText);
        $('.svld-image-props').toggle(isImage);
        $('.svld-invoice-direction-props').toggle(isInvoice);

        if (isQR || isBarcode || isText) {
            $('.svld-customtext-props').toggle(ds === 'custom');
            $('.svld-invoice-props').toggle(isInvoice);
        } else {
            $('.svld-customtext-props').hide();
            $('.svld-invoice-props').hide();
        }

        // Show/hide image-specific props
        if (isImage) {
            $('.svld-image-url-props').toggle(imgDs === 'custom');
            $('.svld-product-image-props').toggle(imgDs === 'product_image');
        } else {
            $('.svld-image-url-props').hide();
            $('.svld-product-image-props').hide();
        }

        // Show fit-to-width for all text elements including invoice
        $('#svld-prop-fit-width-group').toggle(isText);
        // Multi-line only for non-invoice text with fit-to-width on
        $('#svld-prop-multi-line-group').toggle(!!el.fitWidth && isText && !isInvoice);

        // Update validation hints
        updateValidationHints(el);

        // Hide product_image option for non-image elements
        if (isImage) {
            $('#svld-prop-datasource option[value="product_image"]').show();
        } else {
            $('#svld-prop-datasource option[value="product_image"]').hide();
        }

        // Update data preview
        updateDataPreview(el);
    }

    // Barcode/QR validation hints
    function updateValidationHints(el) {
        const barcodeHints = {
            'C128': '✓ Accepts any characters (recommended)',
            'C39': '⚠️ Requires uppercase A-Z, 0-9, and symbols (-. $/+%)',
            'EAN13': '⚠️ Requires 12-13 numeric digits only',
            'EAN8': '⚠️ Requires 7-8 numeric digits only',
            'UPCA': '⚠️ Requires 11-12 numeric digits only',
            'UPCE': '⚠️ Requires 6-8 numeric digits only',
            'I25': '⚠️ Requires even number of digits',
            'POSTNET': '⚠️ Numeric digits only'
        };

        const qrHints = {
            'QRCODE,H': '✓ Standard QR code (recommended)',
            'DATAMATRIX': '✓ Compact 2D code',
            'PDF417': '✓ Stacked 2D code'
        };

        // Update barcode hint
        if (el.type === 'barcode') {
            const hint = barcodeHints[el.barcodeType] || '';
            $('#svld-barcode-validation-hint').text(hint).toggle(!!hint);
        }

        // Update QR hint
        if (el.type === 'qr') {
            const hint = qrHints[el.qrType] || '';
            $('#svld-qr-validation-hint').text(hint).toggle(!!hint);
        }
    }

    // Update data source preview
    function updateDataPreview(el) {
        const $preview = $('#svld-data-source-preview');
        const $content = $('#svld-preview-content');

        if (!el) {
            $content.html('<p class="svld-preview-placeholder">Select an element to preview its data</p>');
            return;
        }

        // Get the text that would be rendered
        const previewText = getElementText(el);
        const ds = el.dataSource || '';

        // Build preview HTML
        let html = '<div class="svld-preview-info">';
        html += '<div class="svld-preview-row"><strong>Element:</strong> <span>' + el.type + '</span></div>';
        html += '<div class="svld-preview-row"><strong>Data Source:</strong> <span>' + ds + '</span></div>';
        html += '</div>';
        html += '<div class="svld-preview-value">';

        if (el.type === 'image') {
            if (el.imageDataSource === 'product_image') {
                html += '<span class="svld-preview-placeholder">🖼️ Product image (shown in PDF)</span>';
            } else {
                html += '<span class="svld-preview-placeholder">🔗 Custom URL image (shown in PDF)</span>';
                if (el.imageUrl || el.customText) {
                    html += '<br><code style="font-size:9px;color:#666;">' + (el.imageUrl || el.customText).substring(0, 50) + '...</code>';
                }
            }
        } else if (el.type === 'barcode') {
            html += '<span class="svld-preview-barcode">||||| ||||| ||</span>';
            if (el.showText !== false) {
                const text = el.customText || (el.dataSource === 'product_sku' ? 'SKU-ABC123' : '123456789012');
                html += '<br><code>' + text + '</code>';
            }
        } else if (el.type === 'qr') {
            html += '<div class="svld-preview-qr-small">▚�▚▚▚</div>';
        } else {
            // Text element
            html += '<div class="svld-preview-text">' + previewText + '</div>';
        }

        html += '</div>';

        $content.html(html);
        $preview.show();
    }

    function applyProperties() {
        if (!selectedId) return;
        const el = layout.find(e => e.id === selectedId);
        if (!el) return;

        el.visible   = $('#svld-prop-visible').is(':checked');
        el.fontSize  = parseInt($('#svld-prop-font-size').val()) || 10;
        // Note: bold, italic, underline, align are now handled by button click handlers
        el.fitWidth  = $('#svld-prop-fit-width').is(':checked');
        el.multiLine = $('#svld-prop-multi-line').is(':checked');
        el.x         = displayUnitToMm(parseFloat($('#svld-prop-x').val()) || 0);
        el.y         = displayUnitToMm(parseFloat($('#svld-prop-y').val()) || 0);
        el.width     = displayUnitToMm(parseFloat($('#svld-prop-width').val()) || 30);
        el.height    = displayUnitToMm(parseFloat($('#svld-prop-height').val()) || 10);
        el.proportional = $('#svld-prop-proportional').is(':checked');
        el.showText  = $('#svld-prop-show-text').is(':checked');
        el.barcodeType = $('#svld-prop-barcode-type').val();
        el.qrType = $('#svld-prop-qr-type').val();
        el.customText = $('#svld-prop-customtext').val();
        el.imageUrl = $('#svld-prop-imageurl').val();
        if (el.type === 'image') {
            el.imageDataSource = $('#svld-prop-image-datasource').val() || 'custom';
            el.dataSource = el.imageDataSource;
        } else {
            el.dataSource = $('#svld-prop-datasource').val();
            el.imageDataSource = '';
        }

        // Update the element content/properties in place without replacing the element
        const $el = $('#svld-canvas [data-id="' + selectedId + '"]');
        if ($el.length) {
            // Update visual properties in place
            if (el.fontSize) {
                const $content = $el.find('.svld-el-content');
                if ($content.length) {
                    $content.css({
                        fontSize: el.fontSize + 'pt',
                        fontWeight: el.bold ? 'bold' : 'normal',
                        fontStyle: el.italic ? 'italic' : 'normal',
                        textDecoration: el.underline ? 'underline' : 'none',
                        justifyContent: el.align === 'center' ? 'center' : (el.align === 'right' ? 'flex-end' : 'flex-start'),
                    });
                }
            }

            // Update content for text elements
            if (['text', 'title', 'sku', 'price', 'website'].includes(el.type)) {
                const $content = $el.find('.svld-el-content');
                if ($content.length) {
                    const text = getElementText(el);
                    if ((el.dataSource || el.type) === 'order_invoice_full') {
                        $content.html(text);
                    } else {
                        $content.text(text);
                    }
                }
            }

            // Update barcode/QR code
            if (el.type === 'barcode') {
                $el.html(buildBarcodeHtml(el));
            } else if (el.type === 'qr') {
                $el.html(buildQrHtml(el));
            } else if (el.type === 'image') {
                const imgDs = el.imageDataSource || 'custom';
                let imgSrc = el.imageUrl || el.customText || 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="100" height="100"%3E%3Crect width="100" height="100" fill="%23e2e8f0"/%3E%3Ctext x="50" y="55" text-anchor="middle" font-size="12" fill="%2394a3b8"%3EImage%3C/text%3E%3C/svg%3E';
                if (imgDs === 'product_image') {
                    imgSrc = 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="200" height="200"%3E%3Crect width="200" height="200" fill="%23e2e8f0"/%3E%3Ctext x="100" y="105" text-anchor="middle" font-size="14" fill="%2394a3b8"%3EProduct Image%3C/text%3E%3C/svg%3E';
                }
                $el.html('<img src="' + imgSrc + '" style="max-width:100%;max-height:100%;object-fit:contain;" />');
            }

            // Update visibility
            $el.toggle(el.visible !== false);
        }

        // Save history for property changes (debounced)
        clearTimeout(window.propertyChangeTimeout);
        window.propertyChangeTimeout = setTimeout(function() {
            saveToHistory('Change Properties');
        }, 500);
    }

    function removeSelected() {
        // Check if we have multiple items selected
        if (multiSelected.size > 1) {
            // Remove all multi-selected elements
            const idsToRemove = Array.from(multiSelected);
            idsToRemove.forEach(function(id) {
                const idx = layout.findIndex(e => e.id === id);
                if (idx > -1) layout.splice(idx, 1);
            });
            deselectElement();
            renderCanvas();
            syncElementPanel(); // Update element panel after removal
            saveToHistory('Remove Elements');
        } else if (selectedId) {
            // Remove single selected element
            const idx = layout.findIndex(e => e.id === selectedId);
            if (idx > -1) layout.splice(idx, 1);
            deselectElement();
            renderCanvas();
            syncElementPanel(); // Update element panel after removal
            saveToHistory('Remove Element');
        }
    }

    function duplicateSelected() {
        if (!selectedId) return;
        duplicateElement(selectedId);
    }

    // =========================================================================
    // Layer ordering - Now updates independent z-index without reordering array
    // =========================================================================
    function bringToFront() {
        if (!selectedId) return;
        const el = layout.find(e => e.id === selectedId);
        if (!el) return;

        // Find the maximum z-index among all elements
        let maxZ = 0;
        layout.forEach(function (e) {
            if (e.zIndex !== undefined && e.zIndex > maxZ) {
                maxZ = e.zIndex;
            }
        });

        // Set this element's z-index to max + 1
        el.zIndex = maxZ + 1;

        // Update only this element's z-index in the DOM - no full re-render
        const $canvas = $('#svld-canvas');
        const $el = $canvas.find('[data-id="' + selectedId + '"]');
        if ($el.length) {
            $el.css('z-index', el.zIndex);
        }

        renderLayersList();
        saveToHistory('Bring to Front');
    }

    function sendToBack() {
        if (!selectedId) return;
        const el = layout.find(e => e.id === selectedId);
        if (!el) return;

        // Find the minimum z-index among all elements
        let minZ = Infinity;
        layout.forEach(function (e) {
            if (e.zIndex !== undefined && e.zIndex < minZ) {
                minZ = e.zIndex;
            }
        });

        // Set this element's z-index to min - 1 (but not below 1)
        el.zIndex = Math.max(1, minZ - 1);

        // Update only this element's z-index in the DOM - no full re-render
        const $canvas = $('#svld-canvas');
        const $el = $canvas.find('[data-id="' + selectedId + '"]');
        if ($el.length) {
            $el.css('z-index', el.zIndex);
        }

        renderLayersList();
        saveToHistory('Send to Back');
    }

    function moveLayerUp() {
        if (!selectedId) return;
        const el = layout.find(e => e.id === selectedId);
        if (!el) return;

        // Find the next highest z-index above this element
        const currentZ = el.zIndex !== undefined ? el.zIndex : 1;
        let nextZ = Infinity;
        let foundHigher = false;

        layout.forEach(function (e) {
            if (e.id !== selectedId && e.zIndex !== undefined) {
                if (e.zIndex > currentZ && e.zIndex < nextZ) {
                    nextZ = e.zIndex;
                    foundHigher = true;
                }
            }
        });

        if (foundHigher) {
            // Swap z-indices with the element above
            const higherEl = layout.find(e => e.zIndex === nextZ);
            if (higherEl) {
                higherEl.zIndex = currentZ;
            }
            el.zIndex = nextZ;

            // Update both elements' z-index in DOM
            const $canvas = $('#svld-canvas');
            layout.forEach(function (e) {
                if (e.id === selectedId || (higherEl && e.id === higherEl.id)) {
                    const $el = $canvas.find('[data-id="' + e.id + '"]');
                    if ($el.length) {
                        $el.css('z-index', e.zIndex);
                    }
                }
            });

            renderLayersList();
            saveToHistory('Move Layer Up');
        }
    }

    function moveLayerDown() {
        if (!selectedId) return;
        const el = layout.find(e => e.id === selectedId);
        if (!el) return;

        // Find the next lower z-index below this element
        const currentZ = el.zIndex !== undefined ? el.zIndex : 1;
        let nextZ = -1;
        let foundLower = false;

        layout.forEach(function (e) {
            if (e.id !== selectedId && e.zIndex !== undefined) {
                if (e.zIndex < currentZ && e.zIndex > nextZ) {
                    nextZ = e.zIndex;
                    foundLower = true;
                }
            }
        });

        if (foundLower) {
            // Swap z-indices with the element below
            const lowerEl = layout.find(e => e.zIndex === nextZ);
            if (lowerEl) {
                lowerEl.zIndex = currentZ;
            }
            el.zIndex = nextZ;

            // Update both elements' z-index in DOM
            const $canvas = $('#svld-canvas');
            layout.forEach(function (e) {
                if (e.id === selectedId || (lowerEl && e.id === lowerEl.id)) {
                    const $el = $canvas.find('[data-id="' + e.id + '"]');
                    if ($el.length) {
                        $el.css('z-index', e.zIndex);
                    }
                }
            });

            renderLayersList();
            saveToHistory('Move Layer Down');
        }
    }

    // =========================================================================
    // Alignment functions
    // =========================================================================
    function alignElements(alignment) {
        // Get elements to align - use multi-selected or single selected element
        const elementsToAlign = multiSelected.size > 0
            ? Array.from(multiSelected)
            : (selectedId ? [selectedId] : []);

        if (elementsToAlign.length === 0) return;

        // For single element, align to canvas bounds
        // For multiple elements, align to the first selected element (anchor)
        const anchorId = elementsToAlign[0];
        const anchorEl = layout.find(e => e.id === anchorId);
        if (!anchorEl) return;

        elementsToAlign.forEach(id => {
            const el = layout.find(e => e.id === id);
            if (!el) return;

            switch (alignment) {
                case 'left':
                    el.x = 0;
                    break;
                case 'right':
                    el.x = labelW - el.width;
                    break;
                case 'center-h':
                    el.x = (labelW - el.width) / 2;
                    break;
                case 'top':
                    el.y = 0;
                    break;
                case 'bottom':
                    el.y = labelH - el.height;
                    break;
                case 'center-v':
                    el.y = (labelH - el.height) / 2;
                    break;
            }

            // Update canvas element position
            const $el = $('#svld-canvas [data-id="' + id + '"]');
            if ($el.length) {
                $el.css({
                    left: mmToPx(el.x) + 'px',
                    top: mmToPx(el.y) + 'px',
                });
            }

            // Update properties panel if this element is selected
            if (id === selectedId) {
                $('#svld-prop-x').val(mmToDisplayUnit(el.x).toFixed(1));
                $('#svld-prop-y').val(mmToDisplayUnit(el.y).toFixed(1));
            }
        });

        renderLayersList();
        saveToHistory('Align ' + alignment);
    }

    function duplicateElement(id) {
        const el = layout.find(e => e.id === id);
        if (!el) return;

        // Deep copy — avoids any reference sharing
        const clone  = JSON.parse(JSON.stringify(el));
        clone.id     = el.type + '_' + (elementCounter++);

        const elX = parseFloat(el.x)      || 0;
        const elY = parseFloat(el.y)      || 0;
        const elW = parseFloat(el.width)  || 30;
        const elH = parseFloat(el.height) || 10;
        const gap = 4; // mm gap between original and clone

        // Try to place directly below with a gap
        let newX = elX;
        let newY = elY + elH + gap;

        // If that would go off the bottom of the canvas, try placing to the right
        if (newY + elH > labelH) {
            newX = elX + elW + gap;
            newY = elY;
        }

        // Position the duplicate (allow outside canvas bounds)
        clone.x = newX;
        clone.y = newY;

        // Insert directly above the original in the stack (visually on top)
        const idx = layout.findIndex(e => e.id === id);
        layout.splice(idx + 1, 0, clone);

        // OPTIMIZED: Instead of full re-render, only append the new element
        // This prevents all elements from being rebuilt and potentially jumping
        const $canvas = $('#svld-canvas');
        const $newEl = buildElement(clone);

        // Update z-index for all elements to reflect new array order
        layout.forEach(function (layoutEl, index) {
            if (!layoutEl.visible) return;
            const $existingEl = $canvas.find('[data-id="' + layoutEl.id + '"]');
            if ($existingEl.length) {
                $existingEl.css('z-index', index + 1);
            }
        });

        // Set z-index for new element (above the original)
        const newZIdx = idx + 2; // Position after original
        $newEl.css('z-index', newZIdx);
        $canvas.append($newEl);

        // Update layers list only
        renderLayersList();
        syncElementPanel(); // Update element panel to disable this type

        // Select the new element
        selectElement(clone.id);
        saveToHistory('Duplicate Element');
    }

    // =========================================================================
    // Right-click context menu
    // =========================================================================
    const ELEMENT_TYPE_ICONS = {
        text: '𝐓', barcode: '▌▌▌', qr: '⬛', image: '🖼',
        title: '𝐓', sku: '#', price: '$', website: '🌐',
    };

    function showContextMenu(clientX, clientY, id) {
        hideContextMenu();
        const el    = layout.find(e => e.id === id);
        const idx   = layout.findIndex(e => e.id === id);
        const total = layout.length;
        const label = el ? (el.customText || el.dataSource || el.type) : id;

        const canUp   = idx < total - 1;
        const canDown = idx > 0;

        const menuHtml = `
            <ul id="svld-ctx-menu" class="svld-ctx-menu">
                <li class="svld-ctx-header">${ELEMENT_TYPE_ICONS[el && el.type] || '◻'} ${label}</li>
                <li class="svld-ctx-divider"></li>
                <li data-action="front"  class="svld-ctx-item ${canUp   ? '' : 'svld-ctx-disabled'}"><span>⤒</span> Bring to Front</li>
                <li data-action="up"     class="svld-ctx-item ${canUp   ? '' : 'svld-ctx-disabled'}"><span>↑</span> Move Up</li>
                <li data-action="down"   class="svld-ctx-item ${canDown ? '' : 'svld-ctx-disabled'}"><span>↓</span> Move Down</li>
                <li data-action="back"   class="svld-ctx-item ${canDown ? '' : 'svld-ctx-disabled'}"><span>⤓</span> Send to Back</li>
                <li class="svld-ctx-divider"></li>
                <li data-action="delete"    class="svld-ctx-item svld-ctx-danger"><span>✕</span> Delete</li>
            </ul>`;

        const $menu = $(menuHtml).appendTo('body');

        // Position — keep inside viewport
        const mw = $menu.outerWidth();
        const mh = $menu.outerHeight();
        let left = clientX + 2;
        let top  = clientY + 2;
        if (left + mw > window.innerWidth  - 8) left = clientX - mw - 2;
        if (top  + mh > window.innerHeight - 8) top  = clientY - mh - 2;
        $menu.css({ left: left + 'px', top: top + 'px' });

        $menu.on('click', '.svld-ctx-item:not(.svld-ctx-disabled)', function(e) {
            e.stopPropagation();
            const action = $(this).data('action');
            hideContextMenu();
            if      (action === 'front')     { selectedId = id; bringToFront(); }
            else if (action === 'up')        { selectedId = id; moveLayerUp(); }
            else if (action === 'down')      { selectedId = id; moveLayerDown(); }
            else if (action === 'back')      { selectedId = id; sendToBack(); }
            else if (action === 'delete') {
                selectedId = id;
                removeSelected();
            }
        });
    }

    function hideContextMenu() {
        $('#svld-ctx-menu').remove();
    }

    // =========================================================================
    // Layers list (left panel)
    // =========================================================================
    function renderLayersList() {
        const $list = $('#svld-layers-list');
        if (!$list.length) return;

        if (layout.length === 0) {
            $list.html('<p class="svld-layers-empty">No elements yet.</p>');
            return;
        }

        // Human-readable label for each data source key
        const DS_LABELS = {
            product_name:'Product Name', product_sku:'SKU', product_price:'Price',
            product_link:'Product Link', product_stock:'Stock', product_weight:'Weight',
            product_categories:'Categories', product_tags:'Tags',
            product_short_description:'Short Description', product_total_sales:'Total Sales',
            product_length:'Length', product_width:'Width', product_height:'Height',
            product_dimensions:'Dimensions', product_id:'Product ID',
            product_link:'Product Link', product_image:'Product Image',
            order_number:'Order Number', order_date:'Order Date', order_total:'Order Total',
            order_subtotal:'Subtotal', order_tax:'Tax', order_shipping_cost:'Shipping Cost',
            order_discount:'Discount', order_status:'Order Status',
            order_item_count:'Item Count', order_items_list:'Items List',
            order_items_table:'Items Table',
            customer_full_name:'Customer Name', customer_first_name:'First Name',
            customer_last_name:'Last Name', customer_email:'Customer Email',
            customer_phone:'Customer Phone', customer_company:'Company',
            billing_address:'Billing Address', billing_address_1:'Billing Line 1',
            billing_address_2:'Billing Line 2', billing_city:'Billing City',
            billing_state:'Billing State', billing_postcode:'Billing Postcode',
            billing_country:'Billing Country',
            shipping_address:'Shipping Address', shipping_address_1:'Shipping Line 1',
            shipping_address_2:'Shipping Line 2', shipping_city:'Shipping City',
            shipping_state:'Shipping State', shipping_postcode:'Shipping Postcode',
            shipping_country:'Shipping Country',
            payment_method:'Payment Method', shipping_method:'Shipping Method',
            shop_name:'Shop Name', shop_email:'Shop Email', shop_phone:'Shop Phone',
            shop_address:'Shop Address', shop_city:'Shop City', shop_country:'Shop Country',
            shop_postcode:'Shop Postcode',
            site_url:'Website URL', phone:'Phone', current_date:'Current Date',
            custom:'Custom Text',
        };

        // Enhanced icons with emoji
        const ENHANCED_ICONS = {
            text: '📝',
            title: '📝',
            sku: '🏷️',
            price: '💲',
            barcode: '📊',
            qr: '📱',
            image: '🖼️',
            website: '🌐',
        };

        // Show in reverse order: top of stack first (last in array = visually on top)
        let html = '';
        for (let i = layout.length - 1; i >= 0; i--) {
            const el      = layout[i];
            const icon    = ENHANCED_ICONS[el.type] || '📦';
            const ds      = el.dataSource || '';
            const displayLabel = (el.customText && ds === 'custom')
                            ? el.customText.substring(0, 25) + (el.customText.length > 25 ? '...' : '')
                            : (DS_LABELS[ds] || ds || el.type);
            const isSelected = el.id === selectedId;
            const isHidden   = !el.visible;
            const zIndex    = el.zIndex !== undefined ? el.zIndex : (i + 1);
            const posX      = mmToDisplayUnit(el.x).toFixed(0);
            const posY      = mmToDisplayUnit(el.y).toFixed(0);

            html += `<div class="svld-layer-item${isSelected ? ' svld-layer-selected' : ''}${isHidden ? ' svld-layer-hidden' : ''}" data-id="${el.id}">
                <div class="svld-layer-header">
                    <span class="svld-layer-icon">${icon}</span>
                    <span class="svld-layer-name">${el.type.charAt(0).toUpperCase() + el.type.slice(1)}: ${displayLabel}</span>
                </div>
                <div class="svld-layer-info">
                    <span class="svld-layer-detail" title="Data source: ${DS_LABELS[ds] || ds}">
                        ${ds ? '├─ Data: ' + (DS_LABELS[ds] || ds).substring(0, 18) : ''}
                    </span>
                    <span class="svld-layer-detail">└─ Position: ${posX}, ${posY}${unitLabel}</span>
                </div>
                <div class="svld-layer-actions">
                    <button type="button" class="svld-layer-toggle-vis" data-id="${el.id}" title="${el.visible ? 'Hide' : 'Show'}">
                        <span class="dashicons dashicons-${el.visible ? 'visibility' : 'hidden'}"></span>
                    </button>
                    <span class="svld-layer-zindex" title="Z-index: ${zIndex}">z:${zIndex}</span>
                </div>
            </div>`;
        }
        $list.html(html);

        // Use event delegation for click handler (persists after HTML replacement)
        $list.off('click', '.svld-layer-item').on('click', '.svld-layer-item', function(e) {
            // Don't select if clicking on action buttons
            if ($(e.target).closest('.svld-layer-toggle-vis').length) return;
            const id = $(this).data('id');

            if (e.shiftKey && selectedId && selectedId !== id) {
                // Shift+Click: add to multi-selection
                toggleMultiSelect(id);
            } else {
                // Normal click: select only this element
                selectElement(id);
            }
        });

        // Visibility toggle
        $list.find('.svld-layer-toggle-vis').on('click', function(e) {
            e.stopPropagation();
            const id = $(this).data('id');
            const el = layout.find(e => e.id === id);
            if (el) {
                el.visible = !el.visible;
                renderCanvas();
                renderLayersList();
            }
        });
    }

    function previewPropertyChange() {
        if (!selectedId) return;
        const el = layout.find(e => e.id === selectedId);
        if (!el) return;

        // Update all element properties from form
        el.visible = $('#svld-prop-visible').is(':checked');
        el.fontSize = parseInt($('#svld-prop-font-size').val()) || 10;
        // Note: bold, italic, underline, align are now handled by button click handlers
        el.fitWidth = $('#svld-prop-fit-width').is(':checked');
        el.multiLine = $('#svld-prop-multi-line').is(':checked');
        el.proportional = $('#svld-prop-proportional').is(':checked');
        el.x = displayUnitToMm(parseFloat($('#svld-prop-x').val()) || 0);
        el.y = displayUnitToMm(parseFloat($('#svld-prop-y').val()) || 0);
        el.width = displayUnitToMm(parseFloat($('#svld-prop-width').val()) || 30);
        el.height = displayUnitToMm(parseFloat($('#svld-prop-height').val()) || 10);
        el.showText = $('#svld-prop-show-text').is(':checked');
        el.customText = $('#svld-prop-customtext').val();
        el.imageUrl = $('#svld-prop-imageurl').val();
        el.showItemImage    = $('#svld-prop-show-item-image').is(':checked');
        el.showItemQty      = $('#svld-prop-show-item-qty').is(':checked');
        el.showItemPrice    = $('#svld-prop-show-item-price').is(':checked');
        el.showSubtotal     = $('#svld-prop-show-subtotal').is(':checked');
        el.showTax          = $('#svld-prop-show-tax').is(':checked');
        el.showShipping     = $('#svld-prop-show-shipping').is(':checked');
        el.showDiscount     = $('#svld-prop-show-discount').is(':checked');
        el.showTotal        = $('#svld-prop-show-total').is(':checked');
        el.showPayment      = $('#svld-prop-show-payment').is(':checked');
        el.showShippingVia  = $('#svld-prop-show-shipping-via').is(':checked');
        el.barcodeType    = $('#svld-prop-barcode-type').val();
        el.qrType         = $('#svld-prop-qr-type').val();
        if (el.type === 'image') {
            el.imageDataSource = $('#svld-prop-image-datasource').val() || 'custom';
            el.dataSource = el.imageDataSource;
        } else {
            el.dataSource = $('#svld-prop-datasource').val();
            el.imageDataSource = '';
        }

        // Update multi-line visibility - only for text elements when fitWidth is enabled
        const isText = ['text', 'title', 'sku', 'price', 'website'].includes(el.type);
        $('#svld-prop-multi-line-group').toggle(!!el.fitWidth && isText);

        const $el = $('#svld-canvas [data-id="' + selectedId + '"]');

        // For text elements - use off-screen measurement to prevent layout shifts
        if (el.type === 'text') {
            const text = getElementText(el);
            const $content = $el.find('.svld-el-content');

            // Auto-scale font size if "Fit to Width" is enabled
            if (el.fitWidth) {
                const maxWidthPx = Math.max(10, mmToPx(el.width) - 4);
                const maxHeightPx = Math.max(10, mmToPx(el.height) - 4);

                if (el.multiLine) {
                    // Multi-line mode: calculate font size to fit both width and height
                    // Use off-screen container that's completely isolated from layout
                    let $measureContainer = $('#svld-text-measure-container');
                    if (!$measureContainer.length) {
                        $measureContainer = $('<div id="svld-text-measure-container">').css({
                            position: 'absolute',
                            left: '0',
                            top: '0',
                            visibility: 'hidden',
                            pointerEvents: 'none',
                            zIndex: '-9999',
                            position: 'fixed',
                            left: '-10000px',
                            top: '-10000px',
                            width: '1px',
                            height: '1px',
                            overflow: 'hidden'
                        }).appendTo('#svld-canvas-scale-host');
                    }

                    const $temp = $('<div>').css({
                        whiteSpace: 'pre-wrap',
                        wordBreak: 'break-word',
                        overflowWrap: 'break-word',
                        fontFamily: 'Arial, sans-serif',
                        fontWeight: el.bold ? 'bold' : 'normal',
                        fontStyle: el.italic ? 'italic' : 'normal',
                        textDecoration: el.underline ? 'underline' : 'none',
                        fontSize: el.fontSize + 'pt',
                        width: maxWidthPx + 'px',
                        lineHeight: '1.2',
                        padding: '2px',
                        position: 'absolute',
                        visibility: 'hidden'
                    }).text(text).appendTo($measureContainer);

                    const tempHeight = $temp[0].getBoundingClientRect().height;
                    $temp.remove();

                    let scaledFontSize = el.fontSize;
                    if (tempHeight > maxHeightPx) {
                        const scale = maxHeightPx / tempHeight;
                        const elementSizePx = Math.min(maxWidthPx, maxHeightPx);
                        const minFontSize = Math.max(1, Math.floor(elementSizePx / 8));
                        scaledFontSize = Math.max(minFontSize, Math.floor(el.fontSize * scale));
                    }

                    $content.css({
                        fontSize: scaledFontSize + 'pt',
                        fontWeight: el.bold ? 'bold' : 'normal',
                        fontStyle: el.italic ? 'italic' : 'normal',
                        textDecoration: el.underline ? 'underline' : 'none',
                        whiteSpace: 'pre-wrap',
                        wordBreak: 'break-word',
                        overflowWrap: 'break-word',
                        lineHeight: '1.2',
                        padding: '2px',
                        textAlign: el.align,
                        display: 'flex',
                        flexDirection: 'column',
                        justifyContent: el.align === 'center' ? 'center' : (el.align === 'right' ? 'flex-end' : 'flex-start'),
                        alignItems: el.align === 'center' ? 'center' : (el.align === 'right' ? 'flex-end' : 'flex-start'),
                    });
                } else {
                    // Single-line mode: only fit to width
                    // Use off-screen container that's completely isolated from layout
                    let $measureContainer = $('#svld-text-measure-container');
                    if (!$measureContainer.length) {
                        $measureContainer = $('<div id="svld-text-measure-container">').css({
                            position: 'absolute',
                            left: '0',
                            top: '0',
                            visibility: 'hidden',
                            pointerEvents: 'none',
                            zIndex: '-9999',
                            position: 'fixed',
                            left: '-10000px',
                            top: '-10000px',
                            width: '1px',
                            height: '1px',
                            overflow: 'hidden'
                        }).appendTo('#svld-canvas-scale-host');
                    }

                    const $temp = $('<div>').css({
                        whiteSpace: 'nowrap',
                        fontFamily: 'Arial, sans-serif',
                        fontWeight: el.bold ? 'bold' : 'normal',
                        fontStyle: el.italic ? 'italic' : 'normal',
                        textDecoration: el.underline ? 'underline' : 'none',
                        fontSize: el.fontSize + 'pt',
                        position: 'absolute',
                        visibility: 'hidden'
                    }).text(text).appendTo($measureContainer);

                    const textWidth = $temp[0].getBoundingClientRect().width;
                    $temp.remove();

                    let scaledFontSize = el.fontSize;
                    if (textWidth > maxWidthPx) {
                        const scale = maxWidthPx / textWidth;
                        const elementWidthPx = mmToPx(el.width);
                        const minFontSize = Math.max(1, Math.floor(elementWidthPx / 10));
                        scaledFontSize = Math.max(minFontSize, Math.floor(el.fontSize * scale));
                    }

                    $content.css({
                        fontSize: scaledFontSize + 'pt',
                        fontWeight: el.bold ? 'bold' : 'normal',
                        fontStyle: el.italic ? 'italic' : 'normal',
                        textDecoration: el.underline ? 'underline' : 'none',
                        whiteSpace: 'nowrap',
                    });
                }
            } else {
                $content.css({
                    fontSize: el.fontSize + 'pt',
                    fontWeight: el.bold ? 'bold' : 'normal',
                    fontStyle: el.italic ? 'italic' : 'normal',
                    textDecoration: el.underline ? 'underline' : 'none',
                    whiteSpace: el.multiLine ? 'normal' : 'nowrap',
                });
            }
            $content.css('justifyContent', el.align === 'center' ? 'center' : (el.align === 'right' ? 'flex-end' : 'flex-start'));
            // Invoice elements return an HTML string — use .html() to render it correctly
            if ((el.dataSource || el.type) === 'order_invoice_full') {
                $content.html(text);
            } else {
                $content.text(text);
            }
        }

        // For barcode elements - re-render when fitWidth or other properties change
        if (el.type === 'barcode') {
            // Store current CSS position before any updates
            const currentLeft = $el.css('left');
            const currentTop = $el.css('top');
            const currentWidth = $el.css('width');
            const currentHeight = $el.css('height');

            // Re-render barcode with updated properties
            $el.html(buildBarcodeHtml(el));
            $el.append('<div class="svld-el-resize"></div>');

            // CRITICAL: Restore position immediately to prevent jumping
            $el.css({
                left: currentLeft,
                top: currentTop,
                width: currentWidth,
                height: currentHeight
            });
        }

        // For QR code elements - re-render when fitWidth or other properties change
        if (el.type === 'qr') {
            // Store current CSS position before any updates
            const currentLeft = $el.css('left');
            const currentTop = $el.css('top');
            const currentWidth = $el.css('width');
            const currentHeight = $el.css('height');

            // Re-render QR code with updated properties
            $el.html(buildQrHtml(el));
            $el.append('<div class="svld-el-resize"></div>');

            // CRITICAL: Restore position immediately to prevent jumping
            $el.css({
                left: currentLeft,
                top: currentTop,
                width: currentWidth,
                height: currentHeight
            });
        }

        // For image elements - use updateImagePreview helper
        if (el.type === 'image') {
            // Store current CSS position before any updates
            const currentLeft = $el.css('left');
            const currentTop = $el.css('top');
            const currentWidth = $el.css('width');
            const currentHeight = $el.css('height');

            // Update image preview using helper
            updateImagePreview(el);

            // CRITICAL: Restore position immediately to prevent jumping
            $el.css({
                left: currentLeft,
                top: currentTop,
                width: currentWidth,
                height: currentHeight
            });
        }

        // Update position and size (convert mm to px for display) - reuse $el from line 2187
        if ($el.length) {
            $el.css({
                left: mmToPx(el.x) + 'px',
                top: mmToPx(el.y) + 'px',
                width: mmToPx(el.width) + 'px',
                height: mmToPx(el.height) + 'px',
            });

            // Update visibility
            $el.toggle(el.visible);

            // Keep data-source attribute in sync so CSS rules re-apply correctly
            $el.attr('data-source', el.type === 'image' ? (el.imageDataSource || 'custom') : (el.dataSource || ''));
        }

        // Update validation hints and data preview
        updateValidationHints(el);
        updateDataPreview(el);
    }

    // =========================================================================
    // Helper: Update Image Preview
    // =========================================================================
    function updateImagePreview(el) {
        const $el = $('#svld-canvas [data-id="' + el.id + '"]');
        if (!$el.length) return;

        let imgSrc = '';

        if (el.imageDataSource === 'product_image') {
            // Use SVG placeholder for product image in designer
            imgSrc = 'data:image/svg+xml,' + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><rect fill="#e8f4fd" width="100" height="100"/><text x="50" y="50" text-anchor="middle" dominant-baseline="middle" fill="#2271b1" font-size="10">Product</text><text x="50" y="62" text-anchor="middle" dominant-baseline="middle" fill="#2271b1" font-size="10">Image</text></svg>');
        } else if (el.imageDataSource === 'shop_logo') {
            imgSrc = 'data:image/svg+xml,' + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><rect fill="#f0f0f0" width="100" height="100"/><text x="50" y="55" text-anchor="middle" dominant-baseline="middle" fill="#666" font-size="10">Logo</text></svg>');
        } else {
            // Custom URL
            imgSrc = el.imageUrl || '';
        }

        // Apply fitWidth styling for images
        const imgStyle = el.fitWidth
            ? 'width:100%;height:100%;object-fit:contain;'
            : 'max-width:100%;max-height:100%;object-fit:contain;';

        const $img = $el.find('img');
        if (imgSrc) {
            if ($img.length) {
                $img.attr('src', imgSrc).attr('style', imgStyle).show();
            } else {
                $el.html('<img src="' + imgSrc + '" style="' + imgStyle + '" />');
            }
            $el.find('.svld-image-placeholder').remove();
        } else {
            if ($img.length) {
                $img.hide();
            }
            // Show placeholder icon
            if (!$el.find('.svld-image-placeholder').length) {
                $el.append('<div class="svld-image-placeholder"><span class="dashicons dashicons-format-image"></span></div>');
            }
            $el.find('.svld-image-placeholder').show();
        }
    }

    // =========================================================================
    // Drag, Resize, Multi-select, Rubber-band, Pan, Guides, Tooltip, Nudge
    // =========================================================================
    function initDragDrop() {

        // ---- Space key: pan mode ----
        $(document).on('keydown.svld', function (e) {
            if (e.key === ' ' && !$(e.target).is('input,textarea,select')) {
                e.preventDefault();
                spacePressed = true;
                $('.svld-canvas-wrapper').addClass('svld-panning');
            }
            // Keyboard nudge handled in initKeyboardNudge()
        }).on('keyup.svld', function (e) {
            if (e.key === ' ') {
                spacePressed = false;
                isPanning = false;
                $('.svld-canvas-wrapper').removeClass('svld-panning svld-panning-active');
            }
        });

        // ---- Middle-mouse pan start ----
        $('.svld-canvas-wrapper').on('mousedown', function (e) {
            if (e.which === 2) {
                e.preventDefault();
                isPanning = true;
                panStart  = { x: e.clientX, y: e.clientY,
                              sl: this.scrollLeft, st: this.scrollTop };
                $(this).addClass('svld-panning svld-panning-active');
            }
        });

        // ---- Resize handle mousedown ----
        $(document).on('mousedown', '.svld-el-resize', function (e) {
            e.preventDefault();
            e.stopPropagation();

            // Store the current selection state before starting resize
            const wasSelected = resizeEl && resizeEl.data('id') === selectedId;

            isResizing = true;
            resizeEl   = $(this).closest('.svld-el');
            const id   = resizeEl.data('id');

            // Store the element's current position BEFORE resize starts
            const el = layout.find(e => e.id === id);
            if (el) {
                resizeStart.originalX = el.x;
                resizeStart.originalY = el.y;
            }

            // DO NOT modify selection state or z-indices during resize
            // Only add visual indicator that we're resizing
            resizeEl.addClass('svld-resizing');

            // Store current dimensions
            const w = resizeEl.width();
            const h = resizeEl.height();
            resizeStart = { x: e.clientX, y: e.clientY, w, h,
                            aspectRatio: w / h, proportional: el && el.proportional,
                            originalX: resizeStart.originalX, originalY: resizeStart.originalY };
        });

        // ---- Element mousedown (drag or shift-click multi-select) ----
        $(document).on('mousedown', '.svld-el', function (e) {
            if ($(e.target).hasClass('svld-el-resize')) return;
            if (spacePressed) {
                // Space held → pan, not element drag
                isPanning = true;
                panStart  = { x: e.clientX, y: e.clientY,
                              sl: $('.svld-canvas-wrapper')[0].scrollLeft,
                              st: $('.svld-canvas-wrapper')[0].scrollTop };
                return;
            }
            e.preventDefault();
            e.stopPropagation(); // prevent canvas bg mousedown from firing

            const id = $(this).data('id');
            const $thisEl = $(this);

            console.log('[MOUSEDOWN] Element:', id, 'Shift:', e.shiftKey, 'selectedId:', selectedId);

            // CRITICAL FIX: Immediately elevate to top z-index to prevent getting stuck on other elements
            $thisEl.css('z-index', 99999);
            $thisEl.addClass('svld-dragging-active');

            // Selection is handled by click handler, not mousedown
            // Just track that we're starting a drag operation
            // Don't select here if Shift is pressed (for multi-select)
            if (!selectedId && !e.shiftKey) {
                // If nothing selected and not Shift+click, select this element now (for immediate drag)
                console.log('[MOUSEDOWN] Calling selectElement');
                selectElement(id);
            }

            isDragging = true;
            dragOffset = { x: e.clientX, y: e.clientY };
            $('body').addClass('svld-is-dragging'); // cursor feedback
        });

        // ---- Canvas background mousedown → rubber-band or deselect ----
        $('#svld-canvas').on('mousedown', function (e) {
            if ($(e.target).closest('.svld-el').length) return;
            if (spacePressed) return;
            e.preventDefault();

            if (!e.shiftKey) {
                deselectElement();
                multiSelected.clear();
                $('#svld-canvas .svld-el').removeClass('svld-multi-selected');
            }

            // Begin rubber-band — store start position in wrapper coordinates
            const wrapperRect = $('.svld-canvas-wrapper')[0].getBoundingClientRect();
            const wX = e.clientX - wrapperRect.left + $('.svld-canvas-wrapper')[0].scrollLeft;
            const wY = e.clientY - wrapperRect.top  + $('.svld-canvas-wrapper')[0].scrollTop;
            isRubberBanding = true;
            rubberStart     = { x: wX, y: wY }; // Now in wrapper coordinates

            $('#svld-rubber-band').css({ left: wX + 'px', top: wY + 'px', width: 0, height: 0 }).show();
        });

        // ---- mousemove: pan / rubber-band / drag / resize ----
        $(document).on('mousemove', function (e) {
            // Pan (space+drag or middle mouse)
            if (isPanning) {
                const $wrapper = $('.svld-canvas-wrapper');
                $wrapper[0].scrollLeft = panStart.sl - (e.clientX - panStart.x);
                $wrapper[0].scrollTop  = panStart.st - (e.clientY - panStart.y);
                $wrapper.addClass('svld-panning-active');
                return;
            }

            // Rubber-band multi-select
            if (isRubberBanding) {
                const wrapperRect = $('.svld-canvas-wrapper')[0].getBoundingClientRect();
                const curWX = e.clientX - wrapperRect.left + $('.svld-canvas-wrapper')[0].scrollLeft;
                const curWY = e.clientY - wrapperRect.top  + $('.svld-canvas-wrapper')[0].scrollTop;

                const x = Math.min(rubberStart.x, curWX);
                const y = Math.min(rubberStart.y, curWY);
                const w = Math.abs(curWX - rubberStart.x);
                const h = Math.abs(curWY - rubberStart.y);

                $('#svld-rubber-band').css({
                    left: x + 'px', top: y + 'px',
                    width: w + 'px', height: h + 'px',
                });
                return;
            }

            // Dragging element(s)
            if (isDragging) {
                // Screen-space delta → canvas-local delta (divide by zoom)
                const dx = (e.clientX - dragOffset.x) / canvasZoom;
                const dy = (e.clientY - dragOffset.y) / canvasZoom;
                dragOffset = { x: e.clientX, y: e.clientY };

                const rawW = labelW * MM_TO_PX;
                const rawH = labelH * MM_TO_PX;

                const ids = multiSelected.size > 1 ? Array.from(multiSelected) : (selectedId ? [selectedId] : []);

                ids.forEach(function (id) {
                    const $el = $('#svld-canvas [data-id="' + id + '"]');
                    if (!$el.length) return;

                    // Calculate new position without constraints - allow free movement anywhere
                    let newL = (parseFloat($el.css('left')) || 0) + dx;
                    let newT = (parseFloat($el.css('top'))  || 0) + dy;

                    if (ids.length === 1) {
                        // Alignment guides + snap (no boundary constraints)
                        const elW = $el.outerWidth();
                        const elH = $el.outerHeight();
                        const guided = updateAlignmentGuides(id, newL, newT, elW, elH);
                        newL = guided.left;
                        newT = guided.top;

                        // Snap to 0.5mm grid ONLY if enabled (live preview, no jerky movement)
                        if (snapEnabled) {
                            newL = mmToPx(Math.round(pxToMm(newL) * 2) / 2);
                            newT = mmToPx(Math.round(pxToMm(newT) * 2) / 2);
                            $el.addClass('svld-snapping');
                        } else {
                            $el.removeClass('svld-snapping');
                        }

                        // Show position/size tooltip
                        showDragTooltip(e.clientX, e.clientY,
                            pxToMm(newL), pxToMm(newT),
                            pxToMm(elW),  pxToMm(elH));
                    }

                    // No boundary constraints - elements can be positioned anywhere (including off-canvas or overlapping)
                    $el.css({ left: newL + 'px', top: newT + 'px' });
                });
            }

            // Resizing
            // Resizing
            if (isResizing && resizeEl) {
                const dx = (e.clientX - resizeStart.x) / canvasZoom;
                const dy = (e.clientY - resizeStart.y) / canvasZoom;

                let newW = Math.max(mmToPx(5), resizeStart.w + dx);
                let newH = Math.max(mmToPx(3), resizeStart.h + dy);

                // Aspect ratio lock (Shift key or element property)
                if (resizeStart.proportional || e.shiftKey) {
                    const wRatio = newW / resizeStart.w;
                    const hRatio = newH / resizeStart.h;
                    if (wRatio > hRatio) { newH = newW / resizeStart.aspectRatio; }
                    else                 { newW = newH * resizeStart.aspectRatio; }
                    newW = Math.max(mmToPx(5), newW);
                    newH = Math.max(mmToPx(3), newH);
                }

                // CRITICAL: Store current positions of ALL elements before resize
                // This helps us detect if any element is being affected
                const allPositions = {};
                $('#svld-canvas .svld-el').each(function() {
                    const id = $(this).data('id');
                    allPositions[id] = {
                        left: parseFloat($(this).css('left')) || 0,
                        top: parseFloat($(this).css('top')) || 0
                    };
                });

                // CRITICAL: Only modify width/height - DO NOT touch position
                // Use inline style directly to avoid any layout recalculations
                resizeEl[0].style.width = newW + 'px';
                resizeEl[0].style.height = newH + 'px';

                // Verify no other elements moved (for debugging)
                $('#svld-canvas .svld-el').each(function() {
                    const id = $(this).data('id');
                    if (id === resizeEl.data('id')) return; // Skip the element being resized

                    const currentLeft = parseFloat($(this).css('left')) || 0;
                    const currentTop = parseFloat($(this).css('top')) || 0;
                    const originalLeft = allPositions[id].left;
                    const originalTop = allPositions[id].top;

                    // If any element moved, restore it immediately
                    if (Math.abs(currentLeft - originalLeft) > 0.1) {
                        this.style.left = originalLeft + 'px';
                    }
                    if (Math.abs(currentTop - originalTop) > 0.1) {
                        this.style.top = originalTop + 'px';
                    }
                });

                // Update position tooltip with current element position (not original position)
                const elLeft = parseFloat(resizeEl.css('left')) || 0;
                const elTop  = parseFloat(resizeEl.css('top'))  || 0;
                showDragTooltip(e.clientX, e.clientY,
                    pxToMm(elLeft), pxToMm(elTop), pxToMm(newW), pxToMm(newH));
            }
        });

        // ---- mouseup: commit all operations ----
        $(document).on('mouseup', function () {
            if (isPanning) {
                isPanning = false;
                if (!spacePressed) {
                    $('.svld-canvas-wrapper').removeClass('svld-panning svld-panning-active');
                }
            }

            if (isRubberBanding) {
                isRubberBanding = false;
                finishRubberBand();
                $('#svld-rubber-band').hide();
            }

            if (isDragging) {
                // Restore z-indices after drag completes
                $('#svld-canvas .svld-el').each(function() {
                    const $el = $(this);
                    const elId = $el.data('id');
                    const el = layout.find(e => e.id === elId);
                    // Restore element's own z-index
                    const zIndex = (el && el.zIndex !== undefined) ? el.zIndex : 1;
                    $el.css('z-index', zIndex).removeClass('svld-dragging-active');
                });

                const ids = multiSelected.size > 1
                    ? Array.from(multiSelected)
                    : (selectedId ? [selectedId] : []);
                ids.forEach(syncElPositionToLayout);
                $('#svld-guides-container').empty();
                $('body').removeClass('svld-is-dragging'); // remove cursor feedback
                saveToHistory(ids.length > 1 ? 'Move ' + ids.length + ' Elements' : 'Move Element');
            }

            if (isResizing && resizeEl) {
                const id = resizeEl.data('id');
                const el = layout.find(e => e.id === id);

                // CRITICAL: Ensure position hasn't changed during resize
                if (el && resizeStart.originalX !== undefined && resizeStart.originalY !== undefined) {
                    // Verify element is still at original position
                    const currentLeft = parseFloat(resizeEl.css('left')) || 0;
                    const currentTop = parseFloat(resizeEl.css('top')) || 0;
                    const expectedLeft = mmToPx(el.x);
                    const expectedTop = mmToPx(el.y);

                    // If position drifted, restore it
                    if (Math.abs(currentLeft - expectedLeft) > 0.5) {
                        resizeEl.css('left', expectedLeft + 'px');
                    }
                    if (Math.abs(currentTop - expectedTop) > 0.5) {
                        resizeEl.css('top', expectedTop + 'px');
                    }
                }

                syncElSizeToLayout(id);
                resizeEl.removeClass('svld-resizing');
                saveToHistory('Resize Element');
            }

            isDragging = false;
            isResizing = false;
            resizeEl   = null;
            hideDragTooltip();
        });
    }

    // ---- Multi-select helpers ----
    function toggleMultiSelect(id) {
        if (multiSelected.has(id)) {
            // Element is already in multi-select, remove it
            multiSelected.delete(id);
            $('#svld-canvas [data-id="' + id + '"]').removeClass('svld-multi-selected');

            // If only one element left, convert to single select
            if (multiSelected.size === 1) {
                const lastId = Array.from(multiSelected)[0];
                multiSelected.clear();
                $('#svld-canvas .svld-el').removeClass('svld-multi-selected');
                selectElement(lastId);
            }
        } else {
            // Add element to multi-select
            // First, add the currently selected element (if different) to multi-select
            if (selectedId && selectedId !== id && !multiSelected.has(selectedId)) {
                multiSelected.add(selectedId);
                $('#svld-canvas [data-id="' + selectedId + '"]').addClass('svld-multi-selected');
            }
            // Then add the newly clicked element
            multiSelected.add(id);
            $('#svld-canvas [data-id="' + id + '"]').addClass('svld-multi-selected');
            selectedId = id;
            showProperties(id);
        }
    }

    function finishRubberBand() {
        const $rb   = $('#svld-rubber-band');
        const rbW   = parseFloat($rb.css('width'))  || 0;
        const rbH   = parseFloat($rb.css('height')) || 0;

        if (rbW < 3 && rbH < 3) {
            return; // tiny click, skip
        }

        // Get the actual position of the rubber band div (in wrapper coords)
        const rbDivLeft = parseFloat($rb.css('left')) || 0;
        const rbDivTop = parseFloat($rb.css('top')) || 0;

        // The canvas has 25px margin for rulers, plus 15px gap to rulers
        const canvasMargin = 40; // 25px for ruler + 15px gap

        // Convert wrapper coordinates to canvas-local coordinates
        // Subtract margin to account for canvas ruler offset, then divide by zoom
        const rbLeft   = (rbDivLeft - canvasMargin) / canvasZoom;
        const rbTop    = (rbDivTop - canvasMargin) / canvasZoom;
        const rbRight  = rbLeft + rbW / canvasZoom;
        const rbBottom = rbTop  + rbH / canvasZoom;


        multiSelected.clear();
        let selectedCount = 0;
        layout.forEach(function (el) {
            if (!el.visible) return;
            const eL = mmToPx(el.x), eT = mmToPx(el.y);
            const eR = eL + mmToPx(el.width), eB = eT + mmToPx(el.height);
            const inside = eR > rbLeft && eL < rbRight && eB > rbTop && eT < rbBottom;
            if (inside) {
                multiSelected.add(el.id);
                selectedCount++;
            }
        });

        if (multiSelected.size === 1) {
            const id = Array.from(multiSelected)[0];
            multiSelected.clear();
            selectElement(id);
        } else if (multiSelected.size > 1) {
            selectedId = Array.from(multiSelected)[0];
            multiSelected.forEach(function (id) {
                $('#svld-canvas [data-id="' + id + '"]').addClass('svld-multi-selected');
            });
            showProperties(selectedId);
            renderLayersList();
        }

        // Set flag to prevent click event from deselecting immediately
        justFinishedRubberBand = true;
        setTimeout(function() { justFinishedRubberBand = false; }, 100);
    }

    // ---- Alignment guides ----
    function updateAlignmentGuides(dragId, newLeft, newTop, dragW, dragH) {
        const $guides   = $('#svld-guides-container');
        const tolerance = 3; // px (canvas-local)
        let snapL = null, snapT = null;

        const de = {
            l: newLeft, r: newLeft + dragW, cx: newLeft + dragW / 2,
            t: newTop,  b: newTop  + dragH, cy: newTop  + dragH / 2,
        };

        $guides.empty();

        layout.forEach(function (el) {
            if (el.id === dragId || !el.visible) return;
            const oL = mmToPx(el.x), oT = mmToPx(el.y);
            const oR = oL + mmToPx(el.width), oB = oT + mmToPx(el.height);
            const oCX = (oL + oR) / 2, oCY = (oT + oB) / 2;

            // Vertical guide candidates (snap X)
            [{ d: de.l, o: oL }, { d: de.l, o: oR }, { d: de.r, o: oL },
             { d: de.r, o: oR }, { d: de.cx, o: oCX }].forEach(function (c) {
                if (Math.abs(c.d - c.o) <= tolerance) {
                    $guides.append('<div class="svld-guide svld-guide-v" style="left:' + c.o + 'px"></div>');
                    if (snapL === null) snapL = newLeft + (c.o - c.d);
                }
            });

            // Horizontal guide candidates (snap Y)
            [{ d: de.t, o: oT }, { d: de.t, o: oB }, { d: de.b, o: oT },
             { d: de.b, o: oB }, { d: de.cy, o: oCY }].forEach(function (c) {
                if (Math.abs(c.d - c.o) <= tolerance) {
                    $guides.append('<div class="svld-guide svld-guide-h" style="top:' + c.o + 'px"></div>');
                    if (snapT === null) snapT = newTop + (c.o - c.d);
                }
            });
        });

        return { left: snapL !== null ? snapL : newLeft, top: snapT !== null ? snapT : newTop };
    }

    // ---- Drag tooltip ----
    function showDragTooltip(clientX, clientY, x, y, w, h) {
        // Values come in mm, convert to display unit
        const dx = mmToDisplayUnit(x);
        const dy = mmToDisplayUnit(y);
        const dw = mmToDisplayUnit(w);
        const dh = mmToDisplayUnit(h);
        $('#svld-drag-tooltip')
            .text('X: ' + dx.toFixed(1) + ' ' + unitLabel + '  Y: ' + dy.toFixed(1) +
                  ' ' + unitLabel + '  W: ' + dw.toFixed(1) + ' ' + unitLabel + '  H: ' + dh.toFixed(1) + ' ' + unitLabel)
            .css({ left: (clientX + 16) + 'px', top: (clientY - 28) + 'px' })
            .show();
    }
    function hideDragTooltip() { $('#svld-drag-tooltip').hide(); }

    // ---- Grid overlay ----
    function drawGrid() {
        const $overlay = $('#svld-grid-overlay');
        if (!showGrid) { $overlay.hide(); return; }
        const W = labelW * MM_TO_PX;
        const H = labelH * MM_TO_PX;
        let lines = '';
        for (let mm = 0; mm <= labelW; mm++) {
            const x  = mm * MM_TO_PX;
            const sw = mm % 10 === 0 ? 0.8 : mm % 5 === 0 ? 0.5 : 0.3;
            const op = mm % 10 === 0 ? 0.25 : mm % 5 === 0 ? 0.14 : 0.07;
            lines += '<line x1="' + x + '" y1="0" x2="' + x + '" y2="' + H +
                     '" stroke="rgba(0,0,0,' + op + ')" stroke-width="' + sw + '"/>';
        }
        for (let mm = 0; mm <= labelH; mm++) {
            const y  = mm * MM_TO_PX;
            const sw = mm % 10 === 0 ? 0.8 : mm % 5 === 0 ? 0.5 : 0.3;
            const op = mm % 10 === 0 ? 0.25 : mm % 5 === 0 ? 0.14 : 0.07;
            lines += '<line x1="0" y1="' + y + '" x2="' + W + '" y2="' + y +
                     '" stroke="rgba(0,0,0,' + op + ')" stroke-width="' + sw + '"/>';
        }
        $overlay.html('<svg xmlns="http://www.w3.org/2000/svg" width="' + W + '" height="' + H +
                      '" style="position:absolute;inset:0;pointer-events:none;">' + lines + '</svg>').show();
    }

    // ---- Keyboard nudge ----
    function initKeyboardNudge() {
        $(document).on('keydown.svld-nudge', function (e) {
            // Undo/Redo shortcuts
            if ((e.ctrlKey || e.metaKey) && e.key === 'z') {
                e.preventDefault();
                if (e.shiftKey) {
                    performRedo();
                } else {
                    performUndo();
                }
                return;
            }
            if ((e.ctrlKey || e.metaKey) && e.key === 'y') {
                e.preventDefault();
                performRedo();
                return;
            }

            // Delete/Backspace to remove element
            if ((e.key === 'Delete' || e.key === 'Backspace') && selectedId) {
                if ($(e.target).is('input,textarea,select')) return;
                e.preventDefault();
                // Pro check for delete
                if (!isPro) {
                    // Show tooltip near the selected element
                    const $selectedEl = $('.svld-el[data-id="' + selectedId + '"]');
                    if ($selectedEl.length) {
                        showProTooltip($selectedEl);
                    }
                    return;
                }
                removeSelected();
                return;
            }

            // Arrow key nudge
            if (!selectedId) return;
            if ($(e.target).is('input,textarea,select')) return;
            const DIRS = { ArrowLeft:'x', ArrowRight:'x', ArrowUp:'y', ArrowDown:'y' };
            if (!DIRS[e.key]) return;
            e.preventDefault();

            let step = 1;
            if (e.shiftKey) step = 0.1;
            if (e.ctrlKey || e.metaKey) step = 5;
            const sign = (e.key === 'ArrowRight' || e.key === 'ArrowDown') ? 1 : -1;
            const axis = DIRS[e.key];

            const el = layout.find(el => el.id === selectedId);
            if (!el) return;

            el[axis] = +(el[axis] + sign * step).toFixed(2);

            const $el = $('#svld-canvas [data-id="' + selectedId + '"]');
            if (axis === 'x') $el.css('left', mmToPx(el.x) + 'px');
            else              $el.css('top',  mmToPx(el.y) + 'px');

            $('#svld-prop-' + axis).val(mmToDisplayUnit(el[axis]).toFixed(1));
        });
    }

    function syncElPositionToLayout(id) {
        const $el = $('#svld-canvas [data-id="' + id + '"]');
        const el  = layout.find(e => e.id === id);
        if (!el || !$el.length) return;

        // FIX: Read CSS left/top directly - NOT affected by zoom transform
        const leftPx = parseFloat($el.css('left')) || 0;
        const topPx  = parseFloat($el.css('top'))  || 0;

        // Convert to mm with high precision
        let newX = pxToMm(leftPx);
        let newY = pxToMm(topPx);

        // Apply snap-to-grid if enabled
        if (snapEnabled) {
            newX = Math.round(newX * 2) / 2;
            newY = Math.round(newY * 2) / 2;
            // Show snapping indicator
            $el.addClass('svld-snapping');
            setTimeout(() => $el.removeClass('svld-snapping'), 200);
        }

        // Update position (allow negative values for elements outside canvas)
        el.x = newX;
        el.y = newY;

        $('#svld-prop-x').val(mmToDisplayUnit(el.x).toFixed(1));
        $('#svld-prop-y').val(mmToDisplayUnit(el.y).toFixed(1));

        // Update layers list
        renderLayersList();
    }

    function syncElSizeToLayout(id) {
        const $el = $('#svld-canvas [data-id="' + id + '"]');
        const el  = layout.find(e => e.id === id);
        if (!el || !$el.length) return;

        // FIX: Read CSS width/height directly - NOT affected by zoom transform
        const widthPx  = parseFloat($el.css('width'))  || mmToPx(30);
        const heightPx = parseFloat($el.css('height')) || mmToPx(10);

        el.width  = pxToMm(widthPx);
        el.height = pxToMm(heightPx);

        $('#svld-prop-width').val(mmToDisplayUnit(el.width).toFixed(1));
        $('#svld-prop-height').val(mmToDisplayUnit(el.height).toFixed(1));
    }

    // =========================================================================
    // Canvas size  (CSS-transform zoom approach)
    // =========================================================================
    function updateCanvasSize() {
        const $wrapper = $('.svld-canvas-wrapper');
        const rawW = labelW * MM_TO_PX;
        const rawH = labelH * MM_TO_PX;
        const $canvas = $('#svld-canvas');

        // Preserve scroll center point during zoom
        const oldScrollLeft = $wrapper.scrollLeft();
        const oldScrollTop = $wrapper.scrollTop();
        const wrapperW = $wrapper.width();
        const wrapperH = $wrapper.height();

        // Calculate center point in canvas coordinates before zoom
        const centerCanvasX = (oldScrollLeft + wrapperW / 2) / (canvasZoom || 1);
        const centerCanvasY = (oldScrollTop + wrapperH / 2) / (canvasZoom || 1);

        // Canvas is always at physical size — zoom is a pure CSS visual scale.
        $canvas.css({
            width:  rawW + 'px',
            height: rawH + 'px',
            transform: 'scale(' + canvasZoom + ')',
            transformOrigin: 'top left',
        });

        // Scale-host provides the correct scrollable area for the wrapper.
        // Canvas has margin: 15px on all sides (rulers are now in their own grid cells).
        const canvasMargin = 30; // 15px on each side
        $('#svld-canvas-scale-host').css({
            width:  Math.ceil(rawW * canvasZoom) + canvasMargin + 'px',
            height: Math.ceil(rawH * canvasZoom) + canvasMargin + 'px',
        });

        // Restore scroll position to maintain center point
        const newScrollLeft = centerCanvasX * canvasZoom - wrapperW / 2;
        const newScrollTop = centerCanvasY * canvasZoom - wrapperH / 2;
        $wrapper.scrollLeft(Math.max(0, newScrollLeft));
        $wrapper.scrollTop(Math.max(0, newScrollTop));

        $('#svld-zoom-level').text(Math.round(canvasZoom * 100) + '%');
        // Update canvas size display with dynamic unit label
        const displayW = mmToDisplayUnit(labelW);
        const displayH = mmToDisplayUnit(labelH);
        $('.svld-canvas-size-value').text(displayW + ' × ' + displayH);

        if (showGrid) drawGrid();
        drawRulers();
        renderCanvas();
        updateResizeHandlePosition();
    }

    // Draw rulers showing measurements in current unit
    function drawRulers() {
        const $rh = $('#svld-ruler-h .svld-ruler-marks');
        const $rv = $('#svld-ruler-v .svld-ruler-marks');
        if (!$rh.length || !$rv.length) return;

        // Clear existing marks
        $rh.empty();
        $rv.empty();

        // Draw horizontal ruler marks (mm-based for cleaner display)
        const canvasPixelW = labelW * MM_TO_PX * canvasZoom;
        const canvasPixelH = labelH * MM_TO_PX * canvasZoom;
        const pxPerMm = MM_TO_PX * canvasZoom;

        // FIXED step size: use consistent 10mm intervals at all zoom levels
        // This ensures ruler always shows 10, 20, 30, 40... regardless of zoom
        const stepInMm = 10; // Always use 10mm steps
        const pxPerStep = stepInMm * pxPerMm;

        // For major marks, show every 10 steps (every 100mm)
        const majorMarkInterval = 10;

        // Format value for display
        function formatValue(mmValue) {
            if (currentUnit === 'mm') {
                return Math.round(mmValue);
            } else if (currentUnit === 'cm') {
                return (mmValue / 10).toFixed(0);
            } else if (currentUnit === 'in') {
                const inches = mmValue / 25.4;
                const wholeInch = Math.floor(inches);
                const fraction = inches - wholeInch;
                if (fraction < 0.01) return wholeInch + '"';
                if (Math.abs(fraction - 0.5) < 0.01) return wholeInch + '½"';
                return wholeInch + '"';
            } else { // pt
                return Math.round(mmValue / 0.352778);
            }
        }

        // Convert mm value to current unit for display
        function mmToUnit(mmValue) {
            if (currentUnit === 'mm') {
                return mmValue;
            } else if (currentUnit === 'cm') {
                return mmValue / 10;
            } else if (currentUnit === 'in') {
                return mmValue / 25.4;
            } else { // pt
                return mmValue / 0.352778;
            }
        }

        // Get the base step size in millimeters for the current unit
        function getBaseStepInMm() {
            if (currentUnit === 'mm') {
                return 1; // 1mm
            } else if (currentUnit === 'cm') {
                return 10; // 1cm = 10mm
            } else if (currentUnit === 'in') {
                return 25.4 / 16; // 1/16 inch
            } else { // pt
                return 25.4 / 72; // 1pt = 1/72 inch
            }
        }

        // Rulers are now OUTSIDE the scrollable wrapper (in a CSS grid).
        // Canvas has margin: 15px inside the wrapper.
        // Origin (0mm mark) is at: 15px - scrollOffset from the ruler's left/top edge.
        const $wrapper     = $('.svld-canvas-wrapper');
        const scrollLeft   = $wrapper.scrollLeft();
        const scrollTop    = $wrapper.scrollTop();
        const canvasMargin = 15; // matches .svld-canvas { margin: 15px }
        const originH      = canvasMargin - scrollLeft; // x of 0mm on horizontal ruler
        const originV      = canvasMargin - scrollTop;  // y of 0mm on vertical ruler
        const rulerW       = $('#svld-ruler-h').width()  || 600;
        const rulerH       = $('#svld-ruler-v').height() || 400;

        // Draw horizontal marks
        for (let pos = 0; pos <= canvasPixelW; pos += pxPerStep) {
            const markPos = originH + pos;
            if (markPos < -20 || markPos > rulerW + 5) continue; // outside visible ruler
            const mmValue   = Math.round(pos / pxPerMm);
            const unitValue = mmToUnit(mmValue);
            const isMajor   = (unitValue % majorMarkInterval === 0);
            const isMedium  = (unitValue % 10 === 0) && !isMajor;

            const mark = $('<div>').addClass('svld-ruler-mark').css({
                left:    markPos + 'px',
                top:     '0',
                width:   isMajor ? '2px' : '1px',
                height:  isMajor ? '14px' : (isMedium ? '10px' : '6px'),
                opacity: isMajor ? 1 : (isMedium ? 0.7 : 0.4),
            });

            if (isMajor) {
                mark.addClass('major');
                const label = $('<div>').addClass('svld-ruler-label').text(formatValue(mmValue)).css({
                    left: (markPos + 3) + 'px',
                    top:  '14px',
                });
                $rh.append(label);
            } else if (isMedium) {
                mark.addClass('medium');
            }
            $rh.append(mark);
        }

        // Draw vertical marks
        for (let pos = 0; pos <= canvasPixelH; pos += pxPerStep) {
            const markPos = originV + pos;
            if (markPos < -20 || markPos > rulerH + 5) continue; // outside visible ruler
            const mmValue   = Math.round(pos / pxPerMm);
            const unitValue = mmToUnit(mmValue);
            const isMajor   = (unitValue % majorMarkInterval === 0);
            const isMedium  = (unitValue % 10 === 0) && !isMajor;

            const mark = $('<div>').addClass('svld-ruler-mark').css({
                top:     markPos + 'px',
                left:    '0',
                height:  isMajor ? '2px' : '1px',
                width:   isMajor ? '14px' : (isMedium ? '10px' : '6px'),
                opacity: isMajor ? 1 : (isMedium ? 0.7 : 0.4),
            });

            if (isMajor) {
                mark.addClass('major');
                const label = $('<div>').addClass('svld-ruler-label').text(formatValue(mmValue)).css({
                    top:              (markPos + 3) + 'px',
                    left:             '14px',
                    transform:        'rotate(-90deg)',
                    'transform-origin': 'left top',
                });
                $rv.append(label);
            } else if (isMedium) {
                mark.addClass('medium');
            }
            $rv.append(mark);
        }

        // Rulers are sized by the CSS grid — no dynamic width/height needed.
    }

    // Fit canvas to the visible wrapper area — called on first load and after label resize
    function fitCanvasToWrapper() {
        const $wrapper = $('.svld-canvas-wrapper');
        const pad = 96;
        const wW  = ($wrapper.width()  || 600) - pad;
        const wH  = ($wrapper.height() || 400) - pad;
        const rawW = labelW * MM_TO_PX;
        const rawH = labelH * MM_TO_PX;
        const scale = Math.min(wW / rawW, wH / rawH, 2.0);
        // Minimum 60% zoom so elements aren't too tiny to click
        canvasZoom = Math.max(0.60, Math.round(scale * 20) / 20);
        updateCanvasSize();
    }

    // Re-fit on window resize
    $(window).on('resize', function() {
        fitCanvasToWrapper();
    });

    // Redraw rulers when canvas area is scrolled so marks track canvas position
    $('.svld-canvas-wrapper').on('scroll', function() {
        drawRulers();
    });

    // =========================================================================
    // Custom canvas wrapper resize handle — positioned at wrapper's visible corner
    // =========================================================================
    function updateResizeHandlePosition() {
        const $wrapper = $('.svld-canvas-wrapper');
        const $handle  = $('#svld-canvas-resize-handle');
        const $panel   = $wrapper.closest('.svld-canvas-panel');
        if (!$wrapper.length || !$handle.length || !$panel.length) return;

        const wrapperPos = $wrapper.position(); // relative to panel
        $handle.css({
            top:  (wrapperPos.top  + $wrapper.outerHeight() - 18) + 'px',
            left: (wrapperPos.left + $wrapper.outerWidth()  - 18) + 'px',
        });
    }

    (function() {
        let isResizingWrapper = false;
        let wrapperResizeStart = {};

        $(document).on('mousedown', '#svld-canvas-resize-handle', function(e) {
            e.preventDefault();
            e.stopPropagation();
            const $wrapper = $('.svld-canvas-wrapper');
            isResizingWrapper = true;
            wrapperResizeStart = {
                x: e.clientX,
                y: e.clientY,
                w: $wrapper.width(),
                h: $wrapper.height(),
            };
            $('body').css('cursor', 'nwse-resize').addClass('svld-resizing-wrapper');
        });

        $(document).on('mousemove.wrapperResize', function(e) {
            if (!isResizingWrapper) return;
            const dx = e.clientX - wrapperResizeStart.x;
            const dy = e.clientY - wrapperResizeStart.y;
            const newW = Math.max(300, wrapperResizeStart.w + dx);
            const newH = Math.max(200, wrapperResizeStart.h + dy);
            $('.svld-canvas-wrapper').css({ width: newW + 'px', height: newH + 'px' });
            updateResizeHandlePosition();
        });

        $(document).on('mouseup.wrapperResize', function(e) {
            if (!isResizingWrapper) return;
            isResizingWrapper = false;
            $('body').css('cursor', '').removeClass('svld-resizing-wrapper');
            fitCanvasToWrapper();
        });
    })();

    // =========================================================================
    // Save layout - Only 1 layout allowed, unlimited saves to it
    // =========================================================================
    function saveLayout() {
        // Get the single saved layout ID from localStorage
        let singleTemplateId = localStorage.getItem('svld_single_template_id');

        // If no layout saved yet, create new one with fixed name "label"
        if (!singleTemplateId) {
            saveAsTemplateWithName('label');
            return;
        }

        // Otherwise, save to the existing single template (overwrite)
        const $status = $('#svld-save-status');
        $status.removeClass('error').text('Saving…');

        $.post(svld_params.ajax_url, {
            action:       svld_params.save_layout_action,
            nonce:        svld_params.nonce,
            layout:       JSON.stringify(layout),
            label_width:  labelW,
            label_height: labelH,
            label_type:   currentLabelType,
            template_id:  singleTemplateId,
        }, function (res) {
            if (res.success) {
                $status.text('✓ Saved');
                setTimeout(function () { $status.text(''); }, 3000);
            } else {
                $status.addClass('error').text('Error: ' + (res.data && res.data.message ? res.data.message : 'save failed'));
            }
        }).fail(function () {
            $status.addClass('error').text('Server error. Try again.');
        });
    }

    function saveAsTemplateWithName(templateName, labelType) {
        const $status = $('#svld-save-status');
        $status.removeClass('error').text('Saving template…');

        $.post(svld_params.ajax_url, {
            action: 'svld_save_template',
            nonce: svld_params.nonce,
            template_name: templateName,
            template_id: currentTemplateId === 'current' ? '' : currentTemplateId,
            label_type: labelType || currentLabelType || '',
            layout: JSON.stringify(layout),
            label_width: labelW,
            label_height: labelH,
        }, function(res) {
            if (res.success) {
                // Update currentTemplateId to the newly created template
                if (res.data && res.data.template_id) {
                    currentTemplateId = res.data.template_id;
                    // Store as the single template for this user
                    localStorage.setItem('svld_single_template_id', res.data.template_id);
                }
                $status.text('✓ Template saved');
                loadTemplatesList(function() {
                    $('#svld-template-select').val(currentTemplateId);
                    $('#svld-load-template').prop('disabled', false);
                });
                setTimeout(function () { $status.text(''); }, 3000);
            } else {
                $status.addClass('error').text('Error: ' + (res.data && res.data.message ? res.data.message : 'save failed'));
            }
        }).fail(function () {
            $status.addClass('error').text('Server error. Try again.');
        });
    }

    // =========================================================================
    // Template Management
    // =========================================================================
    function loadTemplatesList(callback) {
        $.post(svld_params.ajax_url, {
            action: 'svld_list_templates',
            nonce: svld_params.nonce,
        }, function(res) {
            if (res.success && res.data.templates) {
                updateTemplateDropdown(res.data.templates);
                // Auto-load default or last used template
                autoLoadTemplate(res.data.templates);
                if (typeof callback === 'function') callback();
            }
        });
    }

    // Auto-load default template or last used template from localStorage
    function autoLoadTemplate(templates) {
        // Check if there's a last used template in localStorage
        const lastTemplateId = localStorage.getItem('svld_last_template');
        const defaultTemplateId = svld_params.default_template || '';

        // Determine which template to load
        let templateToLoad = null;

        if (lastTemplateId) {
            // Check if last template still exists
            const lastTemplate = templates.find(t => t.id === lastTemplateId);
            if (lastTemplate) {
                templateToLoad = lastTemplateId;
            }
        }

        // Fall back to default template if no last template or it doesn't exist
        if (!templateToLoad && defaultTemplateId) {
            const defaultTemplate = templates.find(t => t.id === defaultTemplateId);
            if (defaultTemplate) {
                templateToLoad = defaultTemplateId;
            }
        }

        // Load the template if found
        if (templateToLoad) {
            $('#svld-template-select').val(templateToLoad);
            loadSelectedTemplate();
        }
    }

    function updateTemplateDropdown(templates) {
        const $select = $('#svld-template-select');
        $select.find('option:not([value="current"])').remove();

        templates.forEach(function(tpl) {
            const typePrefix = tpl.label_type && TYPE_LABELS[tpl.label_type]
                ? TYPE_LABELS[tpl.label_type] + ' — '
                : '';
            const label = typePrefix + tpl.name + (tpl.is_default ? ' ★' : '');
            $select.append('<option value="' + tpl.id + '"' + (tpl.is_default ? ' data-default="1"' : '') + '>' + label + '</option>');
        });
    }

    function updateTemplateSelector() {
        $('#svld-template-select').val('current');
        $('#svld-load-template').prop('disabled', true);
    }

    // =========================================================================
    // Save Template Modal (replaces prompt)
    // =========================================================================
    let currentLabelType = '';

    function openSaveTemplateModal() {
        if (!isPro) {
            const $saveBtn = $('#svld-save-template');
            if ($saveBtn.length) {
                showProTooltip($saveBtn);
            }
            return;
        }
        const existingName = currentTemplateId && currentTemplateId !== 'current'
            ? ($('#svld-template-select option[value="' + currentTemplateId + '"]').text().replace(' (Default)', '').trim())
            : '';

        const modalHtml = `
            <div class="svld-modal-overlay" id="svld-save-modal-overlay">
                <div class="svld-modal">
                    <h2 class="svld-modal-title">Save Template</h2>
                    <div class="svld-modal-body">
                        <div class="svld-modal-field">
                            <label for="svld-tpl-name-input">Template Name</label>
                            <input type="text" id="svld-tpl-name-input" class="regular-text" value="${existingName}" placeholder="e.g. My Product Label">
                        </div>
                        <div class="svld-modal-field">
                            <label for="svld-tpl-type-select">Label Type</label>
                            <select id="svld-tpl-type-select">
                                <option value="">— General —</option>
                                <option value="product"  ${currentLabelType === 'product'  ? 'selected' : ''}>🏷️ Product Label</option>
                                <option value="shipping" ${currentLabelType === 'shipping' ? 'selected' : ''}>📦 Shipping Label</option>
                                <option value="invoice"  ${currentLabelType === 'invoice'  ? 'selected' : ''}>🧾 Invoice Label</option>
                                <option value="return"   ${currentLabelType === 'return'   ? 'selected' : ''}>↩️ Return Label</option>
                            </select>
                        </div>
                    </div>
                    <div class="svld-modal-footer">
                        <button type="button" id="svld-save-modal-confirm" class="button button-primary">Save</button>
                        <button type="button" id="svld-save-modal-cancel" class="button">Cancel</button>
                    </div>
                </div>
            </div>`;

        $(modalHtml).appendTo('body');
        $('#svld-tpl-name-input').trigger('focus').select();

        $('#svld-save-modal-confirm').on('click', function() {
            const name = $('#svld-tpl-name-input').val().trim();
            const type = $('#svld-tpl-type-select').val();
            if (!name) {
                $('#svld-tpl-name-input').css('border-color', '#dc3232').trigger('focus');
                return;
            }
            currentLabelType = type;
            $('#svld-save-modal-overlay').remove();
            saveAsTemplateWithName(name, type);
        });

        $('#svld-save-modal-cancel, #svld-save-modal-overlay').on('click', function(e) {
            if (e.target === this) $('#svld-save-modal-overlay').remove();
        });

        // Enter key submits
        $('#svld-tpl-name-input').on('keydown', function(e) {
            if (e.key === 'Enter') $('#svld-save-modal-confirm').trigger('click');
            if (e.key === 'Escape') $('#svld-save-modal-overlay').remove();
        });
    }

    // =========================================================================
    // New from Preset chooser
    // =========================================================================
    function openPresetChooser() {
        if (!isPro) {
            const $presetBtn = $('#svld-new-preset');
            if ($presetBtn.length) {
                showProTooltip($presetBtn);
            }
            return;
        }
        const presets = [
            { key: 'product',  icon: '🏷️', name: 'Product Label',  desc: '100×50 mm — Name, barcode, QR, price' },
            { key: 'shipping', icon: '📦', name: 'Shipping Label',  desc: '100×150 mm — Recipient, address, barcode, QR' },
            { key: 'invoice',  icon: '🧾', name: 'Invoice Label',   desc: '210×297 mm (A4) — Order, billing, shipping, total' },
            { key: 'return',   icon: '↩️', name: 'Return Label',    desc: '100×100 mm — Customer, order #, QR code' },
        ];

        let cards = presets.map(p => `
            <div class="svld-preset-card" data-key="${p.key}">
                <div class="svld-preset-icon">${p.icon}</div>
                <div class="svld-preset-info">
                    <strong>${p.name}</strong>
                    <span>${p.desc}</span>
                </div>
            </div>`).join('');

        const modalHtml = `
            <div class="svld-modal-overlay" id="svld-preset-modal-overlay">
                <div class="svld-modal svld-modal-wide">
                    <h2 class="svld-modal-title">New from Preset</h2>
                    <p class="svld-modal-subtitle">Choose a starting template. This will replace your current canvas.</p>
                    <div class="svld-preset-grid">${cards}</div>
                    <div class="svld-modal-footer">
                        <button type="button" id="svld-preset-cancel" class="button">Cancel</button>
                    </div>
                </div>
            </div>`;

        $(modalHtml).appendTo('body');

        $('#svld-preset-cancel, #svld-preset-modal-overlay').on('click', function(e) {
            if (e.target === this) $('#svld-preset-modal-overlay').remove();
        });

        $('.svld-preset-card').on('click', function() {
            const key = $(this).data('key');
            $('#svld-preset-modal-overlay').remove();
            loadPreset(key);
        });
    }

    function loadPreset(key) {
        const $status = $('#svld-save-status');
        $status.text('Loading preset…');

        $.post(svld_params.ajax_url, {
            action: 'svld_get_preset_layout',
            nonce:  svld_params.nonce,
            preset: key,
        }, function(res) {
            if (res.success) {
                layout = res.data.layout || [];
                labelW = res.data.label_width  || 100;
                labelH = res.data.label_height || 50;
                currentLabelType = res.data.label_type || key;
                currentTemplateId = 'current';

                layout.forEach(function(el) {
                    el.visible      = el.visible !== false;
                    el.bold         = el.bold === true;
                    el.multiLine    = el.multiLine === true;
                    el.proportional = el.proportional === true;
                    el.showText     = el.showText !== false;
                    el.x            = parseFloat(el.x) || 0;
                    el.y            = parseFloat(el.y) || 0;
                    el.width        = parseFloat(el.width) || 30;
                    el.height       = parseFloat(el.height) || 10;
                    el.fontSize     = parseInt(el.fontSize) || 10;

                    // Normalize type-specific properties
                    if (el.align && typeof el.align !== 'string') el.align = String(el.align);
                    if (el.type === 'barcode') {
                        el.barcodeType = el.barcodeType || 'C128';
                        el.dataSource = el.dataSource || 'product_sku';
                    }
                    if (el.type === 'qr') {
                        el.qrType = el.qrType || 'QRCODE,H';
                        el.dataSource = el.dataSource || 'product_link';
                    }
                    if (el.type === 'image') {
                        el.imageDataSource = el.imageDataSource || 'custom';
                    }
                    if (!el.dataSource && (el.type === 'text' || el.type === 'title' || el.type === 'sku' || el.type === 'price')) {
                        el.dataSource = el.dataSource || 'product_name';
                    }
                });

                $('#svld-label-width').val(labelW);
                $('#svld-label-height').val(labelH);
                updateCanvasSize();
                renderCanvas();
                deselectElement();
                $('#svld-template-select').val('current');

                $status.text('✓ Preset loaded — save it as a template when ready');
                setTimeout(function() { $status.text(''); }, 4000);
            } else {
                $status.addClass('error').text('Error loading preset');
                setTimeout(function() { $status.text('').removeClass('error'); }, 3000);
            }
        });
    }

    function loadSelectedTemplate() {
        if (!isPro) {
            const $loadBtn = $('#svld-load-template');
            if ($loadBtn.length) {
                showProTooltip($loadBtn);
            }
            return;
        }

        const templateId = $('#svld-template-select').val();
        if (!templateId || templateId === 'current') return;

        $.post(svld_params.ajax_url, {
            action: 'svld_load_template',
            nonce: svld_params.nonce,
            template_id: templateId,
        }, function(res) {
            if (res.success && res.data.template) {
                const tpl = res.data.template;
                layout = tpl.layout || [];
                syncElementCounter(); // prevent ID collisions when adding new elements

                layout.forEach(function(el) {
                    el.multiLine    = el.multiLine === true;
                    el.proportional = el.proportional === true;
                    el.visible      = el.visible !== false;
                    el.bold         = el.bold === true;
                    el.showText     = el.showText !== false;
                    el.x            = parseFloat(el.x) || 0;
                    el.y            = parseFloat(el.y) || 0;
                    el.width        = parseFloat(el.width) || 30;
                    el.height       = parseFloat(el.height) || 10;
                    el.fontSize     = parseInt(el.fontSize) || 10;
                    if (el.align && typeof el.align !== 'string') el.align = String(el.align);

                    // Normalize type-specific properties
                    if (el.type === 'barcode') {
                        el.barcodeType = el.barcodeType || 'C128';
                        el.dataSource = el.dataSource || 'product_sku';
                    }
                    if (el.type === 'qr') {
                        el.qrType = el.qrType || 'QRCODE,H';
                        el.dataSource = el.dataSource || 'product_link';
                    }
                    if (el.type === 'image') {
                        el.imageDataSource = el.imageDataSource || 'custom';
                    }
                    if (!el.dataSource && (el.type === 'text' || el.type === 'title' || el.type === 'sku' || el.type === 'price')) {
                        el.dataSource = el.dataSource || 'product_name';
                    }
                });

                labelW = tpl.label_width || 100;
                labelH = tpl.label_height || 50;
                currentLabelType  = tpl.label_type || '';
                currentTemplateId = templateId;

                // Save as last used template in localStorage
                localStorage.setItem('svld_last_template', templateId);

                $('#svld-label-width').val(mmToDisplayUnit(labelW));
                $('#svld-label-height').val(mmToDisplayUnit(labelH));
                updateCanvasSize();
                renderCanvas();
                deselectElement();

                const $status = $('#svld-save-status');
                $status.text('✓ Template loaded');
                setTimeout(function () { $status.text(''); }, 2000);
            } else {
                const $status = $('#svld-save-status');
                const msg = res.data && res.data.message ? res.data.message : 'Failed to load template';
                $status.text('Error: ' + msg).addClass('error');
                setTimeout(function () { $status.text('').removeClass('error'); }, 3000);
            }
        }).fail(function() {
            const $status = $('#svld-save-status');
            $status.text('Error: Server error').addClass('error');
            setTimeout(function () { $status.text('').removeClass('error'); }, 3000);
        });
    }

    function openTemplateManager() {
        // Create modal for template management
        const modalHtml = `
            <div class="svld-template-manager-overlay" style="position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);z-index:100000;display:flex;align-items:center;justify-content:center;">
                <div class="svld-template-manager" style="background:#fff;padding:20px;border-radius:8px;max-width:600px;width:90%;max-height:80vh;overflow-y:auto;">
                    <h2>Manage Templates</h2>
                    <div class="svld-template-list" id="svld-template-manager-list"></div>
                    <button class="button svld-close-manager" style="margin-top:15px;">Close</button>
                </div>
            </div>
        `;

        $(modalHtml).appendTo('body');

        // Load templates
        $.post(svld_params.ajax_url, {
            action: 'svld_list_templates',
            nonce: svld_params.nonce,
        }, function(res) {
            if (res.success && res.data.templates) {
                renderTemplateList(res.data.templates);
            }
        });

        // Close handler
        $('.svld-close-manager, .svld-template-manager-overlay').on('click', function(e) {
            if (e.target === this) {
                $('.svld-template-manager-overlay').remove();
            }
        });
    }

    const TYPE_LABELS = { product: '🏷️ Product', shipping: '📦 Shipping', invoice: '🧾 Invoice', return: '↩️ Return' };

    function renderTemplateList(templates) {
        let html = '<table class="wp-list-table widefat fixed striped" style="margin-top:15px;"><thead><tr><th>Template Name</th><th>Actions</th></tr></thead><tbody>';

        if (templates.length === 0) {
            html += '<tr><td colspan="2">No templates saved yet.</td></tr>';
        } else {
            templates.forEach(function(tpl) {
                const typeBadge = tpl.label_type && TYPE_LABELS[tpl.label_type]
                    ? ' <span class="svld-type-badge svld-type-' + tpl.label_type + '">' + TYPE_LABELS[tpl.label_type] + '</span>'
                    : '';
                html += '<tr>';
                html += '<td>' + tpl.name + typeBadge + (tpl.is_default ? ' <span class="dashicons dashicons-star-filled" style="color:#f0ad4e;" title="Default"></span>' : '') + '</td>';
                html += '<td>';
                html += '<button class="button button-small svld-load-tpl-btn" data-id="' + tpl.id + '">Load</button> ';
                html += '<button class="button button-small svld-duplicate-tpl-btn" data-id="' + tpl.id + '">Duplicate</button> ';
                if (!tpl.is_default) {
                    html += '<button class="button button-small svld-set-default-tpl-btn" data-id="' + tpl.id + '">Set Default</button> ';
                }
                html += '<button class="button button-small svld-delete-tpl-btn" data-id="' + tpl.id + '" style="color:#dc3232;">Delete</button>';
                html += '</td>';
                html += '</tr>';
            });
        }

        html += '</tbody></table>';
        $('#svld-template-manager-list').html(html);

        // Event handlers - use off() to prevent duplicates
        $('.svld-load-tpl-btn').off('click').on('click', function() {
            const id = $(this).data('id');
            $('#svld-template-select').val(id);
            loadSelectedTemplate();
            $('.svld-template-manager-overlay').remove();
        });

        $('.svld-duplicate-tpl-btn').off('click').on('click', function() {
            const id = $(this).data('id');
            $.post(svld_params.ajax_url, {
                action: 'svld_duplicate_template',
                nonce: svld_params.nonce,
                template_id: id,
            }, function(res) {
                if (res.success) {
                    loadTemplatesList();
                    refreshTemplateManagerList();
                    alert('Template duplicated!');
                }
            });
        });

        $('.svld-delete-tpl-btn').off('click').on('click', function() {
            const id = $(this).data('id');
            if (!confirm('Delete this template?')) return;

            $.post(svld_params.ajax_url, {
                action: 'svld_delete_template',
                nonce: svld_params.nonce,
                template_id: id,
            }, function(res) {
                if (res.success) {
                    loadTemplatesList();
                    refreshTemplateManagerList();
                }
            });
        });

        $('.svld-set-default-tpl-btn').off('click').on('click', function() {
            const id = $(this).data('id');
            $.post(svld_params.ajax_url, {
                action: 'svld_set_default_template',
                nonce: svld_params.nonce,
                template_id: id,
            }, function(res) {
                if (res.success) {
                    loadTemplatesList();
                    refreshTemplateManagerList();
                }
            });
        });
    }

    function refreshTemplateManagerList() {
        // Refresh the template list without reopening the modal
        $.post(svld_params.ajax_url, {
            action: 'svld_list_templates',
            nonce: svld_params.nonce,
        }, function(res) {
            if (res.success && res.data.templates) {
                renderTemplateList(res.data.templates);
            }
        });
    }

    // =========================================================================
    // =========================================================================
    // Coordinate helpers
    // =========================================================================
    // The canvas is always sized at true physical px (1mm = MM_TO_PX px).
    // Zoom is applied via CSS transform: scale(canvasZoom) on #svld-canvas.
    // Element sizes & positions therefore never change when the user zooms —
    // only the visual scale changes. pxToMm / mmToPx never include canvasZoom.
    function mmToPx(mm) { return mm * MM_TO_PX; }
    function pxToMm(px) { return +(px / MM_TO_PX).toFixed(3); } // Increased precision to 3 decimals

    // Display conversion functions (convert between mm and current unit)
    function mmToDisplayUnit(mm) { return +(mm / unitToMmFactor).toFixed(2); }
    function displayUnitToMm(value) { return value * unitToMmFactor; }
    function getUnitLabel() { return unitLabel; }

}(jQuery));
