/*-------------------------------------------------------------------
 VMO AI Website Builder – Main Admin Script (REV—autosave+undo 2025‑06‑27)
-------------------------------------------------------------------*/


































































































































































































// Corrupted PHP content removed
console.log('🚀 VMO AI Builder UNIFIED v8.0.0 - Main Script Loading!');
(function ($) {
    // WordPress admin loads jQuery in noConflict mode; ensure `$` is jQuery inside this scope.
    $ = window.jQuery || $;
    if (typeof $ !== 'function') {
        console.error('[VMO] jQuery not available; aborting vmo-main.js init');
        return;
    }
    // 🔒 GATEKEEPER: FORCE PLAN SELECTION ON FIRST LOAD
    // If the user has no plan, redirect them to the "My Plan" page immediately.
    if (typeof vmo_ajax !== 'undefined') {
        const urlParams = new URLSearchParams(window.location.search);
        const page = urlParams.get('page');
        const isVmoPage = page && page.startsWith('vmo-');
        const isPlanPage = page === 'vmo-my-plan';
        const isPaymentSuccess = urlParams.get('payment') === 'success';
        const hasPlan = vmo_ajax.current_plan && vmo_ajax.current_plan !== '';

        if (isVmoPage && !isPlanPage && !hasPlan) {
            
            // Allow temporary access if returning from successful payment (to process activation)
            if (isPaymentSuccess) {
                console.log('💳 Payment success detected. Verifying activation...');
            } 
            // VMO: Bypass Check for Admin/Management Plan
            else if (vmo_ajax.user_roles && (vmo_ajax.user_roles.includes('administrator') || vmo_ajax.user_roles.includes('vmo_manager'))) {
                console.log('🛡️ Admin/Manager Bypass Active for Plan Check');
            }
            // VMO: Standard User Redirect
            else {
                console.warn('🔒 No active plan detected. Redirecting to Plan Selection...');

                // Show Toast Notification (if toast utility available, or fallback to alert/console)
                if (typeof vmo_toast_notification === 'function') {
                    vmo_toast_notification('Subscription Required', 'You need an active plan to access these features.', 'info');
                }
                
                // Create professional overlay
                const $overlay = $('<div>').css({
                    'position': 'fixed', 'top': 0, 'left': 0, 'width': '100vw', 'height': '100vh',
                    'background': '#0b0f1a', 'z-index': 999999, 'display': 'flex',
                    'flex-direction': 'column', 'align-items': 'center', 'justify-content': 'center',
                    'color': 'white', 'text-align': 'center', 'font-family': 'Inter, system-ui, sans-serif'
                }).appendTo('body');
                
                $('<h1>').text('Welcome to VMO Business Suite').css({'font-size':'32px', 'margin-bottom':'15px', 'font-weight':'700'}).appendTo($overlay);
                $('<p>').text('Please select a plan to activate your AI Consultant.').css({'font-size':'18px', 'color':'#a0aec0', 'margin-bottom':'30px'}).appendTo($overlay);
                
                // Spinner
                $('<div class="vmo-loader-spinner">').css({
                    'width':'40px', 'height':'40px', 'border':'3px solid rgba(255,255,255,0.1)',
                    'border-top-color':'#0fe1ff', 'border-radius':'50%', 'animation':'spin 1s linear infinite'
                }).appendTo($overlay);

                // Add keyframes if needed
                if (!$('style#vmo-spinner-style').length) {
                    $('<style id="vmo-spinner-style">@keyframes spin {100%{transform:rotate(360deg)}}</style>').appendTo('head');
                }

                // Redirect
                const adminBase = vmo_ajax.ajaxurl.replace('admin-ajax.php', 'admin.php');
                setTimeout(() => {
                     window.location.href = `${adminBase}?page=vmo-my-plan`;
                }, 1000);
                return; // Stop execution of the rest of the script
            }
        }
    }

    /* ========== GLOBALS & HELPERS ========== */
    const $doc  = $(document);
    const $wrap = $('#vmo-ai-builder-main');

    window.lastContent             = window.lastContent || '';
    window.vmoMediaModalContext    = {};       // { mode, selector, mediaType, mediaId }

    function vmoGenerateMediaId () {
        return 'media-' + Math.random().toString(36).substr(2, 9) + '-' + Date.now();
    }
/* Build one HTML string from the current blocks – Mirrors original schema */
function vmoSyncLastContent () {
    var html = (window.vmoState?.blocks || [])
        .map(b => b.html)
        .join('\n');

    if (typeof window.vmoNormalizeBuilderHtml === 'function') {
        html = window.vmoNormalizeBuilderHtml(html);
    }

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

    window.lastContent = html;
}

    window.vmoSyncLastContent = vmoSyncLastContent;

    /* ensure each media/placeholder carries a stable id */
    function vmoEnsureMediaIdsInBlocks () {
        if (!Array.isArray(window.vmoState?.blocks)) return;
        window.vmoState.blocks.forEach(block => {
            if (!block.html) return;
            const $tmp = $('<div>'+block.html+'</div>');
            $tmp.find('.vmo-media-placeholder, img, video').each(function () {
                const $el = $(this);
                if (!$el.attr('data-media-id')) $el.attr('data-media-id', vmoGenerateMediaId());
                if (!$el.attr('data-type'))    $el.attr('data-type', $el.is('video') ? 'video' : 'image');
                if (!$el.hasClass('vmo-media-placeholder')) $el.addClass('vmo-media-placeholder');
            });
            block.html = $tmp.html();
        });
    }
    $(vmoEnsureMediaIdsInBlocks);
    window.renderBlocks = (fn => function(){ if (typeof fn==='function') fn.apply(this,arguments); vmoEnsureMediaIdsInBlocks(); })(window.renderBlocks);
    vmoSyncLastContent();   // keep lastContent in step for save / publish

    /* ========== IFRAME OVERLAY BRIDGE ========== */
    function normalizeReplaceMediaType(mediaType) {
        return mediaType === 'video' ? 'video' : 'image';
    }

    function readReplaceMediaTypeFromNode(node) {
        if (!node) return 'image';

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

        if (rawType === 'video' || node.hasAttribute('data-vmo-sora') || node.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';
    }

    function resolveMediaPickerContext(payload) {
        const iframe = document.getElementById('vmo-preview-iframe');
        const doc = iframe && iframe.contentDocument ? iframe.contentDocument : null;
        let selector = '';
        let mediaType = '';
        let mediaId = '';

        if (payload && typeof payload === 'object' && !Array.isArray(payload)) {
            selector = String(payload.selector || payload.targetSelector || '');
            mediaType = String(payload.type || payload.mediaType || '');
            mediaId = String(payload.mediaId || payload.id || '');
        } else if (payload != null) {
            mediaId = String(payload);
        }

        if (!selector && mediaId) {
            selector = `[data-media-id="${mediaId}"]`;
        }

        if (!mediaId && selector && doc) {
            const node = doc.querySelector(selector);
            mediaId = node && node.dataset ? String(node.dataset.mediaId || '') : '';
        }

        if (!mediaType && selector && doc) {
            const node = doc.querySelector(selector);
            if (node) {
                mediaType = readReplaceMediaTypeFromNode(node);
            }
        }

        return {
            selector,
            mediaType: normalizeReplaceMediaType(mediaType),
            mediaId
        };
    }

    window.vmoOpenMediaPicker = function(payload) {
        const context = resolveMediaPickerContext(payload);

        if (!context.selector) {
            if (typeof showToast === 'function') {
                showToast('No media target found.', 'error');
            }
            return;
        }

        window.vmoMediaModalContext = {
            mode: 'replace',
            selector: context.selector,
            mediaType: context.mediaType,
            mediaId: context.mediaId
        };
        openReplaceMediaModal(context.selector, context.mediaType);
    };
    
    /* Handle postMessage fallback for iframe communication */
    window.addEventListener('message', function(event) {
        console.log('[VMO PostMessage] Received message:', event.data);
        
        if (event.data && event.data.action === 'vmoOpenMediaPicker') {
            console.log('[VMO PostMessage] Handling vmoOpenMediaPicker');
            const { selector, type } = event.data.data;
            window.vmoMediaModalContext = { mode:'replace', selector, mediaType:type };
            openReplaceMediaModal(selector, type);
        } else if (event.data && event.data.action === 'openReplaceModal') {
            console.log('[VMO PostMessage] Handling openReplaceModal');
            // Handle the openReplaceModal action (supports both flat and nested payloads)
            const payload = event.data.data || event.data;
            const { selector, mediaType } = payload;
            console.log('[VMO PostMessage] Extracted payload:', { selector, mediaType });
            window.vmoMediaModalContext = { mode:'replace', selector, mediaType };
            openReplaceMediaModal(selector, mediaType);
        }
    });
    
    /* ========== DIRECT REPLACE BUTTON HANDLER ========== */
    // Handle replace button clicks directly in main window by monitoring iframe
    function setupReplaceButtonHandler() {
        const iframe = document.getElementById('vmo-preview-iframe');
        if (!iframe) return;
        
        // Remove any existing handler
        if (iframe._vmoReplaceHandler) {
            iframe.removeEventListener('load', iframe._vmoReplaceHandler);
        }
        
        // Set up handler for iframe load/reload
        iframe._vmoReplaceHandler = function() {
            const iframeDoc = iframe.contentDocument;
            if (!iframeDoc) return;
            
            console.log('🔧 Setting up replace button click handler in iframe');
            
            // Remove existing handler if any
            if (iframeDoc._vmoMainReplaceHandler) {
                iframeDoc.removeEventListener('click', iframeDoc._vmoMainReplaceHandler);
            }
            
            // Add direct click handler
            iframeDoc._vmoMainReplaceHandler = function(e) {
                const trigger = e.target && typeof e.target.closest === 'function'
                    ? e.target.closest('.vmo-replace-overlay')
                    : null;

                if (!trigger) return;
                
                console.log('🚀 Replace button clicked - direct handler!', trigger);
                e.preventDefault();
                e.stopPropagation();
                
                const mediaId = trigger.dataset.mediaId;
                const selector = `[data-media-id="${mediaId}"]`;
                const element = iframeDoc.querySelector(selector);
                const mediaType = normalizeReplaceMediaType(trigger.dataset.mediaType || readReplaceMediaTypeFromNode(element));
                
                console.log('🎯 Opening replace modal:', { selector, mediaType, mediaId });
                
                // Set context and open modal
                window.vmoMediaModalContext = { mode: 'replace', selector, mediaType, mediaId };
                openReplaceMediaModal(selector, mediaType);
            };
            
            iframeDoc.addEventListener('click', iframeDoc._vmoMainReplaceHandler, true);
            console.log('✅ Replace button handler attached to iframe document');
        };
        
        iframe.addEventListener('load', iframe._vmoReplaceHandler);
        
        // Also run immediately if iframe is already loaded
        if (iframe.contentDocument) {
            iframe._vmoReplaceHandler();
        }
    }
    
    // Initialize the handler
    $(document).ready(setupReplaceButtonHandler);
    
    /* kill legacy onclick calls that still reference the old helper */
window.vmoReplaceIframeMedia = (...args) => window.vmoOpenMediaPicker({
    iframeId : 'vmo-preview-iframe',
    selector : args[1],            // same order as before
    type     : args[2] || 'image'
});


    /* ========== MEDIA MODAL (library + DALL·E) ========== */
    function openReplaceMediaModal (selector, mediaType) {
        console.log('[VMO Replace] Modal opening with:', { selector, mediaType });
        const normalizedType = normalizeReplaceMediaType(mediaType);
        const aiButtonLabel = normalizedType === 'video' ? 'Generate With Sora' : 'Generate With GPT Image';
        const targetLabel = normalizedType === 'video' ? 'Video' : 'Image';
        
        // Ensure context is set even if called directly
        try {
            window.vmoMediaModalContext = { mode: 'replace', selector, mediaType: normalizedType };
            console.log('[VMO Replace] Context set:', window.vmoMediaModalContext);
        } catch(err) {
            console.error('[VMO Replace] Error setting context:', err);
        }
        
        console.log('[VMO Replace] Removing existing modal and creating new one');
        $('#vmo-replace-modal').remove();
        
        // Ensure we have a valid container to append the modal
        let $container = $wrap;
        if (!$container.length) {
            console.warn('[VMO Replace] Main wrapper not found, using body as fallback');
            $container = $('body');
        }
        console.log('[VMO Replace] Using container:', $container[0]);
        
        $container.append(`<div id="vmo-replace-modal" class="vmo-modal" style="display:flex;position:fixed;top:0;left:0;width:100vw;height:100vh;background:rgba(0,0,0,0.5);z-index:999999;align-items:center;justify-content:center;backdrop-filter:blur(2px);opacity:0;transition:opacity 0.3s ease;"><div class="vmo-modal-content" style="background:#001a2e;border-radius:15px;padding:30px;width:90%;max-width:650px;color:#fff;box-shadow:0 30px 80px rgba(0,226,255,0.4);border:2px solid #00e2ff;transform:scale(0.8);opacity:0;transition:all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);max-height:90vh;overflow-y:auto;">
            <h3 style="margin-top:0;color:#00e2ff;text-align:center;margin-bottom:10px;font-size:24px;">Replace ${targetLabel}</h3>
            <p style="margin:0 0 18px;color:#9fc7d6;text-align:center;font-size:14px;line-height:1.5;">Choose a replacement source. After it is inserted, you can fine-tune crop, fit, and positioning without moving the slot itself.</p>
            <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px;margin-bottom:14px;">
                <button id="vmo-replace-library" class="vmo-btn" style="background:linear-gradient(135deg,#00ff9a,#9bffdc);color:#001a2e;border:none;padding:18px 20px;border-radius:12px;font-weight:700;cursor:pointer;transition:all 0.2s ease;text-align:left;display:flex;flex-direction:column;gap:6px;">
                    <span style="font-size:17px;">Media Library</span>
                    <span style="font-size:13px;font-weight:500;opacity:0.8;">Pick a ${targetLabel.toLowerCase()} already stored in WordPress.</span>
                </button>
                <button id="vmo-replace-generate" class="vmo-btn" style="background:#003054;color:${normalizedType === 'video' ? '#ff9a73' : '#00e2ff'};border:1px solid ${normalizedType === 'video' ? '#ff6b35' : '#00e2ff'};padding:18px 20px;border-radius:12px;font-weight:700;cursor:pointer;transition:all 0.2s ease;text-align:left;display:flex;flex-direction:column;gap:6px;">
                    <span style="font-size:17px;">${aiButtonLabel}</span>
                    <span style="font-size:13px;font-weight:500;opacity:0.8;">${normalizedType === 'video' ? 'Use Sora to generate a replacement clip for this slot.' : 'Use GPT image generation for a replacement visual in this slot.'}</span>
                </button>
            </div>
            <div style="display:flex;justify-content:center;gap:12px;align-items:center;flex-wrap:wrap;margin-bottom:20px;">
                <button id="vmo-open-fit-controls" class="vmo-btn" style="background:transparent;color:#9fc7d6;border:1px dashed rgba(159,199,214,0.55);padding:10px 16px;border-radius:999px;font-weight:600;cursor:pointer;transition:all 0.2s ease;">Adjust Current Fit</button>
                <button id="vmo-close-replace-modal" class="vmo-btn" style="background:#333;color:#fff;border:none;padding:12px 24px;border-radius:8px;font-weight:600;cursor:pointer;transition:all 0.2s ease;">Cancel</button>
            </div>
            <div id="vmo-gen-replace-form" style="display:none;margin-top:15px;">
                <textarea id="vmo-gen-replace-desc" placeholder="Describe your replacement image..." style="width:100%;min-height:60px;background:#003054;color:#fff;border:1px solid #00e2ff;border-radius:8px;padding:12px;font-family:inherit;font-size:14px;box-sizing:border-box;margin-bottom:15px;"></textarea>
                <button id="vmo-submit-replace-gen" class="vmo-btn" style="background:#00ff9a;color:#001a2e;border:none;padding:12px 30px;border-radius:8px;font-weight:600;cursor:pointer;width:100%;font-size:16px;transition:all 0.2s ease;">Generate</button>
            </div>
            <div id="vmo-gen-video-form" style="display:none;margin-top:15px;">
                <p style="font-size:13px;color:#8899aa;margin-bottom:10px;">Generate a professional AI video using Sora 2 Pro. Videos are billed per second.</p>
                <textarea id="vmo-gen-video-desc" placeholder="Describe the video you want (e.g., 'Cinematic aerial shot of a modern office building at sunset with smooth camera motion')..." style="width:100%;min-height:70px;background:#003054;color:#fff;border:1px solid #ff6b35;border-radius:8px;padding:12px;font-family:inherit;font-size:14px;box-sizing:border-box;margin-bottom:12px;"></textarea>
                <div style="display:flex;gap:12px;align-items:center;margin-bottom:12px;flex-wrap:wrap;">
                    <label style="font-size:13px;color:#8899aa;">Duration:</label>
                    <select id="vmo-video-duration" style="background:#003054;color:#fff;border:1px solid #ff6b35;border-radius:6px;padding:8px 12px;font-size:13px;">
                        <option value="4">4 seconds (~25,200 tokens)</option>
                        <option value="8">8 seconds (~50,400 tokens)</option>
                        <option value="12">12 seconds (~75,600 tokens)</option>
                    </select>
                    <label style="font-size:13px;color:#8899aa;">Quality:</label>
                    <select id="vmo-video-quality" style="background:#003054;color:#fff;border:1px solid #ff6b35;border-radius:6px;padding:8px 12px;font-size:13px;">
                        <option value="pro">Sora 2 Pro (HD)</option>
                        <option value="standard">Sora 2 Standard</option>
                    </select>
                </div>
                <button id="vmo-submit-video-gen" class="vmo-btn" style="background:#ff6b35;color:#fff;border:none;padding:12px 30px;border-radius:8px;font-weight:600;cursor:pointer;width:100%;font-size:16px;transition:all 0.2s ease;">🎬 Generate Video</button>
                <div id="vmo-video-gen-progress" style="display:none;margin-top:12px;padding:12px;background:#002040;border-radius:8px;text-align:center;">
                    <div style="color:#ff6b35;font-weight:600;">Generating video...</div>
                    <div id="vmo-video-gen-status" style="color:#8899aa;font-size:13px;margin-top:6px;">Submitting to Sora AI...</div>
                    <div style="background:#003054;border-radius:4px;height:6px;margin-top:10px;overflow:hidden;">
                        <div id="vmo-video-gen-bar" style="background:linear-gradient(90deg,#ff6b35,#ffaa00);height:100%;width:0%;transition:width 0.5s ease;border-radius:4px;"></div>
                    </div>
                </div>
            </div>
            <div id="vmo-overlay-form" style="display:none;margin-top:15px;">
                <p style="font-size:13px;color:#8899aa;margin-bottom:10px;">Add a visual overlay effect or your own media as an overlay layer on this section.</p>
                <div style="display:flex;gap:10px;flex-wrap:wrap;margin-bottom:15px;">
                    <button class="vmo-overlay-preset" data-preset="heroSky" style="background:#003054;color:#c084fc;border:1px solid #c084fc;padding:8px 14px;border-radius:6px;cursor:pointer;font-size:13px;transition:all 0.2s ease;">☁️ Clouds</button>
                    <button class="vmo-overlay-preset" data-preset="heroNight" style="background:#003054;color:#c084fc;border:1px solid #c084fc;padding:8px 14px;border-radius:6px;cursor:pointer;font-size:13px;transition:all 0.2s ease;">✨ Fireflies</button>
                    <button class="vmo-overlay-preset" data-preset="heroWinter" style="background:#003054;color:#c084fc;border:1px solid #c084fc;padding:8px 14px;border-radius:6px;cursor:pointer;font-size:13px;transition:all 0.2s ease;">❄️ Snow</button>
                    <button class="vmo-overlay-preset" data-preset="heroRain" style="background:#003054;color:#c084fc;border:1px solid #c084fc;padding:8px 14px;border-radius:6px;cursor:pointer;font-size:13px;transition:all 0.2s ease;">🌧️ Rain</button>
                    <button class="vmo-overlay-preset" data-preset="luxurySparkle" style="background:#003054;color:#c084fc;border:1px solid #c084fc;padding:8px 14px;border-radius:6px;cursor:pointer;font-size:13px;transition:all 0.2s ease;">💎 Sparkles</button>
                    <button class="vmo-overlay-preset" data-preset="atmospheric" style="background:#003054;color:#c084fc;border:1px solid #c084fc;padding:8px 14px;border-radius:6px;cursor:pointer;font-size:13px;transition:all 0.2s ease;">🌫️ Fog</button>
                    <button class="vmo-overlay-preset" data-preset="dramatic" style="background:#003054;color:#c084fc;border:1px solid #c084fc;padding:8px 14px;border-radius:6px;cursor:pointer;font-size:13px;transition:all 0.2s ease;">💨 Smoke</button>
                    <button class="vmo-overlay-preset" data-preset="romantic" style="background:#003054;color:#c084fc;border:1px solid #c084fc;padding:8px 14px;border-radius:6px;cursor:pointer;font-size:13px;transition:all 0.2s ease;">🌸 Petals</button>
                    <button class="vmo-overlay-preset" data-preset="autumn" style="background:#003054;color:#c084fc;border:1px solid #c084fc;padding:8px 14px;border-radius:6px;cursor:pointer;font-size:13px;transition:all 0.2s ease;">🍂 Leaves</button>
                    <button class="vmo-overlay-preset" data-preset="campfire" style="background:#003054;color:#c084fc;border:1px solid #c084fc;padding:8px 14px;border-radius:6px;cursor:pointer;font-size:13px;transition:all 0.2s ease;">🔥 Embers</button>
                    <button class="vmo-overlay-preset" data-preset="underwater" style="background:#003054;color:#c084fc;border:1px solid #c084fc;padding:8px 14px;border-radius:6px;cursor:pointer;font-size:13px;transition:all 0.2s ease;">🫧 Bubbles</button>
                    <button class="vmo-overlay-preset" data-preset="interactive" style="background:#003054;color:#c084fc;border:1px solid #c084fc;padding:8px 14px;border-radius:6px;cursor:pointer;font-size:13px;transition:all 0.2s ease;">💧 Ripples</button>
                </div>
                <div style="margin-bottom:12px;">
                    <label style="font-size:13px;color:#8899aa;display:block;margin-bottom:6px;">Or upload your own overlay media:</label>
                    <button id="vmo-overlay-upload" class="vmo-btn" style="background:#c084fc;color:#001a2e;border:none;padding:10px 20px;border-radius:8px;font-weight:600;cursor:pointer;transition:all 0.2s ease;">📁 Upload Custom Image/Video Overlay</button>
                </div>
                <div style="display:flex;gap:12px;align-items:center;margin-bottom:12px;flex-wrap:wrap;">
                    <label style="font-size:13px;color:#8899aa;">Opacity:</label>
                    <input id="vmo-overlay-opacity" type="range" min="10" max="100" value="70" style="flex:1;accent-color:#c084fc;">
                    <span id="vmo-overlay-opacity-val" style="color:#c084fc;font-size:13px;">70%</span>
                    <label style="font-size:13px;color:#8899aa;">Speed:</label>
                    <input id="vmo-overlay-speed" type="range" min="10" max="150" value="50" style="flex:1;accent-color:#c084fc;">
                    <span id="vmo-overlay-speed-val" style="color:#c084fc;font-size:13px;">0.5x</span>
                </div>
            </div></div></div>`);

        const $modal = $('#vmo-replace-modal').data('type', mediaType);
        console.log('[VMO Replace] Modal created:', $modal.length ? 'SUCCESS' : 'FAILED');
        
        // Add entrance animation
        setTimeout(() => {
            console.log('[VMO Replace] Starting entrance animation');
            $modal.css('opacity', '1');
            $modal.find('.vmo-modal-content').css({
                'transform': 'scale(1)',
                'opacity': '1'
            });
            console.log('[VMO Replace] Modal should now be visible');
        }, 50);
        
        // Close modal with animation
        $('#vmo-close-replace-modal').on('click', ()=> {
            $modal.css('opacity', '0');
            setTimeout(() => $modal.remove(), 300);
        });
        
        // Close on background click
        $modal.on('click', function(e) {
            if (e.target === this) {
                $(this).css('opacity', '0');
                setTimeout(() => $(this).remove(), 300);
            }
        });

        /* WP Media */
        let frame=null;
        $('#vmo-replace-library').on('click', ()=>{
            console.log('[VMO Replace] Media library button clicked');
            if (frame) {
                console.log('[VMO Replace] Reopening existing media frame');
                return frame.open();
            }
            
            console.log('[VMO Replace] Creating new media frame for type:', mediaType);
            frame = wp.media({ title:'Select Replacement', button:{ text:'Replace'}, multiple:false, library:{type:normalizedType==='video'?[ 'video']:[ 'image']} });
            
            frame.on('select', ()=>{
                console.log('[VMO Replace] Media selected from library');
                const url = frame.state().get('selection').first().toJSON().url;
                console.log('[VMO Replace] Selected URL:', url);
                vmoOnMediaSelected(url, { openAdjuster: true, source: 'library' });
                $modal.remove();
            });
            
            frame.open();
        });

        /* Generate */
        $('#vmo-replace-generate').on('click', ()=> {
            console.log('[VMO Replace] Generate button clicked');
            $('#vmo-gen-replace-form').toggle(normalizedType !== 'video');
            $('#vmo-gen-video-form').toggle(normalizedType === 'video');
        });

        $('#vmo-open-fit-controls').on('click', () => {
            $modal.remove();
            if (typeof window.openMediaPlacementAdjuster === 'function') {
                window.openMediaPlacementAdjuster(window.vmoMediaModalContext || {});
            }
        });
        
        $('#vmo-submit-replace-gen').on('click', ()=>{
            console.log('[VMO Replace] Generate submit clicked');
            const desc = $('#vmo-gen-replace-desc').val().trim();
            if (!desc) {
                console.log('[VMO Replace] No description provided');
                return showToast('Describe the image first.','error');
            }
            
            console.log('[VMO Replace] Starting image generation for:', desc);
            showToast('Generating image...','info',false,true);
            
            $.post(vmo_ajax.ajaxurl,{action:'vmo_generate_image',security:vmo_ajax.nonce,desc},res=>{
                hideToast(true);
                console.log('[VMO Replace] Generation response:', res);
                if (res.success) {
                    console.log('[VMO Replace] Generation successful, replacing media');
                    vmoOnMediaSelected(res.data.url, { openAdjuster: true, source: 'ai-image' });
                    $modal.remove();
                } else {
                    console.log('[VMO Replace] Generation failed:', res.data?.message);
                    showToast(res.data?.message || 'Failed to generate image.', 'error');
                }
            }).fail(() => {
                hideToast(true);
                console.error('[VMO Replace] Generation request failed');
                showToast('Generation failed. Please try again.', 'error');
            });
        });

        /* ========== Sora Video Generation ========== */

        // Opacity/speed slider display
        $('#vmo-overlay-opacity').on('input', function() { $('#vmo-overlay-opacity-val').text(this.value + '%'); });
        $('#vmo-overlay-speed').on('input', function() { $('#vmo-overlay-speed-val').text((this.value / 100).toFixed(1) + 'x'); });

        $('#vmo-submit-video-gen').on('click', async () => {
            const desc = $('#vmo-gen-video-desc').val().trim();
            if (!desc) return showToast('Describe the video first.', 'error');

            const seconds = parseInt($('#vmo-video-duration').val()) || 4;
            const quality = $('#vmo-video-quality').val() || 'pro';
            const model = quality === 'pro' ? 'sora-2-pro' : 'sora-2';

            // Show progress
            $('#vmo-submit-video-gen').prop('disabled', true).text('Generating...');
            $('#vmo-video-gen-progress').show();
            $('#vmo-video-gen-status').text('Submitting to Sora AI...');
            $('#vmo-video-gen-bar').css('width', '5%');

            try {
                // Step 1: Submit video generation job
                const genRes = await $.post(vmo_ajax.ajaxurl, {
                    action: 'vmo_generate_video',
                    security: vmo_ajax.nonce,
                    prompt: desc,
                    seconds: seconds,
                    model: model,
                    size: '1920x1080'
                });

                if (!genRes.success) {
                    showToast(genRes.data?.message || 'Video generation failed.', 'error');
                    $('#vmo-submit-video-gen').prop('disabled', false).text('🎬 Generate Video');
                    $('#vmo-video-gen-progress').hide();
                    return;
                }

                const videoId = genRes.data.video_id;
                $('#vmo-video-gen-status').text('Video queued — polling for completion...');
                $('#vmo-video-gen-bar').css('width', '15%');

                // Step 2: Poll until complete
                let attempts = 0;
                const maxAttempts = 120; // 10 minutes max
                const poll = async () => {
                    attempts++;
                    try {
                        const statusRes = await $.post(vmo_ajax.ajaxurl, {
                            action: 'vmo_check_video_status',
                            security: vmo_ajax.nonce,
                            video_id: videoId
                        });
                        if (statusRes.success) {
                            const st = statusRes.data.status || '';
                            const pct = Math.min(90, 15 + (attempts / maxAttempts) * 75);
                            $('#vmo-video-gen-bar').css('width', pct + '%');
                            if (st === 'completed' || st === 'succeeded') {
                                $('#vmo-video-gen-status').text('Video ready! Downloading...');
                                $('#vmo-video-gen-bar').css('width', '95%');
                                // Step 3: Download and save to media library
                                const dlRes = await $.post(vmo_ajax.ajaxurl, {
                                    action: 'vmo_download_video',
                                    security: vmo_ajax.nonce,
                                    video_id: videoId
                                });
                                if (dlRes.success && dlRes.data.url) {
                                    $('#vmo-video-gen-bar').css('width', '100%');
                                    $('#vmo-video-gen-status').text('Complete! Inserting video...');
                                    // Force media type to video for replacement
                                    if (window.vmoMediaModalContext) window.vmoMediaModalContext.mediaType = 'video';
                                    setTimeout(() => {
                                        vmoOnMediaSelected(dlRes.data.url, { openAdjuster: true, source: 'ai-video' });
                                        $modal.remove();
                                    }, 500);
                                } else {
                                    showToast(dlRes.data?.message || 'Failed to download video.', 'error');
                                    $('#vmo-submit-video-gen').prop('disabled', false).text('🎬 Generate Video');
                                    $('#vmo-video-gen-progress').hide();
                                }
                            } else if (st === 'failed' || st === 'error') {
                                showToast('Video generation failed. Try a different prompt.', 'error');
                                $('#vmo-submit-video-gen').prop('disabled', false).text('🎬 Generate Video');
                                $('#vmo-video-gen-progress').hide();
                            } else {
                                $('#vmo-video-gen-status').text('Processing... (' + st + ') ' + attempts + '/' + maxAttempts);
                                if (attempts < maxAttempts) setTimeout(poll, 5000);
                                else {
                                    showToast('Video generation timed out. It may still complete — check Media Library later.', 'error');
                                    $('#vmo-submit-video-gen').prop('disabled', false).text('🎬 Generate Video');
                                }
                            }
                        } else {
                            if (attempts < maxAttempts) setTimeout(poll, 5000);
                        }
                    } catch (pollErr) {
                        console.error('[VMO Video] Poll error:', pollErr);
                        if (attempts < maxAttempts) setTimeout(poll, 8000);
                    }
                };
                setTimeout(poll, 3000);

            } catch (err) {
                console.error('[VMO Video] Generation error:', err);
                showToast('Video generation request failed.', 'error');
                $('#vmo-submit-video-gen').prop('disabled', false).text('🎬 Generate Video');
                $('#vmo-video-gen-progress').hide();
            }
        });

        /* ========== Media Overlay Controls ========== */
        $('#vmo-replace-overlay').on('click', () => {
            console.log('[VMO Replace] Overlay panel opened');
            $('#vmo-gen-replace-form').hide();
            $('#vmo-gen-video-form').hide();
            $('#vmo-overlay-form').toggle();
        });

        // Preset overlays
        $(document).off('click.vmoOverlayPreset').on('click.vmoOverlayPreset', '.vmo-overlay-preset', function() {
            const preset = $(this).data('preset');
            const presets = window.vmoOverlayPresets || {};
            const config = presets[preset];
            if (!config) return showToast('Overlay preset not found.', 'error');

            // Apply user-configured opacity and speed
            const opacity = parseInt($('#vmo-overlay-opacity').val()) / 100;
            const speed = parseInt($('#vmo-overlay-speed').val()) / 100;
            const finalConfig = Object.assign({}, config, { opacity, speed });

            // Find the target section in iframe
            const ctx = window.vmoMediaModalContext || {};
            const iframe = document.getElementById('vmo-preview-iframe');
            if (iframe && iframe.contentDocument) {
                let targetEl = null;
                if (ctx.selector) targetEl = iframe.contentDocument.querySelector(ctx.selector);
                if (!targetEl && ctx.mediaId) targetEl = iframe.contentDocument.querySelector('[data-media-id="' + ctx.mediaId + '"]');
                const section = targetEl ? (targetEl.closest('section') || targetEl.closest('[data-block-id]') || targetEl.parentElement) : null;

                if (section) {
                    // Store overlay config as data attribute for persistence
                    section.setAttribute('data-vmo-overlay', JSON.stringify(finalConfig));
                    section.style.position = 'relative';
                    section.style.overflow = 'hidden';

                    // Initialize the overlay
                    if (window.VMOAnimatedOverlay) {
                        // Remove existing overlay on this section if any
                        const existingCanvas = section.querySelector('.vmo-overlay-canvas');
                        if (existingCanvas) existingCanvas.remove();
                        new window.VMOAnimatedOverlay(section, finalConfig);
                    }

                    // Sync back to vmoState
                    const blockEl = section.closest('[data-block-id]');
                    if (typeof window.vmoSyncPreviewStateFromIframe === 'function') {
                        window.vmoSyncPreviewStateFromIframe({
                            blockId: blockEl ? String(blockEl.dataset.blockId || '') : '',
                            markUnsaved: true,
                            autoSave: true
                        });
                    } else if (blockEl && window.vmoState?.blocks) {
                        const block = window.vmoState.blocks.find(b => String(b.id) === String(blockEl.dataset.blockId));
                        if (block) {
                            block.html = blockEl.innerHTML;
                            window.isUnsaved = true;
                            if (typeof window.autoSaveCheckpoint === 'function') window.autoSaveCheckpoint();
                        }
                    }

                    showToast('Overlay applied! ✨', 'success');
                    if (typeof window.pushUndo === 'function') window.pushUndo('Add overlay: ' + preset);
                    $modal.remove();
                } else {
                    showToast('Could not find target section for overlay.', 'error');
                }
            }
        });

        // Custom overlay upload
        let overlayFrame = null;
        $('#vmo-overlay-upload').on('click', () => {
            if (overlayFrame) return overlayFrame.open();
            overlayFrame = wp.media({ title: 'Select Overlay Media', button: { text: 'Use as Overlay' }, multiple: false });
            overlayFrame.on('select', () => {
                const attachment = overlayFrame.state().get('selection').first().toJSON();
                const url = attachment.url;
                const opacity = parseInt($('#vmo-overlay-opacity').val()) / 100;
                const speed = parseInt($('#vmo-overlay-speed').val()) / 100;
                const config = { type: 'clouds', imageUrl: url, opacity, speed, layers: 3 };

                const ctx = window.vmoMediaModalContext || {};
                const iframe = document.getElementById('vmo-preview-iframe');
                if (iframe && iframe.contentDocument) {
                    let targetEl = null;
                    if (ctx.selector) targetEl = iframe.contentDocument.querySelector(ctx.selector);
                    if (!targetEl && ctx.mediaId) targetEl = iframe.contentDocument.querySelector('[data-media-id="' + ctx.mediaId + '"]');
                    const section = targetEl ? (targetEl.closest('section') || targetEl.closest('[data-block-id]') || targetEl.parentElement) : null;

                    if (section) {
                        section.setAttribute('data-vmo-overlay', JSON.stringify(config));
                        section.setAttribute('data-overlay-image', url);
                        section.style.position = 'relative';
                        section.style.overflow = 'hidden';
                        if (window.VMOAnimatedOverlay) {
                            const existingCanvas = section.querySelector('.vmo-overlay-canvas');
                            if (existingCanvas) existingCanvas.remove();
                            new window.VMOAnimatedOverlay(section, config);
                        }
                        const blockEl = section.closest('[data-block-id]');
                        if (typeof window.vmoSyncPreviewStateFromIframe === 'function') {
                            window.vmoSyncPreviewStateFromIframe({
                                blockId: blockEl ? String(blockEl.dataset.blockId || '') : '',
                                markUnsaved: true,
                                autoSave: true
                            });
                        } else if (blockEl && window.vmoState?.blocks) {
                            const block = window.vmoState.blocks.find(b => String(b.id) === String(blockEl.dataset.blockId));
                            if (block) {
                                block.html = blockEl.innerHTML;
                                window.isUnsaved = true;
                                if (typeof window.autoSaveCheckpoint === 'function') window.autoSaveCheckpoint();
                            }
                        }
                        showToast('Custom overlay applied! ✨', 'success');
                        if (typeof window.pushUndo === 'function') window.pushUndo('Add custom overlay');
                        $modal.remove();
                    }
                }
            });
            overlayFrame.open();
        });
    }
    
    // Expose the function globally for fallback access
    window.openReplaceMediaModal = openReplaceMediaModal;
    
    // Additional exposure for debugging
    console.log('[VMO Replace] Function exposed globally:', typeof window.openReplaceMediaModal);
    
    // Force exposure to ensure iframe can access it
    if (typeof window !== 'undefined') {
        window.openReplaceMediaModal = openReplaceMediaModal;
        // Also add to global scope for iframe access
        if (typeof global !== 'undefined') {
            global.openReplaceMediaModal = openReplaceMediaModal;
        }
    }

    /* ========== INSERT MEDIA MODAL (restored from OLDER plugin with AI agent) ========== */
    function openInsertMediaModal(mode = "insert", selector = null, mediaType = "image") {
        const isReplace = (mode === "replace");
        
        // Remove any existing modal
        $('#vmo-insert-modal').remove();
        
        const modal = `
        <div id="vmo-insert-modal" class="vmo-modal" style="display:flex !important;position:fixed !important;top:0 !important;left:0 !important;width:100vw !important;height:100vh !important;background:rgba(0,0,0,0.5) !important;z-index:999999;align-items:center !important;justify-content:center !important;backdrop-filter:blur(2px);margin:0 !important;padding:0 !important;border:none !important;outline:none !important;box-sizing:border-box !important;">
            <div class="vmo-modal-content" style="background:#001a2e;border-radius:15px;padding:30px;width:90%;max-width:800px;max-height:90vh;overflow-y:auto;color:#fff;box-shadow:0 30px 80px rgba(0,226,255,0.4);border:2px solid #00e2ff;position:relative;transform:scale(1);transition:all 0.3s ease;margin:0;box-sizing:border-box;">
                <h3 style="margin-top:0;color:#00e2ff;text-align:center;margin-bottom:25px;font-size:24px;">${isReplace ? "🔄 Replace Media" : "📸 Add Media"}</h3>
                <div style="margin-bottom:15px;display:flex;gap:10px;flex-wrap:wrap;justify-content:center;">
                    <button id="vmo-insert-library" class="vmo-btn" style="background:#00ff9a;color:#001a2e;border:none;padding:10px 20px;border-radius:8px;font-weight:600;cursor:pointer;transition:all 0.2s ease;">🖼️ From Media Library</button>
                    <button id="vmo-insert-generate" class="vmo-btn" style="background:#003054;color:#00e2ff;border:1px solid #00e2ff;padding:10px 20px;border-radius:8px;font-weight:600;cursor:pointer;transition:all 0.2s ease;">🎨 Generate Image</button>
                    <button id="vmo-close-modal" class="vmo-btn" style="background:#333;color:#fff;border:none;padding:10px 20px;border-radius:8px;font-weight:600;cursor:pointer;transition:all 0.2s ease;">Cancel</button>
                </div>
                <div id="vmo-preview-images" style="display:none;gap:10px;flex-wrap:wrap;align-items:center;justify-content:center;margin:20px 0;"></div>
                <div id="vmo-what-to-do" style="display:none;margin-top:20px;">
                    <label style="font-weight:600;color:#00e2ff;display:block;margin-bottom:12px;text-align:center;">
                        ${isReplace ? "✨ Ready to replace media directly" : "🚀 How should this media be integrated?"}
                    </label>
                    ${!isReplace ? `
                    <div id="vmo-preset-prompts" style="margin-bottom:12px;display:flex;gap:8px;flex-wrap:wrap;justify-content:center;">
                        <button class="vmo-preset-btn" data-prompt="Create a visually stunning fullscreen hero section with this image, overlay text, a bold call-to-action button, and advanced parallax effect. Use modern CSS transitions and blend modes for a cinematic feel." style="background:#003054;color:#00e2ff;border:1px solid #00e2ff;padding:6px 12px;border-radius:6px;font-size:12px;cursor:pointer;transition:all 0.2s ease;">Hero Image</button>
                        <button class="vmo-preset-btn" data-prompt="Insert this video as a striking fullscreen background hero with smooth fade-in and dynamic playback controls. Ensure no overlays obscure the video. Prefer subtle gradient overlays for legibility if needed." style="background:#003054;color:#00e2ff;border:1px solid #00e2ff;padding:6px 12px;border-radius:6px;font-size:12px;cursor:pointer;transition:all 0.2s ease;">Hero Video</button>
                        <button class="vmo-preset-btn" data-prompt="Create a high-quality gallery or portfolio grid with this media. Use advanced hover transitions, fade-in and slide-up animations, and responsive masonry layout." style="background:#003054;color:#00e2ff;border:1px solid #00e2ff;padding:6px 12px;border-radius:6px;font-size:12px;cursor:pointer;transition:all 0.2s ease;">Gallery</button>
                        <button class="vmo-preset-btn" data-prompt="Insert this logo in the top left or center of the section, with high z-index and subtle drop shadow or glass effect for maximum clarity." style="background:#003054;color:#00e2ff;border:1px solid #00e2ff;padding:6px 12px;border-radius:6px;font-size:12px;cursor:pointer;transition:all 0.2s ease;">Logo</button>
                        <button class="vmo-preset-btn" data-prompt="Showcase this image in a beautiful, swipeable carousel with smooth transitions, navigation arrows, and slide indicators." style="background:#003054;color:#00e2ff;border:1px solid #00e2ff;padding:6px 12px;border-radius:6px;font-size:12px;cursor:pointer;transition:all 0.2s ease;">Carousel</button>
                        <button class="vmo-preset-btn" data-prompt="Apply this image as CSS backdrop to the section element with z-index: 1. Use inline style: background-image: url(IMAGE_URL), background-size: cover, background-position: center. Keep all existing content intact with z-index: 2+. The image must be applied directly to the section's style attribute." style="background:#4a1a7a;color:#dda0ff;border:1px solid:#9966ff;padding:6px 12px;border-radius:6px;font-size:12px;cursor:pointer;transition:all 0.2s ease;">Section Backdrop</button>
                        <button class="vmo-preset-btn" data-prompt="Layer this media on top of existing elements with high z-index (999+) for stacking and overlay effects. Position it prominently above all other content while maintaining proper viewport visibility within the iframe." style="background:#2d5a1f;color:#90ff70;border:1px solid #60cc40;padding:6px 12px;border-radius:6px;font-size:12px;cursor:pointer;transition:all 0.2s ease;">Stack On Top</button>
                    </div>
                    <textarea id="vmo-img-action-prompt" style="width:100%;min-height:60px;background:#003054;color:#fff;border:1px solid #00e2ff;border-radius:8px;padding:12px;font-family:inherit;font-size:14px;box-sizing:border-box;" placeholder="Describe how to use the media..."></textarea>
                    ` : ''}
                    <button id="vmo-img-action-send" class="vmo-btn vmo-btn-primary" style="margin-top:15px;background:#00ff9a;color:#001a2e;border:none;padding:12px 30px;border-radius:8px;font-weight:600;cursor:pointer;width:100%;font-size:16px;transition:all 0.2s ease;">${isReplace ? "Replace Now" : "Insert"}</button>
                </div>
                <div id="vmo-gen-form" style="display:none;margin-top:15px;">
                    <textarea id="vmo-gen-desc" placeholder="Describe your image..." style="width:100%;min-height:60px;background:#003054;color:#fff;border:1px solid #00e2ff;border-radius:8px;padding:12px;font-family:inherit;font-size:14px;box-sizing:border-box;margin-bottom:15px;"></textarea>
                    <button id="vmo-submit-gen" class="vmo-btn" style="background:#00ff9a;color:#001a2e;border:none;padding:12px 30px;border-radius:8px;font-weight:600;cursor:pointer;width:100%;font-size:16px;transition:all 0.2s ease;">Generate Image</button>
                </div>
            </div>
        </div>`;

        // Always append modal directly to body for true fullscreen coverage
        $('body').append(modal);
        
        // Add critical CSS to ensure true fullscreen behavior
        const modalCSS = `
        <style id="vmo-modal-fullscreen-css">
        #vmo-insert-modal.vmo-modal {
            display: flex !important;
            position: fixed !important;
            top: 0 !important;
            left: 0 !important;
            right: 0 !important;
            bottom: 0 !important;
            width: 100vw !important;
            height: 100vh !important;
            max-width: none !important;
            max-height: none !important;
            margin: 0 !important;
            padding: 0 !important;
            border: none !important;
            transform: none !important;
        }
        body.vmo-modal-open {
            overflow: hidden !important;
        }
        </style>
        `;
        
        if ($('#vmo-modal-fullscreen-css').length === 0) {
            $('head').append(modalCSS);
        }
        
        // Prevent body scroll when modal is open
        $('body').addClass('vmo-modal-open');
        
        // Set initial state for animation
        $('#vmo-insert-modal').css({
            'opacity': '0',
            'pointer-events': 'auto'
        }).find('.vmo-modal-content').css({
            'transform': 'scale(0.8)',
            'opacity': '0'
        });
        
        $('#vmo-insert-modal').data({ media: [], mode, selector, mediaType });        // Close modal on background click or cancel button
        $('#vmo-insert-modal').on('click', function(e) {
            if (e.target === this) {
                // Add fade-out animation before removing
                $(this).css('opacity', '0');
                $('body').removeClass('vmo-modal-open');
                setTimeout(() => $(this).remove(), 300);
            }
        });

        // Close modal button with animation
        $('#vmo-close-modal').on('click', () => {
            $('#vmo-insert-modal').css('opacity', '0');
            $('body').removeClass('vmo-modal-open');
            setTimeout(() => $('#vmo-insert-modal').remove(), 300);
        });

        // Add entrance animation
        setTimeout(() => {
            $('#vmo-insert-modal').css({
                'opacity': '1',
                'transition': 'opacity 0.3s ease'
            });
            $('#vmo-insert-modal .vmo-modal-content').css({
                'transform': 'scale(1)',
                'opacity': '1',
                'transition': 'all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1)'
            });
        }, 50);

        // Preset prompt buttons
        $('.vmo-preset-btn').on('click', function() {
            const prompt = $(this).data('prompt');
            $('#vmo-img-action-prompt').val(prompt);
        });

        // Ensure insert button is properly initialized
        function ensureInsertButtonReady() {
            const $insertBtn = $('#vmo-img-action-send');
            if ($insertBtn.length) {
                $insertBtn.prop('disabled', false).removeClass('vmo-btn-loading');
                console.log('[VMO Modal] Insert button initialized and ready');
            }
        }
        
        // Initialize button state
        setTimeout(ensureInsertButtonReady, 100);

        // Media library selection
        let frame = null;
        $('#vmo-insert-library').on('click', () => {
            // Temporarily lower our modal's z-index so WordPress media library can appear on top
            $('#vmo-insert-modal').css('z-index', '150000');
            
            // Also temporarily hide our modal to prevent any interference
            $('#vmo-insert-modal').css('visibility', 'hidden');
            
            if (frame) {
                frame.open();
                // Show our modal again once the media library is fully loaded
                setTimeout(() => $('#vmo-insert-modal').css('visibility', 'visible'), 100);
                return;
            }
            
            frame = wp.media({
                title: 'Select Media',
                button: { text: 'Insert' },
                multiple: true,
                library: { type: ['image', 'video'] }
            });
            
            frame.on('select', function() {
                console.log('[VMO Media] Media selection started...');
                const selections = frame.state().get('selection');
                const mediaArr = selections.map(attachment => {
                    const json = attachment.toJSON();
                    return {
                        url: json.url,
                        type: json.type,
                        title: json.title || json.filename
                    };
                });
                
                console.log('[VMO Media] Selected media:', mediaArr);
                
                // Store media data with redundancy
                $('#vmo-insert-modal').data('media', mediaArr);
                
                // Verify the data was stored correctly
                const storedMedia = $('#vmo-insert-modal').data('media');
                console.log('[VMO Media] Stored media verification:', storedMedia);
                
                displaySelectedMedia(mediaArr);
                $('#vmo-what-to-do').show();
                
                // Update button text since we're using existing media, not generating
                if (!isReplace) {
                    $('#vmo-img-action-send').text('Insert');
                }
                
                // Ensure button is enabled and ready
                const $insertBtn = $('#vmo-img-action-send');
                $insertBtn.prop('disabled', false).removeClass('vmo-btn-loading');
                console.log('[VMO Media] Insert button enabled and ready');
                
                // Restore our modal's z-index and visibility after selection
                $('#vmo-insert-modal').css({
                    'z-index': '999999',
                    'visibility': 'visible'
                });
            });
            
            // Restore z-index and visibility when media library is closed without selection
            frame.on('close', function() {
                $('#vmo-insert-modal').css({
                    'z-index': '999999',
                    'visibility': 'visible'
                });
            });
            
            // Show our modal again once the media library opens
            frame.on('open', function() {
                setTimeout(() => $('#vmo-insert-modal').css('visibility', 'visible'), 200);
            });
            
            frame.open();
        });

        // AI Image generation
        $('#vmo-insert-generate').on('click', () => {
            $('#vmo-gen-form').show();
            $('#vmo-what-to-do').hide();
        });

        $('#vmo-submit-gen').on('click', () => {
            const desc = $('#vmo-gen-desc').val().trim();
            if (!desc) return showToast('Describe the image first.', 'error');
            
            showToast('Generating image...', 'info', true, true);
            $.post(vmo_ajax.ajaxurl, {
                action: 'vmo_generate_image',
                security: vmo_ajax.nonce,
                desc: desc
            }, res => {
                hideToast(true);
                if (res.success && res.data?.url) {
                    const mediaArr = [{
                        url: res.data.url,
                        type: 'image',
                        title: 'Generated Image'
                    }];
                    console.log('[VMO Generate] Generated media:', mediaArr);
                    
                    $('#vmo-insert-modal').data('media', mediaArr);
                    
                    // Verify the data was stored correctly
                    const storedMedia = $('#vmo-insert-modal').data('media');
                    console.log('[VMO Generate] Stored media verification:', storedMedia);
                    
                    displaySelectedMedia(mediaArr);
                    $('#vmo-gen-form').hide();
                    $('#vmo-what-to-do').show();
                    
                    // Update button text since we generated media with AI
                    $('#vmo-img-action-send').text('Generate & Insert');
                    
                    // Ensure button is enabled and ready
                    const $insertBtn = $('#vmo-img-action-send');
                    $insertBtn.prop('disabled', false).removeClass('vmo-btn-loading');
                    console.log('[VMO Generate] Insert button enabled and ready');
                } else {
                    showToast(res.data?.message || 'Image generation failed.', 'error');
                }
            }).fail(() => {
                hideToast(true);
                showToast('Generation failed. Please try again.', 'error');
            });
        });

        function displaySelectedMedia(mediaArr) {
            const previewHtml = mediaArr.map(m => {
                if (m.type === 'video' || /\.(mp4|webm|ogg)$/i.test(m.url)) {
                    return `<video src="${m.url}" style="max-width:150px;max-height:100px;border-radius:6px;" muted></video>`;
                } else {
                    return `<img src="${m.url}" style="max-width:150px;max-height:100px;border-radius:6px;object-fit:cover;" alt="${m.title || 'Media'}">`;
                }
            }).join('');
            
            $('#vmo-preview-images').html(previewHtml).show();
        }
    }

    // Enhanced AI-powered insert action with dedicated agent
    $(document).off('click.vmoSendMedia').on('click.vmoSendMedia', '#vmo-img-action-send', function () {
        console.log('[VMO Insert] Button clicked - checking button state and data...');
        
        // Check if button is already disabled/loading
        const $button = $(this);
        if ($button.prop('disabled') || $button.hasClass('vmo-btn-loading')) {
            console.log('[VMO Insert] Button is disabled or loading, ignoring click');
            return false;
        }
        
        const mediaArr = $('#vmo-insert-modal').data('media') || [];
        const modalData = $('#vmo-insert-modal').data();
        const { mode, selector, mediaType } = modalData;
        
        console.log('[VMO Insert] Media data:', mediaArr, 'Modal data:', modalData);
        
        if (!mediaArr.length) {
            console.log('[VMO Insert] No media found in modal data');
            return showToast('Select or generate at least one image / video first.', 'error');
        }
        
        // **REPLACE MODE: Direct replacement without AI**
        if (mode === 'replace') {
            if (mediaArr.length > 0) {
                window.vmoOnMediaSelected(mediaArr[0].url, { openAdjuster: true, source: 'replace-modal' });
                $('body').removeClass('vmo-modal-open');
                $('#vmo-insert-modal').remove();
            }
            return;
        }
        
        // **INSERT MODE: AI-integrated with enhanced dedicated agent**
        const prompt = $('#vmo-img-action-prompt').val().trim();
        if (!prompt) return showToast('Describe how to use the media.', 'error');

        // Check if user has selected a specific element
        if (window.vmoElementRefiner && window.vmoElementRefiner.selectedElement) {
            // ELEMENT-SPECIFIC REFINEMENT MODE
            const mediaUrl = mediaArr[0]?.url;
            if (!mediaUrl) return showToast('Media URL not found', 'error');
            
            if (window.showToast) {
                window.showToast('Applying media to selected element...', 'info', true, true);
            }
            
            // Use element-specific refinement
            if (window.refineSelectedElement) {
                window.refineSelectedElement(prompt, mediaUrl);
                
                // Close modal and clear selection
                $('#vmo-insert-modal').remove();
                $('body').removeClass('vmo-modal-open');
                
                if (window.clearElementSelection) {
                    window.clearElementSelection();
                }
            } else {
                showToast('Element refinement system not loaded', 'error');
            }
            return;
        }

        // Always pass full structure for smart context
        let sectionMap = "";
        let fullPageHtml = "";
        if (window.vmoState && Array.isArray(window.vmoState.blocks)) {
            sectionMap = window.vmoState.blocks.map((b, i) => `<!-- SECTION ${i+1} -->: ${b.type || 'Section'}`).join('\n');
            fullPageHtml = window.vmoState.blocks.map(b => b.html).join('\n\n');
        }

        // Compose media HTML block
        const mediaHtmlArr = mediaArr.map(m =>
            (m.type === 'video' || /\.(mp4|webm|ogg)$/i.test(m.url))
              ? `<video src="${m.url}" autoplay muted loop playsinline style="max-width:100%"></video>`
              : `<img src="${m.url}" alt="" style="max-width:100%" />`
        ).join('\n');

        // Enhanced user prompt with full context awareness
        const enhancedPrompt = `
CURRENT PAGE STRUCTURE:
${sectionMap}

CURRENT FULL PAGE HTML:
${fullPageHtml}

USER INSTRUCTION:
${prompt}

SELECTED MEDIA TO INTEGRATE:
${mediaHtmlArr}

REQUIREMENTS:
- Analyze my instruction and enhance it with professional design insights
- If I mention specific sections, target only those sections
- If I mention effects like overlays, animations, or scroll interactions, implement them with modern techniques
- If I mention carousels, implement with appropriate libraries (Splide.js recommended)
- If I mention background media, implement with proper layering and responsive design
- Return the complete updated HTML for the entire page
- Maintain all section numbering and structure
- Use semantic HTML and modern CSS/JS techniques
        `.trim();

        // Prevent double submissions
        const $submitBtn = $('#vmo-img-action-send');
        if ($submitBtn.prop('disabled') || $submitBtn.hasClass('vmo-btn-loading')) {
            console.log('[VMO Insert] Button already processing, preventing double submission');
            return false;
        }
        
        console.log('[VMO Insert] Disabling button and starting AJAX request');
        $submitBtn.prop('disabled', true).addClass('vmo-btn-loading');
        
        // Add a fail-safe timeout to re-enable button if something goes wrong
        const failsafeTimeout = setTimeout(() => {
            console.log('[VMO Insert] Fail-safe timeout triggered - re-enabling button');
            $submitBtn.prop('disabled', false).removeClass('vmo-btn-loading');
            if (window.hideToast) hideToast(true);
            showToast('Request timed out. Please try again.', 'error');
        }, 60000); // 60 second timeout

        // Intelligent section detection - check for selected section or use hero detection
        let targetSectionIndex = 0;
        let targetSectionHtml = window.vmoState?.blocks?.[0]?.html || '';
        
        // Check if user has selected a specific section
        if (window.vmoState && window.vmoState.selectedBlockIndex !== undefined && window.vmoState.selectedBlockIndex >= 0) {
            targetSectionIndex = window.vmoState.selectedBlockIndex;
            targetSectionHtml = window.vmoState.blocks?.[targetSectionIndex]?.html || '';
            console.log('[VMO Insert] Using selected section index:', targetSectionIndex);
        }
        // If prompt mentions hero/header/main, always target section 0
        else if (/hero|header|main|banner|landing|fullscreen|top\s*section/i.test(enhancedPrompt)) {
            targetSectionIndex = 0;
            targetSectionHtml = window.vmoState?.blocks?.[0]?.html || '';
            console.log('[VMO Insert] Hero detected - targeting section 0');
        }

        // Send to enhanced backend AI agent
        showToast('🤖 AI Agent processing media integration...', 'info', true, true);
        $.ajax({
            url: vmo_ajax.ajaxurl,
            method: 'POST',
            dataType: 'json',
            data: {
                action: 'vmo_insert_media_section',
                security: vmo_ajax.nonce,
                media_url: mediaArr[0].url,
                media_type: mediaArr[0].type || 'image',
                prompt: enhancedPrompt,
                section_index: targetSectionIndex,
                full_page_html: fullPageHtml,
                section_html: targetSectionHtml
            }
        }).done(res => {
            hideToast(true);

            if (res.success && res.data?.html) {
                // Split the HTML output back into sections
                let newBlocks = [];
                let html = res.data.html.replace(/<\/?(html|head|body|prompt)[^>]*>/gi, '')
                                       .replace(/<!DOCTYPE[^>]*>/gi, '')
                                       .trim();

                // Simple splitter: looks for <!-- SECTION N -->
                let split = html.split(/(<!--\s*SECTION\s*\d+.*?-->)/gi);
                let curSection = "";
                split.forEach((chunk, i) => {
                    if (/<!--\s*SECTION\s*\d+/i.test(chunk)) {
                        if (curSection.trim()) newBlocks.push({ 
                            html: curSection.trim(), 
                            type: 'section', 
                            id: window.getUniqueBlockId ? window.getUniqueBlockId() : Date.now().toString()
                        });
                        curSection = chunk;
                    } else {
                        curSection += chunk;
                    }
                });
                if (curSection.trim()) newBlocks.push({ 
                    html: curSection.trim(), 
                    type: 'section', 
                    id: window.getUniqueBlockId ? window.getUniqueBlockId() : Date.now().toString()
                });
                
                // Overwrite blocks with new structure
                if (typeof window.pushUndo === 'function') window.pushUndo();
                window.vmoState.blocks = newBlocks;
                if (typeof window.renderBlocks === 'function') window.renderBlocks();
                window.isUnsaved = true;
                if (typeof window.autoSaveCheckpoint === 'function') window.autoSaveCheckpoint();
                if (typeof window.vmoInjectReplaceButtonsInIframe === 'function') window.vmoInjectReplaceButtonsInIframe();
                
                showToast('🎉 Media integrated successfully by AI Agent!', 'success');
                $('body').removeClass('vmo-modal-open');
                $('#vmo-insert-modal').remove();
            } else {
                const msg = res?.data?.message || 'Failed to integrate media.';
                showToast('AI Agent: ' + msg, 'error');
            }
        }).fail((xhr) => {
            hideToast(true);
            // Try to surface server-provided error message
            let msg = 'AI Agent encountered a server error.';
            try {
                if (xhr.responseJSON && xhr.responseJSON.data && xhr.responseJSON.data.message) {
                    msg = 'AI Agent: ' + xhr.responseJSON.data.message;
                } else if (xhr.responseText) {
                    const parsed = JSON.parse(xhr.responseText);
                    if (parsed?.data?.message) msg = 'AI Agent: ' + parsed.data.message;
                    else if (parsed?.message) msg = 'AI Agent: ' + parsed.message;
                }
            } catch(_) {}
            showToast(msg, 'error');
        }).always(() => {
            console.log('[VMO Insert] AJAX request completed - re-enabling button');
            clearTimeout(failsafeTimeout);
            $submitBtn.prop('disabled', false).removeClass('vmo-btn-loading');
            
            // Additional safety check - ensure button is clickable
            setTimeout(() => {
                if ($submitBtn.prop('disabled') || $submitBtn.hasClass('vmo-btn-loading')) {
                    console.log('[VMO Insert] Button still disabled after AJAX - force enabling');
                    $submitBtn.prop('disabled', false).removeClass('vmo-btn-loading');
                }
            }, 100);
        });
    });

    window.openInsertMediaModal = openInsertMediaModal;

    function vmoBuildPlacementTransform(scale, offsetX, offsetY) {
        return `translate(${offsetX}px, ${offsetY}px) scale(${scale})`;
    }

    function vmoRemoveMediaGenerationMarkersFromNode(node) {
        if (!node || !node.removeAttribute) return;

        ['data-vmo-generate', 'data-vmo-prompt', 'data-vmo-sora', 'data-vmo-sora-prompt', 'data-vmo-generated'].forEach(attr => {
            node.removeAttribute(attr);
        });
    }

    function vmoReadPlacementState(holder) {
        if (!holder) {
            return {
                fit: 'cover',
                positionX: 50,
                positionY: 50,
                scale: 1,
                offsetX: 0,
                offsetY: 0
            };
        }

        return {
            fit: String(holder.getAttribute('data-vmo-fit') || 'cover'),
            positionX: parseFloat(holder.getAttribute('data-vmo-position-x') || '50') || 50,
            positionY: parseFloat(holder.getAttribute('data-vmo-position-y') || '50') || 50,
            scale: parseFloat(holder.getAttribute('data-vmo-scale') || '1') || 1,
            offsetX: parseFloat(holder.getAttribute('data-vmo-offset-x') || '0') || 0,
            offsetY: parseFloat(holder.getAttribute('data-vmo-offset-y') || '0') || 0
        };
    }

    function vmoPersistPlacementState(holder, state) {
        if (!holder || !holder.setAttribute) return;

        holder.setAttribute('data-vmo-fit', state.fit);
        holder.setAttribute('data-vmo-position-x', String(state.positionX));
        holder.setAttribute('data-vmo-position-y', String(state.positionY));
        holder.setAttribute('data-vmo-scale', String(state.scale));
        holder.setAttribute('data-vmo-offset-x', String(state.offsetX));
        holder.setAttribute('data-vmo-offset-y', String(state.offsetY));
    }

    function vmoResolvePlacementHandle(node) {
        if (!node) return null;

        const tagName = String(node.tagName || '').toLowerCase();

        if (node.dataset && node.dataset.bg === '1') {
            return { mode: 'background', target: node, holder: node, mediaEl: null, container: node };
        }

        if (tagName === 'img' || tagName === 'video') {
            return { mode: 'element', target: node, holder: node, mediaEl: node, container: node.parentElement || node };
        }

        const innerMedia = typeof node.querySelector === 'function'
            ? node.querySelector('[data-vmo-replaced-media="1"], img, video')
            : null;

        if (innerMedia) {
            return { mode: 'element', target: node, holder: node, mediaEl: innerMedia, container: node };
        }

        const backgroundImage = String(node.style && node.style.backgroundImage ? node.style.backgroundImage : '');
        if (backgroundImage && backgroundImage !== 'none') {
            return { mode: 'background', target: node, holder: node, mediaEl: null, container: node };
        }

        return null;
    }

    function vmoApplyPlacementState(handle, state) {
        if (!handle || !state) return;

        const normalizedState = {
            fit: ['cover', 'contain', 'fill'].includes(state.fit) ? state.fit : 'cover',
            positionX: Math.max(0, Math.min(100, parseFloat(state.positionX) || 50)),
            positionY: Math.max(0, Math.min(100, parseFloat(state.positionY) || 50)),
            scale: Math.max(0.5, Math.min(2.5, parseFloat(state.scale) || 1)),
            offsetX: Math.max(-240, Math.min(240, parseFloat(state.offsetX) || 0)),
            offsetY: Math.max(-240, Math.min(240, parseFloat(state.offsetY) || 0))
        };

        vmoPersistPlacementState(handle.holder, normalizedState);

        if (handle.mode === 'background') {
            let backgroundSize = normalizedState.fit === 'contain'
                ? 'contain'
                : (normalizedState.fit === 'fill' ? '100% 100%' : 'cover');

            if (normalizedState.scale !== 1) {
                const scaledPercent = Math.round(normalizedState.scale * 100);
                backgroundSize = normalizedState.fit === 'fill'
                    ? `${scaledPercent}% ${scaledPercent}%`
                    : `${scaledPercent}%`;
            }

            handle.target.style.backgroundSize = backgroundSize;
            handle.target.style.backgroundPosition = `calc(${normalizedState.positionX}% + ${normalizedState.offsetX}px) calc(${normalizedState.positionY}% + ${normalizedState.offsetY}px)`;
            handle.target.style.backgroundRepeat = 'no-repeat';
            handle.target.style.overflow = handle.target.style.overflow || 'hidden';
            return;
        }

        if (!handle.mediaEl) return;

        handle.mediaEl.style.objectFit = normalizedState.fit;
        handle.mediaEl.style.objectPosition = `${normalizedState.positionX}% ${normalizedState.positionY}%`;
        handle.mediaEl.style.transform = vmoBuildPlacementTransform(normalizedState.scale, normalizedState.offsetX, normalizedState.offsetY);
        handle.mediaEl.style.transformOrigin = 'center center';
        handle.mediaEl.style.width = handle.mediaEl.style.width || '100%';
        handle.mediaEl.style.height = handle.mediaEl.style.height || '100%';
        handle.mediaEl.style.display = handle.mediaEl.style.display || 'block';

        if (handle.container && handle.container !== handle.mediaEl) {
            handle.container.style.overflow = handle.container.style.overflow || 'hidden';
            if (!handle.container.style.position || handle.container.style.position === 'static') {
                handle.container.style.position = 'relative';
            }
        }
    }

    function vmoSyncMediaSlotFromPreview(node) {
        if (!node) return;

        const blockWrapper = typeof node.closest === 'function' ? node.closest('[data-block-id]') : null;
        const blockId = blockWrapper ? String(blockWrapper.dataset.blockId || '') : '';

        if (typeof window.vmoSyncPreviewStateFromIframe === 'function') {
            window.vmoSyncPreviewStateFromIframe({
                blockId,
                markUnsaved: true,
                autoSave: true
            });
        }
    }

    function vmoCreateManualReplacementElement(doc, type, url, mediaId, sourceNode) {
        const normalizedType = normalizeReplaceMediaType(type);
        const element = doc.createElement(normalizedType === 'video' ? 'video' : 'img');

        element.setAttribute('data-vmo-replaced-media', '1');
        element.setAttribute('data-media-id', mediaId || '');
        element.setAttribute('data-type', normalizedType);
        element.style.cssText = 'position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:50% 50%;display:block;transform:translate(0px, 0px) scale(1);transform-origin:center center;';

        if (normalizedType === 'video') {
            element.setAttribute('src', url);
            element.setAttribute('autoplay', 'autoplay');
            element.setAttribute('muted', 'muted');
            element.setAttribute('loop', 'loop');
            element.setAttribute('playsinline', 'playsinline');
            element.removeAttribute('controls');
        } else {
            element.setAttribute('src', url);
            element.setAttribute('loading', 'lazy');
            element.setAttribute('alt', sourceNode && sourceNode.getAttribute ? (sourceNode.getAttribute('alt') || 'Inserted Image') : 'Inserted Image');
        }

        return element;
    }

    function vmoApplyManualReplacementToDom(doc, node, url, type, mediaId) {
        if (!doc || !node) return node;

        const normalizedType = normalizeReplaceMediaType(type);
        const tagName = String(node.tagName || '').toLowerCase();

        vmoRemoveMediaGenerationMarkersFromNode(node);
        node.setAttribute('data-media-id', mediaId || '');
        node.setAttribute('data-type', normalizedType);
        node.classList.add('vmo-media-placeholder');

        if (node.dataset && node.dataset.bg === '1') {
            node.style.backgroundImage = `url('${url}')`;
            node.style.backgroundSize = node.style.backgroundSize || 'cover';
            node.style.backgroundPosition = node.style.backgroundPosition || 'center';
            node.style.backgroundRepeat = 'no-repeat';
            return node;
        }

        if (normalizedType === 'image' && tagName === 'img') {
            node.setAttribute('src', url);
            node.setAttribute('loading', 'lazy');
            node.setAttribute('data-vmo-replaced-media', '1');
            return node;
        }

        if (normalizedType === 'video' && tagName === 'video') {
            node.setAttribute('src', url);
            node.setAttribute('autoplay', 'autoplay');
            node.setAttribute('muted', 'muted');
            node.setAttribute('loop', 'loop');
            node.setAttribute('playsinline', 'playsinline');
            node.removeAttribute('controls');
            node.setAttribute('data-vmo-replaced-media', '1');
            if (typeof node.load === 'function') {
                node.load();
            }
            return node;
        }

        const replacement = vmoCreateManualReplacementElement(doc, normalizedType, url, mediaId, node);

        node.setAttribute('data-vmo-media-container', '1');
        if (!node.style.position || node.style.position === 'static') {
            node.style.position = 'relative';
        }
        node.style.overflow = node.style.overflow || 'hidden';
        node.style.backgroundImage = 'none';

        node.innerHTML = '';
        node.appendChild(replacement);

        return node;
    }

    function vmoApplyManualReplacementToJquery($node, url, type, mediaId) {
        if (!$node || !$node.length) return $node;

        const normalizedType = normalizeReplaceMediaType(type);
        const tagName = String($node.prop('tagName') || '').toLowerCase();

        $node.removeAttr('data-vmo-generate data-vmo-prompt data-vmo-sora data-vmo-sora-prompt data-vmo-generated');
        $node.attr({
            'data-media-id': mediaId || '',
            'data-type': normalizedType
        }).addClass('vmo-media-placeholder');

        if ($node.attr('data-bg') === '1') {
            $node.css({
                backgroundImage: `url('${url}')`,
                backgroundSize: $node.css('background-size') || 'cover',
                backgroundPosition: $node.css('background-position') || 'center',
                backgroundRepeat: 'no-repeat'
            });
            return $node;
        }

        if (normalizedType === 'image' && tagName === 'img') {
            $node.attr({ src: url, loading: 'lazy', 'data-vmo-replaced-media': '1' });
            return $node;
        }

        if (normalizedType === 'video' && tagName === 'video') {
            $node.attr({
                src: url,
                autoplay: 'autoplay',
                muted: 'muted',
                loop: 'loop',
                playsinline: 'playsinline',
                'data-vmo-replaced-media': '1'
            }).removeAttr('controls');
            return $node;
        }

        const replacementTag = normalizedType === 'video' ? 'video' : 'img';
        const $replacement = $(`<${replacementTag}>`);

        $replacement.attr({
            'data-vmo-replaced-media': '1',
            'data-media-id': mediaId || '',
            'data-type': normalizedType
        }).css({
            position: 'absolute',
            inset: '0',
            width: '100%',
            height: '100%',
            objectFit: 'cover',
            objectPosition: '50% 50%',
            display: 'block',
            transform: 'translate(0px, 0px) scale(1)',
            transformOrigin: 'center center'
        });

        if (normalizedType === 'video') {
            $replacement.attr({
                src: url,
                autoplay: 'autoplay',
                muted: 'muted',
                loop: 'loop',
                playsinline: 'playsinline'
            });
        } else {
            $replacement.attr({
                src: url,
                loading: 'lazy',
                alt: $node.attr('alt') || 'Inserted Image'
            });
        }

        $node.attr('data-vmo-media-container', '1').css({
            position: $node.css('position') === 'static' ? 'relative' : $node.css('position'),
            overflow: 'hidden',
            backgroundImage: 'none'
        }).empty().append($replacement);

        return $node;
    }

    window.openMediaPlacementAdjuster = function(context) {
        const ctx = context && typeof context === 'object' ? context : (window.vmoMediaModalContext || {});
        const iframe = document.getElementById('vmo-preview-iframe');
        const doc = iframe && iframe.contentDocument ? iframe.contentDocument : null;

        if (!doc) {
            return showToast('Preview is not ready for media adjustments.', 'error');
        }

        let node = null;
        if (ctx.selector) node = doc.querySelector(ctx.selector);
        if (!node && ctx.mediaId) node = doc.querySelector(`[data-media-id="${ctx.mediaId}"]`);
        if (!node) {
            return showToast('Could not find the selected media slot.', 'error');
        }

        const handle = vmoResolvePlacementHandle(node);
        if (!handle) {
            return showToast('This media slot cannot be adjusted yet.', 'error');
        }

        $('#vmo-placement-modal').remove();

        const state = vmoReadPlacementState(handle.holder);
        $('body').append(`<div id="vmo-placement-modal" class="vmo-modal" style="display:flex;position:fixed;top:0;left:0;width:100vw;height:100vh;background:rgba(0,0,0,0.55);z-index:999999;align-items:center;justify-content:center;backdrop-filter:blur(3px);"><div class="vmo-modal-content" style="background:#001a2e;border-radius:16px;padding:28px;width:92%;max-width:560px;color:#fff;box-shadow:0 30px 80px rgba(0,226,255,0.3);border:1px solid rgba(0,226,255,0.45);max-height:88vh;overflow-y:auto;"><h3 style="margin:0 0 8px;color:#00e2ff;text-align:center;font-size:24px;">Fine-Tune Media Fit</h3><p style="margin:0 0 20px;color:#9fc7d6;text-align:center;font-size:14px;line-height:1.5;">Adjust crop, focus point, zoom, and nudges while keeping the replacement in the exact same slot.</p><div style="display:grid;gap:16px;"><label style="display:grid;gap:8px;font-size:13px;color:#9fc7d6;">Fit<select id="vmo-fit-mode" style="background:#003054;color:#fff;border:1px solid #00e2ff;border-radius:8px;padding:10px 12px;"><option value="cover">Cover</option><option value="contain">Contain</option><option value="fill">Fill</option></select></label><label style="display:grid;gap:8px;font-size:13px;color:#9fc7d6;">Zoom <span id="vmo-fit-scale-label" style="color:#fff;font-weight:600;">100%</span><input id="vmo-fit-scale" type="range" min="50" max="250" step="1" value="100" style="accent-color:#00e2ff;"></label><label style="display:grid;gap:8px;font-size:13px;color:#9fc7d6;">Horizontal Focus <span id="vmo-fit-posx-label" style="color:#fff;font-weight:600;">50%</span><input id="vmo-fit-posx" type="range" min="0" max="100" step="1" value="50" style="accent-color:#00e2ff;"></label><label style="display:grid;gap:8px;font-size:13px;color:#9fc7d6;">Vertical Focus <span id="vmo-fit-posy-label" style="color:#fff;font-weight:600;">50%</span><input id="vmo-fit-posy" type="range" min="0" max="100" step="1" value="50" style="accent-color:#00e2ff;"></label><label style="display:grid;gap:8px;font-size:13px;color:#9fc7d6;">Nudge X <span id="vmo-fit-offsetx-label" style="color:#fff;font-weight:600;">0px</span><input id="vmo-fit-offsetx" type="range" min="-240" max="240" step="1" value="0" style="accent-color:#00e2ff;"></label><label style="display:grid;gap:8px;font-size:13px;color:#9fc7d6;">Nudge Y <span id="vmo-fit-offsety-label" style="color:#fff;font-weight:600;">0px</span><input id="vmo-fit-offsety" type="range" min="-240" max="240" step="1" value="0" style="accent-color:#00e2ff;"></label></div><div style="display:flex;gap:12px;justify-content:flex-end;flex-wrap:wrap;margin-top:22px;"><button id="vmo-fit-reset" class="vmo-btn" style="background:#163447;color:#9fc7d6;border:1px solid rgba(159,199,214,0.35);padding:11px 18px;border-radius:10px;font-weight:600;cursor:pointer;">Reset</button><button id="vmo-fit-done" class="vmo-btn" style="background:#00ff9a;color:#001a2e;border:none;padding:11px 20px;border-radius:10px;font-weight:700;cursor:pointer;">Done</button></div></div></div>`);

        const $modal = $('#vmo-placement-modal');
        const $fitMode = $('#vmo-fit-mode');
        const $scale = $('#vmo-fit-scale');
        const $posX = $('#vmo-fit-posx');
        const $posY = $('#vmo-fit-posy');
        const $offsetX = $('#vmo-fit-offsetx');
        const $offsetY = $('#vmo-fit-offsety');
        let syncTimer = null;

        function closeModal() {
            $modal.remove();
        }

        function scheduleSync() {
            clearTimeout(syncTimer);
            syncTimer = setTimeout(() => vmoSyncMediaSlotFromPreview(handle.target), 120);
        }

        function readStateFromInputs() {
            return {
                fit: $fitMode.val() || 'cover',
                scale: (parseFloat($scale.val()) || 100) / 100,
                positionX: parseFloat($posX.val()) || 50,
                positionY: parseFloat($posY.val()) || 50,
                offsetX: parseFloat($offsetX.val()) || 0,
                offsetY: parseFloat($offsetY.val()) || 0
            };
        }

        function updateLabels(nextState) {
            $('#vmo-fit-scale-label').text(Math.round(nextState.scale * 100) + '%');
            $('#vmo-fit-posx-label').text(Math.round(nextState.positionX) + '%');
            $('#vmo-fit-posy-label').text(Math.round(nextState.positionY) + '%');
            $('#vmo-fit-offsetx-label').text(Math.round(nextState.offsetX) + 'px');
            $('#vmo-fit-offsety-label').text(Math.round(nextState.offsetY) + 'px');
        }

        function applyFromInputs() {
            const nextState = readStateFromInputs();
            vmoApplyPlacementState(handle, nextState);
            updateLabels(nextState);
            scheduleSync();
        }

        $fitMode.val(state.fit);
        $scale.val(Math.round(state.scale * 100));
        $posX.val(Math.round(state.positionX));
        $posY.val(Math.round(state.positionY));
        $offsetX.val(Math.round(state.offsetX));
        $offsetY.val(Math.round(state.offsetY));
        updateLabels(state);
        vmoApplyPlacementState(handle, state);

        $fitMode.on('change', applyFromInputs);
        $scale.on('input', applyFromInputs);
        $posX.on('input', applyFromInputs);
        $posY.on('input', applyFromInputs);
        $offsetX.on('input', applyFromInputs);
        $offsetY.on('input', applyFromInputs);

        $('#vmo-fit-reset').on('click', () => {
            $fitMode.val('cover');
            $scale.val('100');
            $posX.val('50');
            $posY.val('50');
            $offsetX.val('0');
            $offsetY.val('0');
            applyFromInputs();
        });

        $('#vmo-fit-done').on('click', () => {
            clearTimeout(syncTimer);
            vmoSyncMediaSlotFromPreview(handle.target);
            closeModal();
        });

        $modal.on('click', function(e) {
            if (e.target === this) {
                clearTimeout(syncTimer);
                vmoSyncMediaSlotFromPreview(handle.target);
                closeModal();
            }
        });
    };

    /* ========== CORE SWAP HANDLER (iframe + state) ========== */
    window.vmoOnMediaSelected = function (url, options = {}) {
        const ctx = window.vmoMediaModalContext || {};
        let targetBlockId = '';
        if (!ctx.selector && !ctx.mediaId) {
            console.error('[VMO] No media context set for replacement');
            return showToast('No media target found.', 'error');
        }

        const iframe=document.getElementById('vmo-preview-iframe');
        if(iframe?.contentDocument){
            const doc=iframe.contentDocument;
            let node = null;
            if (ctx.selector) node = doc.querySelector(ctx.selector);
            if (!node && ctx.mediaId) node = doc.querySelector(`[data-media-id="${ctx.mediaId}"]`);
            if (!node) {
                console.error('[VMO] Target element not found for', ctx);
                return showToast('Target element not found.', 'error');
            }
            const mediaId=node.dataset.mediaId||vmoGenerateMediaId();
            const blockWrapper = node.closest('[data-block-id]');
            targetBlockId = blockWrapper ? String(blockWrapper.dataset.blockId || '') : '';
            console.log('[VMO] Replacing media', { mediaId, mediaType: ctx.mediaType, url, node });
            node = vmoApplyManualReplacementToDom(doc, node, url, ctx.mediaType, mediaId);

            const placementHandle = vmoResolvePlacementHandle(node);
            if (placementHandle) {
                vmoApplyPlacementState(placementHandle, vmoReadPlacementState(placementHandle.holder));
            }

            if(typeof window.vmoInjectReplaceButtonsInIframe==='function') window.vmoInjectReplaceButtonsInIframe();
            ctx.mediaId=mediaId;
            ctx.selector = `[data-media-id="${mediaId}"]`;
        }

        let synced = false;
        try {
            if (typeof window.vmoSyncPreviewStateFromIframe === 'function') {
                synced = !!window.vmoSyncPreviewStateFromIframe({
                    blockId: targetBlockId,
                    markUnsaved: true,
                    autoSave: true
                });
            }
        } catch(e) {
            console.warn('[VMO] Preview sync failed', e);
        }

        if (!synced) {
            try {
                vmoReplaceMediaInBlocks(ctx.mediaId,url,ctx.mediaType);
            } catch(e) {
                console.warn('[VMO] Block sync failed', e);
            }
        }

        if (options && options.openAdjuster && typeof window.openMediaPlacementAdjuster === 'function') {
            setTimeout(() => {
                window.openMediaPlacementAdjuster(window.vmoMediaModalContext || {});
            }, 60);
        }

        showToast('Media replaced!','success');
    };

    /* update builder blocks, push undo, autosave */
    function vmoReplaceMediaInBlocks (mid,url,type){
        if(!Array.isArray(window.vmoState?.blocks)) return;
        let changed=false;
        if(typeof pushUndo==='function') pushUndo();
        window.vmoState.blocks.forEach(b=>{
            if(!b.html) return;
            const $tmp=$('<div>'+b.html+'</div>');
            let blockChanged = false;
            $tmp.find('[data-media-id="'+mid+'"]').each(function(){
                vmoApplyManualReplacementToJquery($(this), url, type, mid);
                blockChanged = true;
                changed = true;
            });
            // Always update the block HTML after processing, even if no media was found
            if(blockChanged) {
                b.html = $tmp.html();
            }
        });
        if(changed){
            if(typeof renderBlocks==='function') renderBlocks();
            window.isUnsaved=true;
            window.lastContent=window.vmoState.blocks.map(b=>b.html).join('\n');
            if(typeof autoSaveCheckpoint==='function') autoSaveCheckpoint();
        }
    }

    // (Legacy direct send handler removed; use unified binding at the bottom with handlePromptSend only)

    function isNearBottom(element, threshold = 80) {
        if (!element) return false;
        const distanceFromBottom = element.scrollHeight - element.scrollTop - element.clientHeight;
        return distanceFromBottom <= threshold;
    }

    // Append a message to chat history with role-based styling and conditional auto-scroll
    function appendChatMessage(role, text) {
        try {
            const $log = $('#vmo-chat-history');
            if ($log.length === 0) return;
            const logEl = $log[0];
            const shouldAutoScroll = isNearBottom(logEl);
            
            // ✅ CRITICAL FIX: Prevent duplicate message display
            // Use a Set to track recently added messages
            if (!window._vmoRecentMessages) {
                window._vmoRecentMessages = new Set();
            }
            
            // Create message signature to detect duplicates
            const messageSignature = `${role}:${text}:${Date.now()}`;
            const messageKey = `${role}:${text.substring(0, 50)}`; // Use first 50 chars for comparison
            
            // Check if this exact message was just added (within last 500ms)
            if (window._vmoRecentMessages.has(messageKey)) {
                console.warn('⚠️ Duplicate message prevented:', messageKey);
                return;
            }
            
            // Add to recent messages set
            window._vmoRecentMessages.add(messageKey);
            
            // Remove from set after 500ms to allow legitimate re-sends
            setTimeout(() => {
                window._vmoRecentMessages.delete(messageKey);
            }, 500);
            
            // Clean text - remove markdown symbols, format properly
            let cleanText = (text || '').toString()
                .replace(/###/g, '') // Remove markdown headers
                .replace(/\*\*/g, '') // Remove bold markers
                .replace(/\*/g, '') // Remove italic markers
                .trim();
            
            // Format text properly - preserve intentional line breaks
            cleanText = cleanText
                .split('\n')
                .filter(line => line.trim()) // Remove empty lines
                .map(line => {
                    line = line.trim();
                    // Capitalize first letter if not already (and not an emoji or bullet)
                    if (line.length > 0 && /[a-z]/.test(line[0])) {
                        line = line.charAt(0).toUpperCase() + line.slice(1);
                    }
                    return line;
                })
                .join('\n\n'); // Double line break between paragraphs
            
            // Create message element with role-specific styling
            const isUser = role === 'user';
            const $msg = $('<div/>')
                .addClass('vmo-chat-msg')
                .addClass(isUser ? 'user-msg' : 'ai-msg')
                .css({
                    'margin': '15px 0',
                    'padding': '12px 18px',
                    'border-radius': '12px',
                    'max-width': '85%',
                    'word-wrap': 'break-word',
                    'white-space': 'pre-wrap',
                    'line-height': '1.6',
                    'text-align': 'left',
                    'clear': 'both',
                    'float': isUser ? 'right' : 'left',
                    'background': isUser ? 'linear-gradient(135deg, #003054 0%, #00416A 100%)' : '#f0f0f0',
                    'color': isUser ? '#00e2ff' : '#333333',
                    'border': isUser ? '2px solid #00e2ff' : 'none',
                    'box-shadow': '0 2px 8px rgba(0,0,0,0.1)',
                    'position': 'relative',
                    'animation': 'fadeIn 0.3s ease'
                });
            
            // Add sender label with VMO logo
            const $label = $('<div/>')
                .css({
                    'font-weight': '600',
                    'font-size': '11px',
                    'margin-bottom': '6px',
                    'opacity': '0.85',
                    'text-transform': 'uppercase',
                    'letter-spacing': '0.5px',
                    'display': 'flex',
                    'align-items': 'center',
                    'gap': '6px'
                });
            
            if (!isUser) {
                // Add VMO logo for AI messages
                const pluginMeta = (window.vmoAjax || window.vmo_ajax || {});
                const pluginBase = String(pluginMeta.pluginUrl || pluginMeta.plugin_url || '').replace(/\/+$/, '');
                const logoPath = pluginBase ? `${pluginBase}/assets/vmo-icon.svg` : '';

                if (logoPath) {
                    const $logo = $('<img/>')
                        .attr('src', logoPath)
                        .attr('alt', 'VMO')
                        .css({
                            'width': '16px',
                            'height': '16px',
                            'display': 'inline-block'
                        });
                    $label.append($logo);
                }
            }
            
            $label.append($('<span/>').text(isUser ? 'You' : 'VMO AI'));
            
            // Add message content
            const $content = $('<div/>')
                .css({
                    'font-size': '14px',
                    'line-height': '1.6'
                })
                .text(cleanText);
            
            $msg.append($label).append($content);
            
            // Add clearfix after message
            const $clearfix = $('<div/>').css('clear', 'both');
            
            $log.append($msg).append($clearfix);
            
            // Only follow new messages when user is already at the bottom
            if (shouldAutoScroll) {
                $log.stop(true, false);
                $log.scrollTop(logEl.scrollHeight);
            }
            
        } catch (e) { 
            console.warn('appendChatMessage error', e); 
        }
    }
    
    // ✅ CRITICAL FIX: Expose to window so other modules can use it
    // Voice panel system disabled - no voice manipulation in no-voice version
    window.appendChatMessage = appendChatMessage;
    console.log('✅ appendChatMessage exposed globally');

    // Ensure consultation gating exists (prevents accidental generation before business consultation)
    window.vmoEnsureConsultationReady = function(cb) {
        const unlocked = !!(window.vmo_ajax && window.vmo_ajax.generation_unlocked);
        if (unlocked) {
            if (typeof cb === 'function') cb();
            return true;
        }
        // Guide the user to run the Business Consultation first
        const guidance = 'Let\'s start with your Business Consultation. Click the red Business Wizard button at the top to begin. Jarvis will coordinate the team, and Jerreme will lead the strategy so we can generate your website after you approve the plan.';
        if (window.showToast) window.showToast('Website generation is locked until after consultation.', 'warning');
        appendChatMessage('ai', guidance);
        // Voice feedback disabled - text only interface
        console.log('🔕 Voice feedback disabled in no-voice version');
        return false;
    };

    // Conversation-only message to Jarvis-style VMO assistant
    async function sendConversationMessage(text) {
        const userText = (text || '').trim();
        if (!userText) return;
        appendChatMessage('user', userText);
        // Build lightweight system prompt for conversational guidance (no HTML generation)
        const system = 'You are VMO, the coordinating AI inside the VMO Web Business Consultant WordPress plugin. '
            + 'Only answer questions about using this plugin (setup, features, business consultation flow, generation/refinement, voice, payments, SEO, templates). '
            + 'If asked about other plugins or unrelated topics, politely say you can only help with this plugin. '
            + 'Be concise, friendly, and actionable. Do not generate HTML or modify the preview. '
            + 'Ask one helpful follow-up question when appropriate.';
        const profileSystem = (window.vmoConsultationProfileSystem || '').toString();
        const chat = [
            { role: 'system', content: system + (profileSystem ? ('\n\n' + profileSystem) : '') },
            { role: 'user', content: userText }
        ];
        try {
            const res = await $.post({
                url: vmo_ajax.ajaxurl,
                method: 'POST',
                dataType: 'json',
                data: { action: 'vmo_conversation_chat', security: vmo_ajax.nonce, chat: JSON.stringify(chat), chat_type: 'jarvis' }
            });
            if (res && res.success && res.data?.response) {
                appendChatMessage('ai', res.data.response);
                // Voice response disabled - text only interface  
                console.log('🔕 Voice response disabled in no-voice version');
            } else {
                const msg = res?.data?.message || 'I couldn\'t reach the assistant just now.';
                appendChatMessage('ai', msg);
            }
        } catch (err) {
            appendChatMessage('ai', 'There was a problem contacting the server. Please try again.');
        }
    }

    // Enhanced content generation function
    function generateContent(userPrompt, isRefinement = false) {
        console.log('[VMO] generateContent called:', { userPrompt, isRefinement });
        // Hard gate: do not generate until after business consultation unlock
        if (!window.vmoEnsureConsultationReady(() => {})) {
            return;
        }
        
        // Validate AJAX variables
        if (typeof vmo_ajax === 'undefined') {
            console.error('[VMO] vmo_ajax not defined');
            if (typeof window.showToast === 'function') {
                window.showToast('AJAX configuration missing. Please refresh the page.', 'error');
            }
            return;
        }
        
        console.log('[VMO] AJAX config:', vmo_ajax);
        
        window.isGenerating = true;
        $('#vmo-send-btn').prop('disabled', true).addClass('vmo-btn-loading');
        
        // Enhanced mobile-responsive prompt
        const mobileResponsivePrompt = userPrompt + `
        
CRITICAL MOBILE REQUIREMENTS:
- Must be fully responsive and mobile-first
- Include proper viewport meta tag: <meta name="viewport" content="width=device-width, initial-scale=1.0">
- Use flexible layouts (flexbox, CSS Grid) that work on all screen sizes
- Minimum 16px font size for mobile readability
- Touch-friendly buttons (minimum 44px touch targets)
- Proper spacing and margins for mobile usability
- Responsive images and media
- Test on phones, tablets, and desktops
- Ensure content fits properly in iframe container
- Use relative units (%, em, rem, vw, vh) instead of fixed pixels where appropriate`;
        
        // Show generating toast
        if (typeof window.showToast === 'function') {
            window.showToast('Designing website and preparing required media…', 'info', true, true);
        }
    // Do NOT append user chat here; handlePromptSend will append to avoid duplicates

        // Build chat messages array
        let finalPrompt = mobileResponsivePrompt;
        
        // Check responsive mode setting
        const responsiveMode = $('#vmo-theme-align').prop('checked');
        
        if (isRefinement && window.vmoState?.blocks?.length) {
            // Build refinement prompt with existing content
            const existingHtml = window.vmoState.blocks.map(b => b.html).join('\n');
            
            // Enhanced refinement instructions for surgical precision
            finalPrompt = `${userPrompt}

--- EXISTING CONTENT ---
${existingHtml}
--- END EXISTING CONTENT ---

REFINEMENT INSTRUCTIONS:
- SURGICAL PRECISION: Only modify the exact element, section, or feature mentioned in the user's request
- PRESERVE ALL OTHER CONTENT: Keep all other sections, elements, and content exactly as they are
- NO SCOPE CREEP: Do not add new sections, headers, footers, or content not explicitly requested
- MAINTAIN STRUCTURE: Preserve existing HTML structure, classes, and functionality
- PROTECT SIBLINGS: When modifying one element, ensure its siblings remain untouched
- ELEMENT ISOLATION: Changes should be confined to the specific target mentioned
- RETURN COMPLETE PAGE: Always return the full page with only the requested changes applied

Based on the instruction above, please modify ONLY the specific element/section mentioned while keeping everything else exactly the same.`;
            
            if (responsiveMode) {
                finalPrompt += '\n\nIMPORTANT: Emphasize mobile-first responsive design and ensure all changes work perfectly on mobile devices.';
            }
        } else {
            // Add smart prompt building for new content
            if (typeof window.buildSmartPrompt === 'function') {
                finalPrompt = window.buildSmartPrompt(userPrompt);
            }
            
            if (responsiveMode) {
                finalPrompt = `RESPONSIVE MODE ENABLED: Create a mobile-first, fully responsive design that looks perfect on all devices. ${finalPrompt}`;
            }
        }

        // Prepare system messages
        let profileSystem = '';
        try { 
            profileSystem = window.vmoConsultationProfileSystem || ''; 
        } catch(e) {
            console.log('[VMO] No consultation profile system available');
        }
        
        const systemMessage = `You are Jerreme, a professional web designer and expert copywriter with surgical precision capabilities. 

${profileSystem}

FOR NEW CONTENT: Create modern, responsive HTML with beautiful CSS, professional copy writing, and advanced design patterns. Include proper section structure with numbered HTML comments and section IDs. Write complete, engaging copy content for all text elements.

FOR REFINEMENTS: Make ONLY the exact changes requested. Preserve all other content, sections, and elements exactly as they are. When modifying one element (like a flip card), ensure all sibling elements remain untouched. Never add unrequested sections or content.

MEDIA HANDLING: Use proper placeholder structure for flip cards and interactive elements. Keep image containers separate from text content areas.

COPY WRITING: Provide complete, professional copy content that businesses can use directly. Match specified word counts and tone requirements exactly.`;

        const chatArr = [
            { 
                role: 'system', 
                content: systemMessage
            },
            { 
                role: 'user', 
                content: finalPrompt
            }
        ];
        
        console.log('[VMO] Prepared chat array:', chatArr);

        // Call backend generation
        const ajaxData = {
            action: 'vmo_generate_content',
            security: vmo_ajax.nonce,
            chat: JSON.stringify(chatArr)
        };
        
        console.log('[VMO] Making AJAX call with data:', ajaxData);
        
        $.post({
            url: vmo_ajax.ajaxurl,
            method: 'POST',
            data: ajaxData
        }).done(async function(res) {
            console.log('[VMO] AJAX response received:', res);
            
            if (typeof window.hideToast === 'function') {
                window.hideToast(true);
            }

            if (res.success && (res.data?.grapes_plan || res.data?.html)) {
                let generatedHtml = '';
                let compositionError = '';

                if (res.data?.grapes_plan) {
                    if (window.vmoGrapesAdapter && typeof window.vmoGrapesAdapter.composeWebsite === 'function') {
                        try {
                            const extracted = window.vmoConsultation?.consultation_data?.extracted_information || {};
                            const phoneFromStatus = window.vmoConsultation?.phoneProvisioningStatus?.phone_number || '';
                            const phoneFromConsultation = extracted.business_phone || extracted.phone || extracted.supportPhone || '';
                            const emailFromConsultation = extracted.business_email || extracted.businessEmail || extracted.email || extracted.supportEmail || '';

                            const composeContext = {
                                phoneNumber: phoneFromStatus || phoneFromConsultation || '',
                                emailAddress: emailFromConsultation || ''
                            };

                            const composed = window.vmoGrapesAdapter.composeWebsite(res.data.grapes_plan, composeContext);
                            if (composed && composed.ok && composed.html) {
                                generatedHtml = composed.html;
                            } else {
                                compositionError = composed?.reason || 'GrapesJS composition failed';
                            }
                        } catch (composeErr) {
                            compositionError = composeErr?.message || 'GrapesJS composition failed';
                            console.error('[VMO] GrapesJS composition error:', composeErr);
                        }
                    } else {
                        compositionError = 'GrapesJS composer is unavailable';
                    }
                }

                if (!generatedHtml && res.data?.html) {
                    generatedHtml = res.data.html;
                }

                if (!generatedHtml) {
                    const msg = compositionError || 'Unable to compose website frontend with GrapesJS.';
                    if (typeof window.showToast === 'function') {
                        window.showToast(msg, 'error');
                    }
                    appendChatMessage('ai', msg);
                    return;
                }

                // Process the generated HTML
                let cleanHtml = generatedHtml
                    .replace(/<\/?(html|head|body|prompt)[^>]*>/gi, '')
                    .replace(/<!DOCTYPE[^>]*>/gi, '')
                    .trim();

                // Enhance content for mobile responsiveness
                cleanHtml = enhanceContentForMobile(cleanHtml);

                // Wrap with CDNs if function exists
                if (typeof window.vmoWrapWithCDNs === 'function') {
                    cleanHtml = window.vmoWrapWithCDNs(cleanHtml);
                }

                // Push undo state
                if (typeof window.pushUndo === 'function') {
                    window.pushUndo();
                }

                if (isRefinement && window.vmoState?.blocks?.length) {
                    // Replace existing content
                    window.vmoState.blocks = [{
                        id: window.getUniqueBlockId ? window.getUniqueBlockId() : Date.now().toString(),
                        html: cleanHtml,
                        type: 'content'
                    }];
                } else {
                    // Add new content
                    if (!window.vmoState) window.vmoState = { blocks: [] };
                    if (!Array.isArray(window.vmoState.blocks)) window.vmoState.blocks = [];
                    
                    window.vmoState.blocks.push({
                        id: window.getUniqueBlockId ? window.getUniqueBlockId() : Date.now().toString(),
                        html: cleanHtml,
                        type: 'content'
                    });
                }

                // Re-render and save
                if (typeof window.renderBlocks === 'function') {
                    window.renderBlocks();
                } else {
                    console.warn('[VMO] renderBlocks function not available');
                }
                
                // Mark content as present (prevents placeholder from reappearing)
                window.vmoHasContent = true;
                window.isUnsaved = true;
                if (typeof window.autoSaveCheckpoint === 'function') {
                    window.autoSaveCheckpoint();
                }

                let mediaResult = { complete: true, total: 0, completed: 0, failed: [] };
                if (typeof window.vmoMediaGenerator !== 'undefined' && typeof window.vmoMediaGenerator.resolvePendingMedia === 'function') {
                    try {
                        const pendingTargets = typeof window.vmoMediaGenerator.collectPendingMediaTargets === 'function'
                            ? window.vmoMediaGenerator.collectPendingMediaTargets()
                            : [];

                        if (pendingTargets.length && typeof window.vmoSaveProjectSnapshot === 'function' && typeof window.vmoMediaGenerator.queueProjectMedia === 'function') {
                            const savedProject = await window.vmoSaveProjectSnapshot({
                                title: window.currentProjectTitle || 'Auto-saved Website',
                                html: cleanHtml,
                                state: window.vmoState,
                                markSaved: false
                            });

                            mediaResult = await window.vmoMediaGenerator.queueProjectMedia({
                                source: 'generation',
                                targets: pendingTargets,
                                projectId: savedProject && savedProject.projectId ? savedProject.projectId : (window.currentProjectId || 0),
                                html: cleanHtml,
                                state: window.vmoState,
                                title: window.currentProjectTitle || 'Auto-saved Website'
                            });
                        } else {
                            mediaResult = await window.vmoMediaGenerator.resolvePendingMedia({
                                source: 'generation',
                                requireComplete: true,
                                onProgress: function(progress) {
                                    if (typeof window.showToast !== 'function') return;
                                    const progressText = progress.total
                                        ? `Finishing website media ${progress.completed}/${progress.total}: ${progress.message}`
                                        : progress.message;
                                    window.showToast(progressText, progress.failed ? 'error' : 'info', true, true);
                                }
                            });
                        }
                    } catch (mediaError) {
                        console.error('[VMO] Background media queue failed, falling back to foreground completion:', mediaError);
                        try {
                            mediaResult = await window.vmoMediaGenerator.resolvePendingMedia({
                                source: 'generation',
                                requireComplete: true,
                                onProgress: function(progress) {
                                    if (typeof window.showToast !== 'function') return;
                                    const progressText = progress.total
                                        ? `Finishing website media ${progress.completed}/${progress.total}: ${progress.message}`
                                        : progress.message;
                                    window.showToast(progressText, progress.failed ? 'error' : 'info', true, true);
                                }
                            });
                        } catch (fallbackMediaError) {
                            console.error('[VMO] Media completion failed:', fallbackMediaError);
                            mediaResult = {
                                complete: false,
                                total: 0,
                                completed: 0,
                                failed: [{ message: fallbackMediaError?.message || 'Required media generation failed.' }]
                            };
                        }
                    }
                }

                const mediaQueuedInBackground = !!(mediaResult && mediaResult.queued);
                const websiteReady = mediaQueuedInBackground || !mediaResult || mediaResult.complete !== false;
                const builderMessage = mediaQueuedInBackground
                    ? 'Generated new website content and started the required media in the background. You can keep refining or leave the builder while the remaining assets finish.'
                    : (websiteReady
                        ? (isRefinement ? 'Refinement complete. I applied the requested changes.' : 'Generated new website content, finished the required media, and updated the preview.')
                        : 'Website layout drafted, but required media generation is still incomplete. The website is not ready yet.');
                const toastMessage = mediaQueuedInBackground
                    ? 'Website generated. Media is continuing in the background.'
                    : (websiteReady
                        ? (isRefinement ? 'Content refined successfully!' : 'Website generated successfully!')
                        : (mediaResult.failed.length
                            ? mediaResult.failed.map((item) => item.message).slice(0, 2).join(' ')
                            : 'Required media generation did not complete. The website is not ready yet.'));

                if (websiteReady) {
                    $('#vmo-prompt-input').val('');
                }

                if (typeof window.showToast === 'function') {
                    window.showToast(toastMessage, websiteReady ? 'success' : 'error');
                }

                console.log('[VMO] Content generation completed:', { websiteReady, mediaResult });
                appendChatMessage('ai', builderMessage);

                // Voice integration disabled - text only interface
                console.log('� Voice auto-speak disabled in no-voice version');

                // Update balance
                if (vmo_ajax.token_balance) {
                    const tokensUsed = parseInt(res.data?.tokens_used || (isRefinement ? 225 : 2500), 10);
                    if (res.data?.new_balance !== undefined && res.data?.new_balance !== null) {
                        vmo_ajax.token_balance = Math.max(0, parseInt(res.data.new_balance, 10));
                    } else {
                        vmo_ajax.token_balance = Math.max(0, parseInt(vmo_ajax.token_balance, 10) - tokensUsed);
                    }
                    $('#vmo-token-balance').text('Balance: ' + vmo_ajax.token_balance);
                    
                    // Check for upgrade notification (use plan allocation, not hardcoded value)
                    const planAllocation = parseInt(vmo_ajax.plan_tokens || vmo_ajax.token_balance || 72326);
                    const remainingPercentage = (parseInt(vmo_ajax.token_balance) / planAllocation) * 100;
                    if (remainingPercentage <= 30 && remainingPercentage > 0) {
                        setTimeout(() => {
                            if (typeof window.showToast === 'function') {
                                window.showToast('⚡ Low balance. Consider upgrading for more capacity.', 'warning', false, true);
                            }
                        }, 3000);
                    }
                }

            } else {
                console.error('[VMO] Generation failed:', res);
                let errorMessage = 'Failed to generate content.';
                
                // Handle specific error cases
                if (res.data?.code === 'insufficient_tokens') {
                    errorMessage = '⚠️ Insufficient balance. Please upgrade or add an add-on.';
                } else if (res.data?.message) {
                    errorMessage = res.data.message;
                }
                
                if (typeof window.showToast === 'function') {
                    window.showToast(errorMessage, 'error');
                }
                appendChatMessage('ai', errorMessage);
            }
        }).fail(function(jqXHR, textStatus, errorThrown) {
            console.error('[VMO] AJAX Error:', textStatus, errorThrown, jqXHR.responseText);
            if (typeof window.hideToast === 'function') {
                window.hideToast(true);
            }
            if (typeof window.showToast === 'function') {
                let errorMsg = 'Server error. Please try again.';
                if (jqXHR.status === 403) {
                    errorMsg = 'Permission denied. Please refresh and try again.';
                } else if (jqXHR.status === 500) {
                    errorMsg = 'Server error. Please check your service configuration and try again.';
                }
                window.showToast(errorMsg, 'error');
            }
            appendChatMessage('ai', 'There was a problem contacting the server. Please try again.');
        }).always(function() {
            window.isGenerating = false;
            $('#vmo-send-btn').prop('disabled', false).removeClass('vmo-btn-loading');
        });
    }

    /* ========== 🔧 FIX: MISSING CORE FUNCTIONS ========== */
    
    // 🔧 FIX: Main AI communication router
    window.sendToAI = function(prompt, type = 'refinement') {
        if (!prompt?.trim()) {
            window.showToast('Please enter a prompt.', 'error');
            return;
        }

        console.log(`[VMO] Sending ${type} request to AI:`, prompt);

        switch(type) {
            case 'refinement':
                if (window.refineWithUserEdit) {
                    window.refineWithUserEdit(prompt);
                } else {
                    console.error('[VMO] Refinement function not available');
                    window.showToast('Refinement system not loaded.', 'error');
                }
                break;
                
            case 'media':
                window.insertMediaViaAI(prompt);
                break;
                
            case 'generation':
                window.generateContentViaAI(prompt);
                break;
                
            default:
                console.warn(`[VMO] Unknown AI request type: ${type}`);
                window.showToast('Unknown request type.', 'error');
        }
    };

    // 🔧 FIX: Handle prompt sending from UI
    window.handlePromptSend = function() {
        const prompt = $('#vmo-prompt-input').val()?.trim();
        if (!prompt) {
            window.showToast('Please enter a prompt.', 'error');
            return;
        }

        console.log('[VMO] Processing prompt:', prompt);

        // Determine if this is new content generation or refinement
        const hasExistingContent = window.vmoState?.blocks?.length > 0;
        
        // Check if this is a media-specific request
        if (prompt.toLowerCase().includes('insert') && (prompt.toLowerCase().includes('image') || prompt.toLowerCase().includes('video') || prompt.toLowerCase().includes('media'))) {
            console.log('[VMO] Routing to media insertion');
            appendChatMessage('user', prompt);
            window.insertMediaViaAI(prompt);
            $('#vmo-prompt-input').val('');
            return;
        }
        
        // Identify explicit build/generate intents
        const wantsGeneration = /\b(build|generate|create|make)\b.*\b(site|website|page|homepage|landing)\b/i.test(prompt);
        const wantsRefine = hasExistingContent && /(change|modify|update|refine|edit)/i.test(prompt);

        if (wantsGeneration) {
            // Respect consultation gate
            if (!window.vmoEnsureConsultationReady(() => {})) {
                $('#vmo-prompt-input').val('');
                return;
            }
            console.log('[VMO] User explicitly asked to generate');
            appendChatMessage('user', prompt);
            generateContent(prompt, false);
        } else if (wantsRefine) {
            // Only allow refinement if generation has been unlocked
            if (!window.vmoEnsureConsultationReady(() => {})) {
                $('#vmo-prompt-input').val('');
                return;
            }
            console.log('[VMO] Routing to refinement');
            appendChatMessage('user', prompt);
            window.sendToAI(prompt, 'refinement');
        } else {
            // Default: conversational assistant
            console.log('[VMO] Routing to conversational assistant');
            sendConversationMessage(prompt);
        }
        
        $('#vmo-prompt-input').val(''); // Clear input
    };

    // 🔧 FIX: Media insertion trigger
    window.insertMedia = function(type = 'image', sectionIndex = null) {
        const description = prompt(`Enter description for the ${type}:`);
        if (!description?.trim()) return;

        if (sectionIndex !== null) {
            window.insertMediaIntoSection(sectionIndex, type, description);
        } else {
            // Insert into current/last section
            const lastIndex = (window.vmoState?.blocks?.length || 1) - 1;
            window.insertMediaIntoSection(lastIndex, type, description);
        }
    };

    // 🔧 FIX: Enhanced content generation
    window.generateContentViaAI = function(prompt) {
        console.log('[VMO] Starting AI content generation:', prompt);
        window.showToast('Generating content...', 'info', true, true);

        // Use the main generation function
        generateContent(prompt, false);
    };

    // 🔧 FIX: Media insertion via AI
    window.insertMediaViaAI = function(prompt) {
        // Extract media type and description from prompt
        let mediaType = 'image';
        if (prompt.toLowerCase().includes('video')) mediaType = 'video';
        
        // Use refinement system to add media
        const refinementPrompt = `Add a ${mediaType} with description: "${prompt}". Use [GENERATED_${mediaType.toUpperCase()}: ${prompt}] placeholder.`;
        
        if (window.refineWithUserEdit) {
            window.refineWithUserEdit(refinementPrompt);
        }
    };

    // 🔧 Helper: Call multi-agent router (SEO, website, research, legal, stripe, reports)
    window.callAgent = async function(taskType, userInput, context = {}) {
        const ajaxUrl = (window.vmo_ajax && vmo_ajax.ajaxurl) || (window.vmoAjax && (vmoAjax.ajaxurl || vmoAjax.ajax_url)) || '/wp-admin/admin-ajax.php';
        const nonce = (window.vmo_ajax && vmo_ajax.nonce) || (window.vmoAjax && (vmoAjax.security || vmoAjax.nonce)) || '';

        if (!taskType || !userInput) {
            if (typeof window.showToast === 'function') window.showToast('Missing task type or input for agent.', 'warning');
            return { error: 'Missing task type or input' };
        }

        try {
            const form = new FormData();
            form.append('action', 'vmo_route_agent_task');
            form.append('security', nonce);
            form.append('task_type', taskType);
            form.append('user_input', userInput);
            if (context && Object.keys(context).length) form.append('context', JSON.stringify(context));

            const resp = await fetch(ajaxUrl, { method: 'POST', body: form });
            if (!resp.ok) throw new Error('HTTP ' + resp.status);
            const data = await resp.json();
            if (!data.success) throw new Error(data.data?.message || 'Agent call failed');
            return data.data;
        } catch (e) {
            console.error('[VMO] Agent error:', e);
            if (typeof window.showToast === 'function') window.showToast('Agent error: ' + e.message, 'error');
            return { error: e.message };
        }
    };

    // 🔧 FIX: Bind missing event handlers on document ready
    $doc.ready(function() {
        // Bind prompt send button
        $(document).on('click', '#vmo-send-btn, #vmo-prompt-send', function() {
            window.handlePromptSend();
        });

        // 📷 Media Integration Button - opens AI-powered media modal
        $(document).on('click', '#vmo-media-btn', function(e) {
            e.preventDefault();
            e.stopPropagation();
            
            // Check if openInsertMediaModal is available
            if (typeof window.openInsertMediaModal === 'function') {
                window.openInsertMediaModal('insert', null, 'image');
            } else {
                console.error('[VMO Media] openInsertMediaModal not available');
                if (typeof window.showToast === 'function') {
                    window.showToast('Media integration is loading, please try again.', 'info');
                }
            }
        });

        // Bind enter key in prompt input
        $(document).on('keypress', '#vmo-prompt-input', function(e) {
            if (e.which === 13 && !e.shiftKey) {
                e.preventDefault();
                window.handlePromptSend();
            }
        });

        // Bind media insertion buttons
        $(document).on('click', '[data-action="insert-image"]', function() {
            window.insertMedia('image');
        });

        $(document).on('click', '[data-action="insert-video"]', function() {
            window.insertMedia('video');
        });

        // Bind refinement shortcuts
        $(document).on('click', '[data-action="quick-refine"]', function() {
            const promptTemplate = $(this).data('prompt');
            if (promptTemplate) {
                window.sendToAI(promptTemplate, 'refinement');
            }
        });

        // Section click handler (selection only; never block form controls)
        $(document).on('click', '.vmo-section, [class*="section"]', function(e) {
            // If the user clicked a child control, do nothing (let the control behave normally)
            const $t = $(e.target);
            if ($t.is('input, textarea, select, button, a, label') || $t.closest('input, textarea, select, button, a, label').length) {
                return;
            }
            // Only handle clicks on the section background itself
            if (e.target !== this) return;

            // Clear previous selections
            $('.vmo-selected').removeClass('vmo-selected');

            // Mark clicked section as selected
            $(this).addClass('vmo-selected');
            const sectionIndex = $(this).index();

            console.log('[VMO] Section clicked:', sectionIndex);

            // Notify selection (inspector removed)
            if (window.showToast) window.showToast(`Section ${sectionIndex + 1} selected`, 'info');

            // Store selected section globally
            window.vmoSelectedSection = sectionIndex;
        });

        // Escape key handler removed (inspector removed)

        console.log('[VMO] Main script loaded with fixed communication handlers');

        // Bind Insert Media action button
        $(document).on('click', '#vmo-insert-image-btn', function(e){
            e.preventDefault();
            openInsertMediaModal();
        });

        // VMO Jarvis-style coordinating AI greeting system
        // Greets user based on their status: first_time, incomplete_consultation, or active_business
        if (true) {
        setTimeout(() => {
            console.log('🎤 VMO Greeting: Checking...');
            // Temporarily disable session check for testing - greeting will show every time
            sessionStorage.removeItem('vmo_greeted_once');
            if (sessionStorage.getItem('vmo_greeted_once')) return;
            // Fetch user status for greeting scenario
            const ajaxUrl = (window.vmo_ajax && vmo_ajax.ajaxurl) || (window.vmoAjax && (vmoAjax.ajaxurl || vmoAjax.ajax_url)) || '/wp-admin/admin-ajax.php';
            const nonce = (window.vmo_ajax && window.vmo_ajax.nonce) || (window.vmoAjax && (window.vmoAjax.security || window.vmoAjax.nonce)) || '';
            $.post(ajaxUrl, {
                action: 'vmo_get_user_status_for_greeting',
                security: nonce
            }, function(response) {
                if (!response || !response.success || !response.data) return;
                const data = response.data;
                let greet = '';
                if (data.status === 'first_time') {
                    greet = `Welcome, ${data.display_name}. I'm Jarvis, your VMO AI launch guide. Your website builder is ready, and the wider VMO team is standing by across strategy, content, design, SEO, media, documents, and automation. Click the red Business Wizard button to meet Jerreme and begin building your business the right way.`;
                } else if (data.status === 'incomplete_consultation') {
                    greet = `Welcome back, ${data.display_name}. I'm Jarvis, your VMO launch guide. Your builder is ready, and behind me is the full VMO AI team covering design, content, SEO, documents, media, and automation. Click the red Business Wizard button to speak with Jerreme and continue your consultation.`;
                } else if (data.status === 'active_business') {
                    greet = `Welcome back, ${data.display_name}. Jarvis here. Your VMO team is ready to keep building, refining, and managing your business. If you want strategy, content, design, or new execution work, open the red Business Wizard button and Jerreme will take it from there.`;
                } else {
                    greet = `Welcome! I am VMO, your coordinating AI business manager. Let's get started building your business empire.`;
                }
                appendChatMessage('ai', greet);
                sessionStorage.setItem('vmo_greeted_once', '1');
                // Auto-speak greeting and auto-enable voice conversation mode (skip v8's internal welcome)
                try {
                    if (window.VMOVoice && window.VMOVoice.autoSpeakResponse) {
                        window.VMOVoice.autoSpeakResponse(greet, () => {
                            if (window.vmoVoiceSystem && typeof window.vmoVoiceSystem.startConversationMode === 'function') {
                                window.vmoVoiceSystem.startConversationMode(true);
                            }
                        });
                    } else if (window.vmoVoice && window.vmoVoice.autoSpeak) {
                        window.vmoVoice.autoSpeak(greet, () => {
                            if (window.vmoVoiceSystem && typeof window.vmoVoiceSystem.startConversationMode === 'function') {
                                window.vmoVoiceSystem.startConversationMode(true);
                            }
                        });
                    } else if (window.vmoVoiceSystem && typeof window.vmoVoiceSystem.startConversationMode === 'function') {
                        window.vmoVoiceSystem.startConversationMode(false);
                    }
                } catch(e) { console.warn('Voice greeting error', e); }
                // Set voice conversation button ON by default
                if ($('#vmo-wizard-voice').length) {
                    $('#vmo-wizard-voice').addClass('active').attr('aria-pressed', 'true');
                }
                // Ensure speech-to-text button is OFF
                if ($('#vmo-wizard-transcribe').length) {
                    $('#vmo-wizard-transcribe').removeClass('active').attr('aria-pressed', 'false');
                }
            });
        }, 2000); // 2-second delay for better user experience
        } // End of disabled greeting block
    });

    // Enhance content for mobile responsiveness
    function enhanceContentForMobile(html) {
        // Ensure viewport meta tag is present
        if (!html.includes('viewport')) {
            html = html.replace('<head>', '<head>\n<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">');
        }
        
        // Add mobile-responsive CSS if not present
        if (!html.includes('box-sizing: border-box')) {
            const mobileCSS = `
<style>
/* Mobile-First Responsive Framework */
* {
    box-sizing: border-box;
}

html {
    font-size: 16px;
    scroll-behavior: smooth;
}

body {
    margin: 0;
    padding: 0;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
    line-height: 1.6;
    color: #333;
    overflow-x: hidden;
}

/* Container responsive behavior */
.container, .section {
    width: 100%;
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 16px;
}

/* Responsive images and media */
img, video {
    max-width: 100%;
    height: auto;
    display: block;
}

/* Touch-friendly buttons */
button, .btn, a.button {
    min-height: 44px;
    min-width: 44px;
    padding: 12px 24px;
    font-size: 16px;
    border-radius: 8px;
    cursor: pointer;
    touch-action: manipulation;
    text-decoration: none;
    display: inline-block;
}

/* Responsive typography */
h1 { font-size: clamp(24px, 4vw, 48px); }
h2 { font-size: clamp(20px, 3.5vw, 36px); }
h3 { font-size: clamp(18px, 3vw, 28px); }
h4 { font-size: clamp(16px, 2.5vw, 24px); }
p, li { font-size: clamp(14px, 2vw, 18px); }

/* Flex layouts for responsiveness */
.flex {
    display: flex;
    flex-wrap: wrap;
}

.grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 20px;
}

/* Tablet adjustments */
@media (min-width: 768px) {
    .container, .section {
        padding: 0 32px;
    }
}

/* Desktop adjustments */
@media (min-width: 1024px) {
    .container, .section {
        padding: 0 48px;
    }
}

/* Ensure iframe content fits properly */
@media (max-width: 767px) {
    body {
        padding: 0 !important;
        margin: 0 !important;
    }
    
    .section {
        padding-left: 16px !important;
        padding-right: 16px !important;
    }
}
</style>`;

            // Insert mobile CSS after the first <style> tag or before </head>
            if (html.includes('<style>')) {
                html = html.replace('<style>', mobileCSS + '\n<style>');
            } else if (html.includes('</head>')) {
                html = html.replace('</head>', mobileCSS + '\n</head>');
            } else {
                html = mobileCSS + '\n' + html;
            }
        }
        
        return html;
    }

    /* other original code (GPT generation etc.) remains UNTOUCHED BELOW */

})(window.jQuery);
