(function ($) {

    const PREVIEW_SNAPSHOT_KEY = 'vmo_preview_frame_state';
    const PREVIEW_SNAPSHOT_MAX_BYTES = 3500000;

    function getPreviewIframe() {
        return document.getElementById('vmo-preview-iframe');
    }

    function getPreviewIframeSrc() {
        const iframe = getPreviewIframe();
        if (!iframe) return '';
        return String(iframe.getAttribute('src') || iframe.src || '');
    }

    function getLivePreviewHtmlInternal() {
        const iframe = getPreviewIframe();

        if (iframe && getPreviewIframeSrc() && !window.vmoPreviewIsLive) {
            return '';
        }

        if (typeof window.vmoSerializePreviewDocument === 'function') {
            const serialized = window.vmoSerializePreviewDocument();
            if (serialized && serialized.trim()) {
                return serialized;
            }
        }

        if (!iframe) {
            return '';
        }

        const srcdocHtml = String(iframe.getAttribute('srcdoc') || iframe.srcdoc || '');
        if (srcdocHtml && srcdocHtml.trim()) {
            return srcdocHtml;
        }

        try {
            if (iframe.contentDocument && iframe.contentDocument.documentElement) {
                return '<!DOCTYPE html>\n' + iframe.contentDocument.documentElement.outerHTML;
            }
        } catch (_) {}

        return '';
    }

    function readPersistedPreviewState() {
        try {
            const raw = sessionStorage.getItem(PREVIEW_SNAPSHOT_KEY);
            if (!raw) return null;
            return JSON.parse(raw);
        } catch (error) {
            console.warn('[VMO Theme] Could not read persisted preview state:', error);
            return null;
        }
    }

    function writePersistedPreviewState(snapshot) {
        if (!snapshot) {
            try {
                sessionStorage.removeItem(PREVIEW_SNAPSHOT_KEY);
                return true;
            } catch (_) {
                return false;
            }
        }

        try {
            const raw = JSON.stringify(snapshot);
            if (raw.length > PREVIEW_SNAPSHOT_MAX_BYTES) {
                console.warn('[VMO Theme] Skipped preview snapshot: payload too large');
                return false;
            }
            sessionStorage.setItem(PREVIEW_SNAPSHOT_KEY, raw);
            return true;
        } catch (error) {
            console.warn('[VMO Theme] Could not persist preview state:', error);
            return false;
        }
    }

    function hasActiveIframePreview() {
        const iframe = getPreviewIframe();
        let html = '';
        if (!iframe) return false;

        html = getLivePreviewHtmlInternal();
        if (html && html.trim()) {
            if (typeof window.vmoHasMeaningfulPreviewHtml === 'function') {
                return window.vmoHasMeaningfulPreviewHtml(html);
            }
            return true;
        }
        if (getPreviewIframeSrc()) return !!window.vmoPreviewIsLive;

        try {
            const bodyHtml = iframe.contentDocument && iframe.contentDocument.body
                ? String(iframe.contentDocument.body.innerHTML || '').trim()
                : '';
            return !!bodyHtml;
        } catch (_) {
            return false;
        }
    }

    function buildPreviewSnapshot() {
        const iframe = getPreviewIframe();
        const showcasePreviewActive = isShowcasePlaceholderActive();
        const iframeSrc = getPreviewIframeSrc();
        let html = '';
        let mode = '';

        if (!iframe) {
            return null;
        }

        if (showcasePreviewActive) {
            const demoPreviewUrl = typeof window.vmoGetDemoPreviewUrl === 'function' ? window.vmoGetDemoPreviewUrl() : '';
            if (iframeSrc && demoPreviewUrl && iframeSrc.indexOf(demoPreviewUrl) === 0) {
                return {
                    version: 2,
                    ts: Date.now(),
                    mode: 'showcase-url',
                    html: '',
                    src: iframeSrc,
                    previewIsLive: false,
                    showcasePreviewActive: true,
                    currentProjectId: window.currentProjectId || null,
                    currentProjectTitle: window.currentProjectTitle || null,
                    currentLivePageId: window.currentLivePageId || null
                };
            }

            html = getLivePreviewHtmlInternal();
            if (!html && typeof window.vmoGetShowcasePreviewHtml === 'function') {
                html = window.vmoGetShowcasePreviewHtml();
            }
            if (typeof window.vmoHasMeaningfulPreviewHtml === 'function' && !window.vmoHasMeaningfulPreviewHtml(html)) {
                html = '';
            }
            if (!html || !html.trim()) {
                return null;
            }
            mode = 'showcase';
        } else {
            html = getLivePreviewHtmlInternal();
            if (typeof window.vmoHasMeaningfulPreviewHtml === 'function' && !window.vmoHasMeaningfulPreviewHtml(html)) {
                html = '';
            }
            if ((!html || !html.trim()) && typeof window.vmoNormalizeBuilderHtml === 'function') {
                html = window.vmoNormalizeBuilderHtml(window.lastContent || '');
            }

            if (html && html.trim()) {
                if (typeof window.vmoShouldTreatAsRealContent === 'function'
                    && !window.vmoShouldTreatAsRealContent(html, window.vmoState)) {
                    html = '';
                }
            }

            if (html && html.trim()) {
                mode = 'html';
            } else {
                return null;
            }
        }

        return {
            version: 1,
            ts: Date.now(),
            mode: mode,
            html: html || '',
            src: mode === 'live-url' ? iframeSrc : '',
            previewIsLive: !!window.vmoPreviewIsLive,
            showcasePreviewActive: showcasePreviewActive,
            currentProjectId: window.currentProjectId || null,
            currentProjectTitle: window.currentProjectTitle || null,
            currentLivePageId: window.currentLivePageId || null
        };
    }

    window.vmoPersistPreviewFrameState = function(reason) {
        const snapshot = buildPreviewSnapshot();

        if (!snapshot) {
            return false;
        }

        const persisted = writePersistedPreviewState(snapshot);
        if (persisted && window.vmoDebug) {
            console.log('[VMO Theme] Preview snapshot persisted:', reason || 'manual', snapshot.mode);
        }
        return persisted;
    };

    window.vmoRestorePersistedPreviewFrameState = function(options = {}) {
        const iframe = getPreviewIframe();
        const snapshot = readPersistedPreviewState();
        const force = !!options.force;

        if (!iframe || !snapshot) {
            return false;
        }

        if (!force && hasActiveIframePreview()) {
            return false;
        }

        if (snapshot.mode === 'showcase' && snapshot.html) {
            if (typeof window.vmoHasMeaningfulPreviewHtml === 'function' && !window.vmoHasMeaningfulPreviewHtml(snapshot.html)) {
                writePersistedPreviewState(null);
                try {
                    sessionStorage.removeItem(PREVIEW_SNAPSHOT_KEY);
                } catch (_) {}
                return false;
            }
            window.vmoPreviewIsLive = false;
            window.vmoHasContent = false;
            window.lastContent = '';
            window.vmoShowcasePreviewHtml = snapshot.html;
            iframe.removeAttribute('src');
            iframe.dataset.vmoPreviewMode = 'showcase-placeholder';
            iframe.dataset.vmoShowcaseMediaState = 'persisted';
            iframe.srcdoc = snapshot.html;
            if (typeof window.vmoGenerateShowcaseMedia === 'function') {
                setTimeout(function() {
                    window.vmoGenerateShowcaseMedia();
                }, 180);
            }
            return true;
        }

        if (snapshot.mode === 'showcase-url' && snapshot.src) {
            writePersistedPreviewState(null);
            iframe.removeAttribute('src');
            return false;
        }

        if (snapshot.mode === 'html' && snapshot.html) {
            if (typeof window.vmoHasMeaningfulPreviewHtml === 'function' && !window.vmoHasMeaningfulPreviewHtml(snapshot.html)) {
                try {
                    sessionStorage.removeItem(PREVIEW_SNAPSHOT_KEY);
                } catch (_) {}
                return false;
            }
            if (typeof window.vmoShouldTreatAsRealContent === 'function'
                && !window.vmoShouldTreatAsRealContent(snapshot.html, window.vmoState)) {
                return false;
            }

            window.vmoPreviewIsLive = false;
            window.vmoHasContent = true;
            window.lastContent = snapshot.html;
            iframe.removeAttribute('src');
            delete iframe.dataset.vmoPreviewMode;
            iframe.srcdoc = snapshot.html;

            const codeView = document.getElementById('vmo-code-view');
            if (codeView) {
                codeView.value = snapshot.html;
                codeView.textContent = snapshot.html;
            }
            return true;
        }

        if (snapshot.mode === 'live-url' && snapshot.src) {
            writePersistedPreviewState(null);
            iframe.removeAttribute('src');
            return false;
        }

        return false;
    };

    function bindPreviewPersistenceLifecycle() {
        const iframe = getPreviewIframe();

        if (!window.__vmoPreviewPersistenceBound) {
            window.__vmoPreviewPersistenceBound = true;

            window.addEventListener('pagehide', function() {
                window.vmoPersistPreviewFrameState('pagehide');
            });

            window.addEventListener('beforeunload', function() {
                window.vmoPersistPreviewFrameState('beforeunload');
            });

            window.addEventListener('pageshow', function() {
                setTimeout(function() {
                    if (!window.vmoRestorePersistedPreviewFrameState()) {
                        window.vmoPersistPreviewFrameState('pageshow');
                    }
                }, 140);
            });

            document.addEventListener('visibilitychange', function() {
                if (document.visibilityState === 'hidden') {
                    window.vmoPersistPreviewFrameState('visibilitychange-hidden');
                } else {
                    setTimeout(function() {
                        if (!window.vmoRestorePersistedPreviewFrameState()) {
                            window.vmoPersistPreviewFrameState('visibilitychange-visible');
                        }
                    }, 140);
                }
            });
        }

        if (iframe && iframe.dataset.vmoPreviewPersistenceBound !== '1') {
            iframe.dataset.vmoPreviewPersistenceBound = '1';
            iframe.addEventListener('load', function() {
                setTimeout(function() {
                    window.vmoPersistPreviewFrameState('iframe-load');
                }, 160);
            });
        }

        setTimeout(function() {
            if (!window.vmoRestorePersistedPreviewFrameState()) {
                window.vmoPersistPreviewFrameState('initial-pass');
            }
        }, 220);
    }

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

    function isShowcasePlaceholderActive() {
        if (typeof window.vmoIsShowcasePreviewActive === 'function') {
            return !!window.vmoIsShowcasePreviewActive();
        }

        const iframe = document.getElementById('vmo-preview-iframe');
        if (!iframe) return false;
        if (iframe.dataset && iframe.dataset.vmoPreviewMode === 'showcase-placeholder') return true;

        try {
            return !!iframe.contentDocument?.getElementById('vmo-demo-showcase');
        } catch (_) {
            return false;
        }
    }

    function getCurrentPreviewHtml() {
        const snapshot = readPersistedPreviewState();
        const liveHtml = getLivePreviewHtmlInternal();

        if (liveHtml && liveHtml.trim()) {
            return liveHtml;
        }

        if (!getPreviewIframe()) {
            return snapshot && snapshot.html ? String(snapshot.html) : '';
        }

        return snapshot && snapshot.html ? String(snapshot.html) : '';
    }

    function hasRenderableBackgroundMedia(el) {
        if (!el) return false;

        const inlineBackground = el.style && el.style.backgroundImage ? String(el.style.backgroundImage) : '';
        if (inlineBackground && inlineBackground !== 'none') {
            return true;
        }

        try {
            const computedBackground = window.getComputedStyle(el).backgroundImage;
            return !!computedBackground && computedBackground !== 'none' && computedBackground.indexOf('url(') !== -1;
        } catch (_) {
            return false;
        }
    }

    function hasNestedRenderableMedia(el) {
        if (!el || typeof el.querySelector !== 'function') return false;

        try {
            return !!el.querySelector('img, video, audio, canvas, svg, embed, object, iframe, .vmo-media-placeholder, [data-vmo-generate], [data-vmo-sora]');
        } catch (_) {
            return false;
        }
    }

    function isExplicitMediaSlot(el) {
        if (!el || !el.classList) return false;

        return el.classList.contains('vmo-media-placeholder')
            || el.classList.contains('vmo-media-placeholder-image')
            || el.classList.contains('vmo-media-placeholder-video')
            || el.hasAttribute('data-vmo-generate')
            || el.hasAttribute('data-vmo-sora')
            || el.getAttribute('data-bg') === '1';
    }

    function resolveReplaceTargetType(el) {
        if (!el || !el.tagName) return 'image';

        const tagName = el.tagName.toLowerCase();
        const dataType = String(el.getAttribute('data-type') || el.getAttribute('data-media-type') || '').toLowerCase();
        const source = String(el.getAttribute('src') || el.getAttribute('data-src') || el.getAttribute('data') || '').toLowerCase();

        if (dataType === 'audio' || tagName === 'audio' || /\.(mp3|wav|m4a|aac|oga)(\?|$)/i.test(source)) {
            return 'audio';
        }

        if (dataType === 'video' || el.hasAttribute('data-vmo-sora') || el.classList.contains('vmo-media-placeholder-video')) {
            return 'video';
        }

        if (tagName === 'video') {
            return 'video';
        }

        if (tagName === 'iframe' && /(youtube|vimeo|dailymotion|twitch|facebook|instagram)/i.test(source)) {
            return 'video';
        }

        if (/\.(mp4|webm|ogg|mov|m4v)(\?|$)/i.test(source)) {
            return 'video';
        }

        return 'image';
    }
    
    // Helper function to validate if element is actually media
    function isValidMediaElement(el) {
        if (!el || !el.tagName) return false;

        if (el.matches && el.matches('.vmo-replace-overlay, .vmo-replace-btn, .vmo-replace-media-btn, .replace-image-btn, .replace-video-btn, [data-vmo-editor-only="media-replace-overlay"], [data-noneditable="1"], button')) {
            return false;
        }

        if (el.closest && el.closest('.vmo-replace-overlay, .vmo-replace-btn, .vmo-replace-media-btn, .replace-image-btn, .replace-video-btn, [data-vmo-editor-only="media-replace-overlay"], [data-noneditable="1"]')) {
            return false;
        }
        
        const tagName = el.tagName.toLowerCase();
        const directMediaTags = ['img', 'video', 'audio', 'canvas', 'svg', 'embed', 'object', 'iframe'];
        const hasNestedMedia = hasNestedRenderableMedia(el);
        const hasBackgroundMedia = hasRenderableBackgroundMedia(el);
        const explicitSlot = isExplicitMediaSlot(el);

        if (tagName === 'source') {
            return false;
        }

        // Skip wrapper nodes that merely contain media. We want buttons anchored to the actual media slot.
        if (hasNestedMedia && !directMediaTags.includes(tagName) && !hasBackgroundMedia && !explicitSlot) {
            return false;
        }

        // Skip if too small (likely decorative)
        const rect = el.getBoundingClientRect();
        if (rect.width < 20 || rect.height < 20) {
            return false;
        }
        
        // Direct media tags
        if (directMediaTags.includes(tagName)) {
            return true;
        }
        
        // Elements with background images
        if (hasBackgroundMedia) {
            if (!el.getAttribute('data-bg')) {
                el.setAttribute('data-bg', '1');
            }
            return true;
        }

        if (explicitSlot) {
            return true;
        }
        
        // Elements with media-related attributes
        if (el.hasAttribute('src') || el.hasAttribute('data-src') || el.hasAttribute('srcset')) {
            return true;
        }
        
        // Elements with media-related classes
        const mediaClasses = ['media', 'image', 'video', 'photo', 'picture', 'gallery', 'thumbnail'];
        for (const cls of mediaClasses) {
            if (String(el.className || '').toLowerCase().includes(cls) && !hasNestedMedia) {
                return true;
            }
        }
        
        return false;
    }
    
    /* ------------------------------------------------------------------
       1.  OVERLAY HELPER — adds ONE context‑aware button per media
       ------------------------------------------------------------------ */
    function vmoInjectReplaceButtonsInIframe() {
        console.log('🔧 vmoInjectReplaceButtonsInIframe called');
        const iframe = document.getElementById('vmo-preview-iframe');
        if (!iframe?.contentDocument) {
            console.log('❌ No iframe or contentDocument found');
            return;
        }

        const doc = iframe.contentDocument;
        console.log('✅ Iframe document found');

        if (doc._vmoInjectingReplaceButtons) {
            console.log('⏳ Replace button injection already running, skipping duplicate call');
            return;
        }

        doc._vmoInjectingReplaceButtons = true;

        try {

        // Remove existing overlay buttons
        const existingButtons = doc.querySelectorAll('.vmo-replace-overlay, .vmo-replace-btn, .vmo-replace-media-btn, .replace-image-btn, .replace-video-btn, [data-replace-media], [data-vmo-editor-only="media-replace-overlay"]');
        console.log('🧹 Removing existing buttons:', existingButtons.length);
        existingButtons.forEach(btn => btn.remove());

        // COMPREHENSIVE media selectors - covers ALL possible media elements
        const mediaSelectors = [
            // VMO-specific placeholders
            '.vmo-media-placeholder',
            '[data-media-id]',
            '[data-media-type]',
            
            // Standard HTML media
            'img:not(.vmo-replace-overlay):not([data-noneditable]):not([src=""])',
            'video:not(.vmo-replace-overlay):not([data-noneditable])',
            'audio:not(.vmo-replace-overlay):not([data-noneditable])',
            'source[srcset]',
            'embed[src]',
            'object[data]',
            'canvas',
            
            // Iframe content (YouTube, Vimeo, etc.)
            'iframe[src*="youtube"]', 'iframe[src*="vimeo"]', 'iframe[src*="dailymotion"]',
            'iframe[src*="twitch"]', 'iframe[src*="facebook"]', 'iframe[src*="instagram"]',
            
            // WordPress blocks
            '.wp-block-image img', '.wp-block-image', 
            '.wp-block-video video', '.wp-block-video',
            '.wp-block-media-text img', '.wp-block-media-text',
            '.wp-block-cover', '.wp-block-gallery img', '.wp-block-gallery',
            '.wp-block-audio', '.wp-block-file',
            
            // Semantic HTML
            'figure img', 'figure video', 'figure',
            'picture img', 'picture',
            
            // Common class names and patterns
            '.media-element', '.hero-image', '.background-image', '.banner-image',
            '.featured-image', '.thumbnail', '.gallery-item', '.slider-image',
            '.card-image', '.profile-image', '.avatar', '.logo', '.icon-image',
            
            // Data attributes and roles
            '[data-type="image"]', '[data-type="video"]', '[data-type="media"]',
            '[role="img"]', '[aria-label*="image" i]', '[aria-label*="video" i]',
            
            // Background images (any element with background-image)
            '[style*="background-image"]:not(body):not(html)',
            
            // Generated content areas that might contain media
            '.content img', '.post-content img', '.entry-content img',
            '.article img', '.section img', '.container img',
            
            // Small media elements
            'img[width][height]', 'img[style*="width"]', 'img[style*="height"]',
            
            // SVG and vector graphics
            'svg image', 'svg', 'use[href*="#"]',
            
            // Plugin-generated content
            '.elementor-image img', '.elementor-video', '.elementor-background-video',
            '.vc_single_image img', '.vc_video', 
            '.fusion-image img', '.fusion-video',
            
            // Any element that looks like it could be media
            '*[src*=".jpg"]', '*[src*=".jpeg"]', '*[src*=".png"]', '*[src*=".gif"]', 
            '*[src*=".webp"]', '*[src*=".svg"]', '*[src*=".mp4"]', '*[src*=".webm"]',
            '*[href*=".jpg"]', '*[href*=".jpeg"]', '*[href*=".png"]', '*[href*=".gif"]'
        ];
        
        let allMediaEls = [];
        let elementMap = new Map(); // Prevent duplicates
        
        mediaSelectors.forEach(selector => {
            try {
                const elements = [...doc.querySelectorAll(selector)];
                elements.forEach(el => {
                    // Skip if already processed or is a button
                    if (!elementMap.has(el) && 
                        !el.classList.contains('vmo-replace-overlay') && 
                        !el.hasAttribute('data-noneditable') &&
                        el.tagName !== 'BUTTON') {
                        
                        // Additional validation for actual media content
                        if (isValidMediaElement(el)) {
                            elementMap.set(el, true);
                            allMediaEls.push(el);
                        }
                    }
                });
            } catch (e) {
                console.warn('Selector failed:', selector, e);
            }
        });
        
        // Additional scan for elements with background images
        const allElements = [...doc.querySelectorAll('*')];
        allElements.forEach(el => {
            const bgImage = window.getComputedStyle(el).backgroundImage;
            if (bgImage && bgImage !== 'none' && bgImage.includes('url(') && 
                !elementMap.has(el) && !el.classList.contains('vmo-replace-overlay')) {
                if (isValidMediaElement(el)) {
                    elementMap.set(el, true);
                    allMediaEls.push(el);
                }
            }
        });
        
        console.log('🎯 Found media elements:', allMediaEls.length, allMediaEls);

        if (!allMediaEls.length) {
            const showcasePreviewActive = (iframe.dataset && iframe.dataset.vmoPreviewMode === 'showcase-placeholder')
                || (typeof window.vmoIsShowcasePreviewActive === 'function' && window.vmoIsShowcasePreviewActive());
            const docBodyHtml = doc && doc.body ? String(doc.body.innerHTML || '').trim() : '';
            const hasShowcaseStructure = !!(doc
                && ((typeof doc.getElementById === 'function' && doc.getElementById('vmo-showcase-stage'))
                    || (typeof doc.querySelector === 'function' && doc.querySelector('.vmo-showcase-slide, .demo-hero, .demo-shell'))));

            if (showcasePreviewActive
                && (!docBodyHtml || !hasShowcaseStructure)
                && typeof window.vmoRecoverShowcasePlaceholder === 'function') {
                if (window.vmoRecoverShowcasePlaceholder('replace-buttons-empty')) {
                    return;
                }
            }
        }

        allMediaEls.forEach((el, idx) => {
            console.log(`📍 Processing media element ${idx}:`, el, 'tagName:', el.tagName);
            
            // Ensure stable id for delegation
            if (!el.dataset.mediaId) {
                el.dataset.mediaId = `media-${Date.now()}-${idx}`;
            }
            
            // Enhanced data-type detection for comprehensive media support
            if (!el.dataset.type) {
                const tagName = el.tagName.toLowerCase();
                
                if (tagName === 'video' || el.querySelector('video')) {
                    el.dataset.type = 'video';
                } else if (tagName === 'audio' || el.querySelector('audio')) {
                    el.dataset.type = 'audio';
                } else if (tagName === 'iframe' && (el.src?.includes('youtube') || el.src?.includes('vimeo'))) {
                    el.dataset.type = 'video';
                } else if (tagName === 'img' || 
                          el.style.backgroundImage || 
                          el.querySelector('img') ||
                          tagName === 'canvas' ||
                          tagName === 'svg' ||
                          el.classList.contains('wp-block-image') ||
                          el.classList.contains('wp-block-cover') ||
                          el.classList.contains('hero-image') ||
                          el.classList.contains('background-image') ||
                          el.hasAttribute('role') && el.getAttribute('role') === 'img') {
                    el.dataset.type = 'image';
                } else if (tagName === 'embed' || tagName === 'object') {
                    // Determine if it's video or image based on src/data
                    const src = el.src || el.data || '';
                    if (src.match(/\.(mp4|webm|ogg|mov|avi)$/i)) {
                        el.dataset.type = 'video';
                    } else {
                        el.dataset.type = 'image';
                    }
                } else {
                    el.dataset.type = 'image'; // safe default
                }
            }
            
            // Ensure vmo-media-placeholder class
            if (!el.classList.contains('vmo-media-placeholder')) {
                el.classList.add('vmo-media-placeholder');
            }

            // Create replace button with adaptive sizing
            const replaceTargetType = resolveReplaceTargetType(el);
            const mediaLabel = replaceTargetType === 'video' ? 'video' : (replaceTargetType === 'audio' ? 'audio' : 'image');
            const btn = doc.createElement('button');
            btn.type = 'button';
            btn.className = 'vmo-replace-overlay';
            btn.setAttribute('data-vmo-editor-only', 'media-replace-overlay');
            btn.dataset.mediaId = el.dataset.mediaId;
            btn.dataset.mediaType = replaceTargetType;
            btn.dataset.noneditable = '1';
            btn.setAttribute('data-noneditable', '1');
            btn.setAttribute('aria-label', 'Replace ' + mediaLabel);
            btn.setAttribute('title', 'Replace ' + mediaLabel);
            btn.contentEditable = 'false';
            btn.textContent = 'Replace ' + mediaLabel.charAt(0).toUpperCase() + mediaLabel.slice(1);
            
            // Get element dimensions for adaptive button sizing
            const rect = el.getBoundingClientRect();
            const isSmall = rect.width < 100 || rect.height < 100;
            const isTiny = rect.width < 50 || rect.height < 50;
            
            // Adaptive button styling based on element size
            let buttonStyles = {
                position: 'absolute',
                zIndex: '9999',
                background: '#00f8ff',
                border: 'none',
                borderRadius: '4px',
                fontWeight: '600',
                cursor: 'pointer',
                pointerEvents: 'auto',
                touchAction: 'manipulation',
                userSelect: 'none',
                color: '#000',
                boxShadow: '0 2px 8px rgba(0,248,255,0.4)',
                fontFamily: 'system-ui, -apple-system, sans-serif'
            };
            
            if (isTiny) {
                // Ultra-small elements get minimal button
                Object.assign(buttonStyles, {
                    top: '2px',
                    right: '2px',
                    padding: '2px 4px',
                    fontSize: '8px',
                    borderRadius: '2px'
                });
                btn.textContent = mediaLabel === 'video' ? 'Video' : (mediaLabel === 'audio' ? 'Audio' : 'Image');
            } else if (isSmall) {
                // Small elements get compact button
                Object.assign(buttonStyles, {
                    top: '4px',
                    right: '4px',
                    padding: '3px 6px',
                    fontSize: '9px'
                });
                btn.textContent = 'Replace';
            } else {
                // Normal-sized elements get full button
                Object.assign(buttonStyles, {
                    top: '6px',
                    right: '6px',
                    padding: '4px 8px',
                    fontSize: '11px'
                });
            }
            
            // Apply styles
            const styleString = Object.entries(buttonStyles)
                .map(([key, value]) => `${key.replace(/([A-Z])/g, '-$1').toLowerCase()}:${value}`)
                .join(';');
            btn.style.cssText = styleString;
            
            console.log(`✅ Created button for ${el.dataset.mediaId}:`, btn);

            // Enhanced parent positioning and button attachment
            let parent = el.parentElement;
            const backgroundLayer = typeof el.closest === 'function' ? el.closest('.vmo-ai-background-media') : null;
            const backgroundSection = backgroundLayer && typeof backgroundLayer.closest === 'function'
                ? backgroundLayer.closest('section, header, [data-block-id], .vmo-section, [data-vmo-section-type]')
                : null;

            if (backgroundSection) {
                parent = backgroundSection;
            }
            
            // Find the best parent for positioning
            let attempts = 0;
            while (parent && attempts < 3) {
                const parentRect = parent.getBoundingClientRect();
                const parentStyle = window.getComputedStyle(parent);
                const pointerEvents = parentStyle.pointerEvents;
                
                // Check if parent is large enough and suitable for positioning
                if (pointerEvents !== 'none' && parentRect.width > rect.width * 0.9 && parentRect.height > rect.height * 0.9) {
                    break;
                }
                parent = parent.parentElement;
                attempts++;
            }
            
            // Fall back to element itself if no suitable parent
            if (!parent || attempts >= 3) {
                parent = el;
            }
            
            // Ensure parent has relative positioning (or is already positioned)
            const parentComputedStyle = window.getComputedStyle(parent);
            const currentPosition = parentComputedStyle.position;
            
            if (!['relative', 'absolute', 'fixed', 'sticky'].includes(currentPosition)) {
                parent.style.position = 'relative';
            }

            if (parent.style.pointerEvents === 'none') {
                parent.style.pointerEvents = 'auto';
            }
            
            // Add hover effects to make button more discoverable
            btn.addEventListener('mouseenter', () => {
                btn.style.background = '#00d4ff';
                btn.style.transform = 'scale(1.05)';
            });
            
            btn.addEventListener('mouseleave', () => {
                btn.style.background = '#00f8ff';
                btn.style.transform = 'scale(1)';
            });

            const readClosestDatasetValue = (node, keys) => {
                let cursor = node;
                while (cursor && cursor.nodeType === 1) {
                    for (const key of keys) {
                        if (cursor.dataset && cursor.dataset[key]) return cursor.dataset[key];
                        const attr = 'data-' + key.replace(/[A-Z]/g, match => '-' + match.toLowerCase());
                        if (cursor.hasAttribute && cursor.hasAttribute(attr)) return cursor.getAttribute(attr);
                    }
                    cursor = cursor.parentElement;
                }
                return '';
            };

            const inferPlacementRole = (node, mediaType) => {
                const explicit = readClosestDatasetValue(node, ['placementRole', 'vmoPlacementRole', 'role', 'vmoRole']);
                if (explicit) return explicit;
                const text = [node.className || '', node.id || '', readClosestDatasetValue(node, ['sectionType', 'vmoSectionType'])].join(' ').toLowerCase();
                if (/logo|brand-mark|brandmark/.test(text)) return 'logo';
                if (/hero|masthead|cover/.test(text)) return mediaType === 'video' ? 'hero_video' : 'hero_image';
                if (/product|shop|commerce|gallery/.test(text)) return mediaType === 'video' ? 'product_video' : 'product_image';
                if (/testimonial|review/.test(text)) return 'testimonial_media';
                if (/audio|voice|tts|podcast/.test(text)) return 'audio';
                return mediaType === 'video' ? 'section_video' : (mediaType === 'audio' ? 'section_audio' : 'section_image');
            };

            const allowedReplacementTypes = (mediaType, placementRole) => {
                if (mediaType === 'audio') return ['audio'];
                if (placementRole === 'logo') return ['image', 'logo'];
                return ['image', 'video'];
            };

            const buildReplacePayload = () => {
                const mediaType = btn.dataset.mediaType || resolveReplaceTargetType(el);
                const placementRole = inferPlacementRole(el, mediaType);
                const block = typeof el.closest === 'function' ? el.closest('[data-block-id]') : null;
                const section = typeof el.closest === 'function' ? el.closest('section, [data-section-id], [data-vmo-section-id], [data-vmo-section-type], .vmo-section') : null;
                const currentSrc = el.currentSrc || el.src || el.getAttribute('src') || el.getAttribute('data-src') || el.getAttribute('poster') || '';
                return {
                    selector: `[data-media-id="${el.dataset.mediaId}"]`,
                    mediaId: el.dataset.mediaId,
                    type: mediaType,
                    mediaType,
                    slot_id: el.dataset.vmoSlotId || el.dataset.slotId || el.dataset.mediaId,
                    page_id: readClosestDatasetValue(el, ['pageId', 'vmoPageId', 'page']) || (doc.body && doc.body.dataset ? (doc.body.dataset.pageId || doc.body.dataset.vmoPageId || '') : ''),
                    section_id: el.dataset.sectionId || readClosestDatasetValue(el, ['sectionId', 'vmoSectionId']) || (section && section.id ? section.id : ''),
                    product_id: el.dataset.productId || readClosestDatasetValue(el, ['productId', 'vmoProductId', 'wooProductId']),
                    placement_role: placementRole,
                    current_attachment_id: el.dataset.attachmentId || el.dataset.currentAttachmentId || '',
                    allowed_replacement_types: allowedReplacementTypes(mediaType, placementRole),
                    block_id: block ? String(block.dataset.blockId || '') : '',
                    current_src: currentSrc,
                    target_tag: String(el.tagName || '').toLowerCase(),
                    source: 'iframe_replace_overlay'
                };
            };

            const buttonPayload = buildReplacePayload();
            btn.dataset.slotId = buttonPayload.slot_id || '';
            btn.dataset.pageId = buttonPayload.page_id || '';
            btn.dataset.sectionId = buttonPayload.section_id || '';
            btn.dataset.productId = buttonPayload.product_id || '';
            btn.dataset.placementRole = buttonPayload.placement_role || '';
            btn.dataset.currentAttachmentId = buttonPayload.current_attachment_id || '';
            btn.dataset.currentSrc = buttonPayload.current_src || '';
            btn.dataset.blockId = buttonPayload.block_id || '';
            btn.dataset.targetTag = buttonPayload.target_tag || '';
            btn.dataset.allowedReplacementTypes = (buttonPayload.allowed_replacement_types || []).join(',');

            const dispatchReplacePicker = (payload) => {
                if (typeof window.vmoOpenMediaPicker === 'function') {
                    window.vmoOpenMediaPicker(payload);
                    return true;
                } else if (window.parent && typeof window.parent.vmoOpenMediaPicker === 'function') {
                    window.parent.vmoOpenMediaPicker(payload);
                    return true;
                } else if (window.parent && typeof window.parent.postMessage === 'function') {
                    window.parent.postMessage({ action: 'vmoOpenMediaPicker', data: payload }, '*');
                    return true;
                }

                return false;
            };

            const openReplacePicker = (event) => {
                if (event) {
                    event.preventDefault();
                    event.stopPropagation();
                    if (typeof event.stopImmediatePropagation === 'function') event.stopImmediatePropagation();
                }

                const now = Date.now();
                const lastOpen = Number(btn.dataset.vmoReplaceOpenedAt || '0');
                if (now - lastOpen < 350) return false;

                btn.dataset.vmoReplaceOpenedAt = String(now);
                dispatchReplacePicker(buildReplacePayload());
                return false;
            };

            const inlinePayload = JSON.stringify(buildReplacePayload()).replace(/</g, '\\u003c');
            btn.setAttribute('onclick', `event.preventDefault();event.stopPropagation();window.parent&&window.parent.postMessage({action:'vmoOpenMediaPicker',data:${inlinePayload}},'*');return false;`);
            ['pointerdown', 'mousedown', 'touchstart', 'click'].forEach(eventName => {
                btn.addEventListener(eventName, openReplacePicker, true);
            });
            
            // Append button to parent
            parent.appendChild(btn);
            
            // Add a data attribute to track that this element has a button
            el.setAttribute('data-vmo-has-button', 'true');
        });

        console.log(`🎉 Replace button injection complete: ${allMediaEls.length} elements processed`);
        
        // Set up mutation observer to handle dynamically added content
        if (!doc._vmoMutationObserver) {
            let debounceTimer = null;

            const isEditorOnlyMutationNode = (node) => {
                return !!(node && node.nodeType === 1 && node.matches && (
                    node.matches('.vmo-replace-overlay, .vmo-replace-btn, .vmo-replace-media-btn, .replace-image-btn, .replace-video-btn, [data-vmo-editor-only="media-replace-overlay"], [data-noneditable="1"]') ||
                    (node.closest && node.closest('.vmo-replace-overlay, .vmo-replace-btn, .vmo-replace-media-btn, .replace-image-btn, .replace-video-btn, [data-vmo-editor-only="media-replace-overlay"], [data-noneditable="1"]'))
                ));
            };
            
            const observer = new MutationObserver((mutations) => {
                if (doc._vmoInjectingReplaceButtons) {
                    return;
                }

                let hasNewMedia = false;
                mutations.forEach(mutation => {
                    if (mutation.type === 'childList') {
                        mutation.addedNodes.forEach(node => {
                            if (node.nodeType === 1) { // Element node
                                if (isEditorOnlyMutationNode(node)) {
                                    return;
                                }

                                // Check if added node or its children contain media
                                const newMediaElements = [node, ...node.querySelectorAll('img, video, canvas, svg, iframe, [style*="background-image"]')]
                                    .filter(el => !isEditorOnlyMutationNode(el));
                                if (newMediaElements.some(el => isValidMediaElement(el))) {
                                    hasNewMedia = true;
                                }
                            }
                        });
                    }
                });
                
                if (hasNewMedia) {
                    console.log('🔄 New media detected, scheduling button injection...');
                    
                    // Debounce to avoid excessive re-injections
                    clearTimeout(debounceTimer);
                    debounceTimer = setTimeout(() => {
                        if (!doc._vmoInjectingReplaceButtons) {
                            vmoInjectReplaceButtonsInIframe();
                        }
                    }, 300);
                }
            });
            
            const targetNode = doc && doc.body;
            if (targetNode && targetNode.nodeType === 1) {
                observer.observe(targetNode, {
                    childList: true,
                    subtree: true,
                    attributes: false
                });
                doc._vmoMutationObserver = observer;
                console.log('👀 Mutation observer set up for dynamic content');
            } else {
                console.warn('[VMO Theme] Skipped mutation observer setup: no valid document body found');
            }
        }
        } finally {
            doc._vmoInjectingReplaceButtons = false;
        }
    }

    /* ------------------------------------------------------------------
       2.  "VIEW IN BROWSER" BUTTON
       Opens the current local site preview in a new browser tab.
       ------------------------------------------------------------------ */
    $(document).on('click', '#vmo-view-browser-btn', function () {
        const showcasePreviewActive = isShowcasePlaceholderActive();
        const persistedPreview = readPersistedPreviewState();
        const currentIframePreview = getCurrentPreviewHtml();

        // Always sync lastContent from vmoState if available
        if (window.vmoState && window.vmoState.blocks && window.vmoState.blocks.length) {
            window.lastContent = window.vmoState.blocks.map(b => b.html).join('\n');
        }

        if (typeof window.vmoNormalizeBuilderHtml === 'function') {
            window.lastContent = window.vmoNormalizeBuilderHtml(window.lastContent || '');
        }
        
        // Fallback: try localStorage checkpoint if lastContent is still empty
        if ((!window.lastContent || !window.lastContent.trim())
            || (typeof window.vmoShouldTreatAsRealContent === 'function' && !window.vmoShouldTreatAsRealContent(window.lastContent, window.vmoState))) {
            window.lastContent = '';
            try {
                var lsHtml = localStorage.getItem('vmo_checkpoint_html');
                var normalizedLsHtml = typeof window.vmoNormalizeBuilderHtml === 'function'
                    ? window.vmoNormalizeBuilderHtml(lsHtml)
                    : (lsHtml || '');
                if (normalizedLsHtml && normalizedLsHtml.trim()
                    && (typeof window.vmoShouldTreatAsRealContent !== 'function' || window.vmoShouldTreatAsRealContent(normalizedLsHtml, window.vmoState))) {
                    window.lastContent = normalizedLsHtml;
                }
            } catch (e) { /* ignore */ }
        }

        let previewPayload = currentIframePreview || '';
        if (!previewPayload && showcasePreviewActive && typeof window.vmoGetShowcasePreviewHtml === 'function') {
            previewPayload = window.vmoGetShowcasePreviewHtml();
        }
        if (!previewPayload && !showcasePreviewActive) {
            previewPayload = window.lastContent || '';
        }
        if (!previewPayload && persistedPreview && persistedPreview.html) {
            previewPayload = persistedPreview.html;
        }
        if (!showcasePreviewActive && typeof window.vmoShouldTreatAsRealContent === 'function' && !window.vmoShouldTreatAsRealContent(previewPayload, window.vmoState)) {
            previewPayload = '';
        }

        if (!previewPayload || !previewPayload.trim()) {
            return showToast(showcasePreviewActive
                ? 'The demo showcase is still being prepared. Please wait for the preview to finish loading.'
                : 'Nothing to preview. Build or restore a website first.', 'error');
        }

        if (!showcasePreviewActive && window.vmoPreviewGateLocked === true) {
            return showToast('Preview is locked until final QA passes and required media is complete.', 'error');
        }

        // Prefer a full HTML document so the preview renders exactly like the builder.
        // This allows the preview endpoint to split head/body/footer and use the VMO template runtime.
        try {
            if (typeof window.wrapIframeContent === 'function') {
                previewPayload = window.wrapIframeContent(previewPayload);
            }
        } catch (e) {
            // fall back to raw HTML
        }

        showToast(showcasePreviewActive ? 'Opening demo showcase in browser...' : 'Opening in browser...', 'info', true);

        $.post(vmo_ajax.ajaxurl, {
            action  : 'vmo_preview_in_browser',
            security: vmo_ajax.nonce,
            post_id : window.currentProjectId || window.currentPostId || '',
            content : previewPayload
        }).done(res => {
            hideToast(true);
            const previewLink = res && res.success && res.data && res.data.link ? res.data.link : '';

            if (previewLink) {
                window.open(previewLink, '_blank', 'noopener,noreferrer');
            } else {
                showToast(res.data?.message || 'Failed to open preview.', 'error');
            }
        }).fail(() => {
            hideToast(true);
            showToast('Failed to generate preview.', 'error');
        });
    });

    /* ------------------------------------------------------------------
       3.  THEME & UI TOGGLES
       ------------------------------------------------------------------ */
    $('#vmo-theme-toggle').off('click').on('click', () => {
        $('body').toggleClass('vmo-light-mode');
        localStorage.setItem('vmo-theme', $('body').hasClass('vmo-light-mode') ? 'light' : 'dark');
    });

    if (localStorage.getItem('vmo-theme') === 'light') $('body').addClass('vmo-light-mode');

    /* Code <-> Preview toggle with token-based access control */
    $('#vmo-view-code-btn').off('click').on('click', function () {
        const showingCode = $('#vmo-code-view').is(':visible');
        
        // Check if trying to show code view (not hide it)
        if (!showingCode) {
            // Check token balance for code view access
            const currentBalance = parseInt(vmo_ajax.token_balance) || 0;
            
            if (currentBalance <= 0) {
                // No balance = no code view access
                if (typeof window.showToast === 'function') {
                    window.showToast('🔒 Code view requires an active balance. Upgrade or add an add-on to access premium features.', 'warning');
                }
                return; // Block code view access
            }
        }
        
        $('#vmo-preview-title').text(showingCode ? 'Live Preview' : 'Code View');
        $('#vmo-code-view').toggle(!showingCode);
        $('#vmo-preview-iframe').toggle(showingCode);
    });

    /* Click‑outside to close dropdown menus */
    $(document).on('click', e => {
        if (!$(e.target).closest('.vmo-load-toggle-group, #vmo_load_project_btn').length) {
            $('#vmo-load-menu').removeClass('open');
        }
        if (!$(e.target).closest('.vmo-upgrade-toggle-group').length) {
            $('#vmo-upgrade-menu').removeClass('open');
        }
    });

    // Global binding for replace button injection
    window.vmoInjectReplaceButtonsInIframe = vmoInjectReplaceButtonsInIframe;

    // Auto inject after a brief delay
    $(document).ready(function() {
        setTimeout(vmoInjectReplaceButtonsInIframe, 250);
    });

})(jQuery);