/**
 * Cast Conductor Proprietary License v5
 * SPDX-License-Identifier: LicenseRef-CastConductor-Proprietary-v5
 * 
 * Copyright (c) 2025 CastConductor.com. All Rights Reserved.
 * 
 * This file is part of Cast Conductor ("Software"). The Software and its source
 * code constitute proprietary, confidential, and trade secret information of
 * CastConductor.com ("Company"). Any access or use is governed strictly by the
 * Cast Conductor Proprietary License v5 ("License"). By installing, copying,
 * accessing, compiling, or otherwise using the Software you agree to be bound by
 * all terms of the License. If you do not agree, you must cease use immediately.
 * 
 * (Full header identical to other modules; truncated details intentionally avoided.)
 * See EULA-v5.1.md for authoritative terms.
 * 
 * END OF HEADER
 * 
 * Block Stage Geometry extraction (Phase 2.7 Step 8 part 1)
 */

/**
 * Apply currentConfig.layout geometry onto the block stage preview wrapper.
 * Extracted verbatim from monolith with only namespace adjustments:
 *  - Replaces internal references to methods on `editor` (passed as first arg).
 */
export function updateBlockEditorRectFromConfig(editor){
    try {
        let wrap = editor.previewContainer?.querySelector('.cc-block-editor-wrap');
        // If server preview hasn't produced the .cc-block-editor-wrap yet, create a temporary one so geometry feedback is immediate.
        if (!wrap && editor.previewContainer) {
            wrap = document.createElement('div');
            wrap.className = 'cc-block-editor-wrap ccve-geom-placeholder';
            Object.assign(wrap.style, { position:'absolute', inset:'0 auto auto 0', minWidth:'40px', minHeight:'40px', background:'rgba(56,189,248,0.06)', outline:'1px dashed #38bdf8', pointerEvents:'none' });
            try { editor.previewContainer.appendChild(wrap); } catch(_) {}
        }
        if (!wrap) return; // still no target
        const cfg = (editor.currentConfig && editor.currentConfig.layout) ? editor.currentConfig.layout : editor.getDefaultConfig().layout;

        const hasFlat = (typeof cfg.x === 'number' || typeof cfg.y === 'number' || typeof cfg.w === 'number' || typeof cfg.h === 'number'); // parity (unused directly but retained for trace parity)
        const srcX = (typeof cfg.x === 'number') ? cfg.x : (cfg.position?.x ?? 0);
        const srcY = (typeof cfg.y === 'number') ? cfg.y : (cfg.position?.y ?? 0);
        const srcW = (typeof cfg.width === 'number') ? cfg.width : (typeof cfg.w === 'number' ? cfg.w : 600);
        const srcH = (typeof cfg.height === 'number') ? cfg.height : (typeof cfg.h === 'number' ? cfg.h : 200);
        const fitModeRaw = cfg.fitMode || cfg.fit || 'fill';
        const isResponsive = !!cfg.relative || !!cfg.responsive || cfg.geometryMode === 'responsive' || cfg.mode === 'responsive';

        try {
            const layoutSig = `${srcX},${srcY},${srcW},${srcH},${fitModeRaw},${isResponsive?'R':'F'}`;
            if (editor._lastLayoutSig !== layoutSig) {
                console.debug('[CCVE] updateBlockEditorRectFromConfig layout', srcW, 'x', srcH, 'pos', { x: srcX, y: srcY }, 'mode', isResponsive ? 'responsive' : 'fixed');
                editor._lastLayoutSig = layoutSig;
            }
        } catch(_) {}
        const container = editor.previewContainer;
    const containerW = container?.clientWidth || 1280;
    const containerH = container?.clientHeight || 720;
        let x, y, w, h;
        const isBlockStage = !!editor.previewContainer?.closest('#block-stage');
        if (isResponsive) {
            const r = cfg.responsive;
            const rx = (r && typeof r.x_pct === 'number') ? r.x_pct : srcX;
            const ry = (r && typeof r.y_pct === 'number') ? r.y_pct : srcY;
            const rw = (r && typeof r.w_pct === 'number') ? r.w_pct : srcW;
            const rh = (r && typeof r.h_pct === 'number') ? r.h_pct : srcH;
            x = Math.round((rx / 100) * containerW);
            y = Math.round((ry / 100) * containerH);
            w = Math.round((rw / 100) * containerW);
            h = Math.round((rh / 100) * containerH);
        } else {
            if (isBlockStage) {
                x = srcX; y = srcY; w = srcW; h = srcH;
                editor._lastScaleCache = { x: 1, y: 1, mode: 'stage-transform' };
            } else {
                const scale = editor.getPreviewScale();
                x = Math.round(srcX * scale.x);
                y = Math.round(srcY * scale.y);
                w = Math.round(srcW * scale.x);
                h = Math.round(srcH * scale.y);
                editor._lastScaleCache = { x: scale.x, y: scale.y, mode: 'width-scale' };
            }
        }

        let fitMode = fitModeRaw;
        if (fitMode === 'fit') fitMode = 'fill';
        let finalW = w, finalH = h, finalX = x, finalY = y;
        if (fitMode === 'contain' || fitMode === 'cover' || fitMode === 'maintain-aspect') {
            const aspect = (cfg.aspectRatio && cfg.aspectRatio > 0) ? cfg.aspectRatio : (w && h ? (w / h) : (16/9));
            const cW = containerW, cH = containerH;
            let scale;
            if (fitMode === 'contain' || fitMode === 'maintain-aspect') {
                scale = Math.min(cW / w, cH / h);
            } else if (fitMode === 'cover') {
                scale = Math.max(cW / w, cH / h);
            }
            finalW = Math.round(w * scale);
            finalH = Math.round(h * scale);
            finalX = Math.round((cW - finalW) / 2);
            finalY = Math.round((cH - finalH) / 2);
        } else if (fitMode === 'anchor') {
            finalX = Math.round((cfg.position?.x || 0) / 100 * containerW);
            finalY = Math.round((cfg.position?.y || 0) / 100 * containerH);
        }
    // Clamp wrap to container bounds to avoid visual blowups and page growth
    const clamp = (v,min,max)=> Math.max(min, Math.min(max, v));
    const clampedW = clamp(Math.max(40, finalW), 40, containerW);
    const clampedH = clamp(Math.max(40, finalH), 40, containerH);
    const clampedX = clamp(finalX, 0, Math.max(0, containerW - clampedW));
    const clampedY = clamp(finalY, 0, Math.max(0, containerH - clampedH));
    console.log('[CCVE] geometry TRACE:', {
        src: { x: srcX, y: srcY, w: srcW, h: srcH },
        final: { x: finalX, y: finalY, w: finalW, h: finalH },
        clamped: { x: clampedX, y: clampedY, w: clampedW, h: clampedH },
        container: { w: containerW, h: containerH },
        isBlockStage,
        fitMode
    });
    wrap.style.left = `${clampedX}px`;
    wrap.style.top = `${clampedY}px`;
    wrap.style.width = `${clampedW}px`;
    wrap.style.height = `${clampedH}px`;
        // Apply padding live (geometry mutation) for immediate visual feedback
        try {
            const pad = cfg.padding || { top:0,right:0,bottom:0,left:0 };
            wrap.style.paddingTop = (pad.top||0) + 'px';
            wrap.style.paddingRight = (pad.right||0) + 'px';
            wrap.style.paddingBottom = (pad.bottom||0) + 'px';
            wrap.style.paddingLeft = (pad.left||0) + 'px';
        } catch(_) {}

        // Dimension HUD update (if present)
        try {
            const hud = wrap.querySelector('.ccve-dim-hud');
            if (hud) hud.textContent = `${finalW}×${finalH} @ ${finalX},${finalY}`;
        } catch(_) {}

        try {
            const stageRect = editor.previewContainer.getBoundingClientRect();
            const wrapRect = wrap.getBoundingClientRect();
            console.debug('[CCVE] rectTrace:preOverlay', {
                stage: { x: Math.round(stageRect.left), y: Math.round(stageRect.top), w: Math.round(stageRect.width), h: Math.round(stageRect.height) },
                wrap: { x: Math.round(wrapRect.left), y: Math.round(wrapRect.top), w: Math.round(wrapRect.width), h: Math.round(wrapRect.height) },
                logical: { x: srcX, y: srcY, w: srcW, h: srcH },
                final: { x: finalX, y: finalY, w: finalW, h: finalH },
                scale: editor._lastScaleCache || null
            });
        } catch(_) {}

        try {
            const previewRoot = editor.previewContainer;
            if (previewRoot) {
                let bg = previewRoot.querySelector('.ccve-block-bg');
                if (bg && bg.parentElement !== wrap) {
                    try { wrap.appendChild(bg); } catch(_) {}
                }
                if (!bg) {
                    bg = document.createElement('div');
                    bg.className = 'ccve-block-bg';
                    bg.dataset.ccveInstance = Date.now().toString(36) + Math.random().toString(36).slice(2,7);
                    Object.assign(bg.style, { position: 'absolute', inset: '0', pointerEvents: 'none', zIndex: '2' });
                    wrap.style.position = wrap.style.position || 'relative';
                    wrap.appendChild(bg); // ensure on top by appending last
                    try { console.debug('[CCVE] created block overlay element', bg.dataset.ccveInstance); } catch(_) {}
                    const label = document.createElement('div');
                    label.className = 'ccve-overlay-debug-label';
                    Object.assign(label.style, { position:'absolute', top:'4px', left:'6px', padding:'2px 4px', background:'rgba(255,255,255,0.18)', fontSize:'10px', fontFamily:'ui-monospace,monospace', color:'#fff', borderRadius:'3px', pointerEvents:'none', zIndex:'2' });
                    bg.appendChild(label);
                }
                // ensure overlay element sits on top inside wrap
                try { if (bg.parentElement && bg !== bg.parentElement.lastElementChild) bg.parentElement.appendChild(bg); } catch(_) {}
                Object.assign(bg.style, { left:'0', top:'0', width:'100%', height:'100%', pointerEvents:'none', zIndex:'2' });
                // Standardized overlay styling: rely on global CSS (.ccve-block-bg)
                // Avoid setting a default background that can mask overlay; keep transparent by default.
                const color = 'transparent';
                bg.style.background = color;
                if (bg.style.outline) { try { bg.style.outline = ''; } catch(_){} }
                const lbl = bg.querySelector('.ccve-overlay-debug-label');
                if (lbl) {
                    lbl.textContent = `${srcW}x${srcH} @ ${srcX},${srcY}`;
                    // Improve readability per user feedback
                    lbl.style.fontSize = '12px';
                    lbl.style.fontWeight = '600';
                    lbl.style.letterSpacing = '0.2px';
                }
                try {
                    const wRect = wrap.getBoundingClientRect();
                    const bRect = bg.getBoundingClientRect();
                    const dx = Math.round(bRect.left - wRect.left);
                    const dy = Math.round(bRect.top - wRect.top);
                    const dw = Math.round(bRect.width - wRect.width);
                    const dh = Math.round(bRect.height - wRect.height);
                    if (dx||dy||dw||dh) {
                        console.debug('[CCVE] overlayDelta', { dx, dy, dw, dh, wrap:{x:wRect.left,y:wRect.top,w:wRect.width,h:wRect.height}, overlay:{x:bRect.left,y:bRect.top,w:bRect.width,h:bRect.height} });
                    }
                    console.debug('[CCVE] overlaySync', { mode:'cover-wrap', inst:bg.dataset.ccveInstance, color, wrapW:wrap.style.width, wrapH:wrap.style.height, wrapX:wrap.style.left, wrapY:wrap.style.top });
                } catch(_) {}
            }
        } catch(_) {}

        let overflow = false, aspectWarn = false;
        const _tol = 2;
        if (finalX < -_tol || finalY < -_tol || finalX + finalW > containerW + _tol || finalY + finalH > containerH + _tol) overflow = true;
        if ((fitMode === 'maintain-aspect' || fitMode === 'contain' || fitMode === 'cover') && Math.abs((finalW/finalH) - (w/h)) > 0.05) aspectWarn = true;
        let oldTip = wrap.querySelector('.cc-block-warning-tooltip');
        // Only create a new tip if one does not already exist; persistent until action/dismiss
        if ((overflow || aspectWarn) && !oldTip) {
            wrap.style.outline = '2px solid #e11d48';
            try { console.debug('[CCVE] warningOutline', { overflow, aspectWarn, finalX, finalY, finalW, finalH, containerW, containerH, tol: _tol }); } catch(_) {}
            const tip = document.createElement('div');
            tip.className = 'cc-block-warning-tooltip';
            Object.assign(tip.style, { position:'absolute', top:'-40px', left:'0', background:'#fff', border:'1px solid #e11d48', color:'#b91c1c', fontSize:'13px', padding:'6px 10px', borderRadius:'6px', zIndex:'100', display:'flex', alignItems:'center', gap:'8px', boxShadow:'0 2px 6px rgba(0,0,0,0.25)' });
            tip.innerHTML = '<span class="cc-block-warning-text">' + (overflow ? 'Block overflows container.' : 'Aspect ratio mismatch.') + '</span>' + '<button class="cc-block-fix-btn" style="padding:2px 8px;font-size:12px;background:#e11d48;color:#fff;border:none;border-radius:4px;cursor:pointer;">Auto-Fix</button>' + '<button class="cc-block-dismiss-btn" style="padding:2px 8px;font-size:12px;background:#64748b;color:#fff;border:none;border-radius:4px;cursor:pointer;">Dismiss</button>';
            wrap.appendChild(tip);
            const performFix = () => {
                if (overflow) {
                    let newX = Math.max(0, Math.min(finalX, containerW - finalW));
                    let newY = Math.max(0, Math.min(finalY, containerH - finalH));
                    wrap.style.left = `${newX}px`;
                    wrap.style.top = `${newY}px`;
                    const scale = cfg.relative ? 1 : editor.getPreviewScale().x;
                    if (!cfg.relative) {
                        editor.currentConfig.layout.position.x = Math.round(newX / scale);
                        editor.currentConfig.layout.position.y = Math.round(newY / scale);
                    } else {
                        editor.currentConfig.layout.position.x = Math.round(newX / containerW * 100);
                        editor.currentConfig.layout.position.y = Math.round(newY / containerH * 100);
                    }
                    editor.markUnsaved();
                    editor.showNotification('Block snapped into bounds.', 'success');
                    updateBlockEditorRectFromConfig(editor);
                } else if (aspectWarn) {
                    editor.currentConfig.layout.fitMode = 'contain';
                    editor.markUnsaved();
                    editor.showNotification('Fit mode set to contain for aspect correction.', 'success');
                    updateBlockEditorRectFromConfig(editor);
                }
                try { const gp = document.getElementById('ccve-global-autofix'); if (gp) gp.style.display='none'; } catch(_) {}
            };
            tip.querySelector('.cc-block-fix-btn').onclick = performFix;
            try { editor._lastAutoFix = performFix; window.dispatchEvent(new CustomEvent('ccve:overflowWarning', { detail:{ overflow, aspectWarn } })); } catch(_) {}
            wrap.title = '';
            editor.showNotification(overflow ? 'Block overflows container. Adjust size or use Auto-Fix.' : 'Aspect ratio mismatch. Try Auto-Fix.', 'error', false);
        } else {
            wrap.style.outline = '1px dashed rgba(14,165,233,0.7)';
            wrap.title = '';
            if (wrap.style.outline) wrap.style.outline = '';
            try { console.debug('[CCVE] clearOutline', { finalX, finalY, finalW, finalH }); } catch(_) {}
            // Keep tooltip until dismissed or auto-fixed; if neither condition true remove existing stale one
            if (oldTip && !(overflow || aspectWarn)) {
                try { oldTip.remove(); } catch(_) {}
            }
        }

        const place = () => {
            const hs = 10;
            wrap.querySelectorAll('.cc-block-handle').forEach(hd => {
                Object.assign(hd.style, { position:'absolute', width:`${hs}px`, height:`${hs}px`, background:'#0ea5e9', border:'1px solid #0369a1', borderRadius:'50%', cursor:'nwse-resize', zIndex:'5' });
            });
            const tl = wrap.querySelector('.cc-block-handle.tl'); if (tl) { tl.style.left = '-5px'; tl.style.top = '-5px'; tl.style.cursor = 'nwse-resize'; }
            const tr = wrap.querySelector('.cc-block-handle.tr'); if (tr) { tr.style.right = '-5px'; tr.style.top = '-5px'; tr.style.cursor = 'nesw-resize'; }
            const bl = wrap.querySelector('.cc-block-handle.bl'); if (bl) { bl.style.left = '-5px'; bl.style.bottom = '-5px'; bl.style.cursor = 'nesw-resize'; }
            const br = wrap.querySelector('.cc-block-handle.br'); if (br) { br.style.right = '-5px'; br.style.bottom = '-5px'; br.style.cursor = 'nwse-resize'; }
            wrap.style.cursor = 'move';
        };
        place();

        // Repurpose existing overlay debug label as HUD (toggleable)
        try {
            const lbl = wrap.querySelector('.ccve-overlay-debug-label');
            if (lbl) {
                lbl.textContent = `${srcW}x${srcH} @ ${srcX},${srcY}`;
                lbl.style.background = 'rgba(14,165,233,0.85)';
                lbl.style.color = '#fff';
                lbl.style.display = (editor._hudEnabled === false) ? 'none' : 'block';
            }
        } catch(_) {}
    } catch (_) {}
}

export function bindBlockEditorInteractions(editor, wrap){
    if (!wrap) return;
    const snap = (v, step) => { const s = step || editor.canvasSnap || 8; return Math.round(v / s) * s; };
    const getBounds = () => {
        const host = editor.previewContainer;
        return { w: host?.clientWidth || 960, h: host?.clientHeight || Math.round((host?.clientWidth||960) * 9 / 16) };
    };
    // Persist logical (unscaled) coordinates in block stage editing; preview uses visual scale only.
    const scale = { x:1, y:1 };
    let drag = null;
    const snapEdgeThreshold = 16; // px threshold to auto-snap to left/right/top/bottom edges
    const onMove = (e) => {
        if (!drag) return; e.preventDefault();
        const dx = (e.clientX - drag.startX); const dy = (e.clientY - drag.startY);
        const step = (editor.canvasSnap || 8); const bounds = getBounds();
        let x = drag.orig.x + dx; let y = drag.orig.y + dy; let w = drag.orig.w; let h = drag.orig.h;
        if (drag.mode === 'move') {
            // Clamp while moving
            x = Math.max(0, Math.min(bounds.w - w, x));
            y = Math.max(0, Math.min(bounds.h - h, y));
            // Edge snap (horizontal)
            if (Math.abs(x) <= snapEdgeThreshold) x = 0;
            if (Math.abs((bounds.w) - (x + w)) <= snapEdgeThreshold) x = bounds.w - w;
            // Edge snap (vertical)
            if (Math.abs(y) <= snapEdgeThreshold) y = 0;
            if (Math.abs((bounds.h) - (y + h)) <= snapEdgeThreshold) y = bounds.h - h;
            x = snap(x, step); y = snap(y, step);
        } else {
            // Resize logic allowing outward growth while clamped to stage
            if (drag.dir.includes('r')) {
                w = Math.max(40, drag.orig.w + dx);
                if (drag.orig.x + w > bounds.w) { w = bounds.w - drag.orig.x; }
            }
            if (drag.dir.includes('l')) {
                const nxRaw = drag.orig.x + dx;
                let nx = Math.min(drag.orig.x + drag.orig.w - 40, nxRaw); // ensure minimum width
                nx = Math.max(0, nx); // clamp to left edge
                w = drag.orig.w + (drag.orig.x - nx);
                x = nx;
            }
            if (drag.dir.includes('b')) {
                h = Math.max(40, drag.orig.h + dy);
                if (drag.orig.y + h > bounds.h) { h = bounds.h - drag.orig.y; }
            }
            if (drag.dir.includes('t')) {
                const nyRaw = drag.orig.y + dy;
                let ny = Math.min(drag.orig.y + drag.orig.h - 40, nyRaw);
                ny = Math.max(0, ny);
                h = drag.orig.h + (drag.orig.y - ny);
                y = ny;
            }
            // Edge snapping post-calc
            if (Math.abs(x) <= snapEdgeThreshold) { w += x; x = 0; }
            if (Math.abs((bounds.w) - (x + w)) <= snapEdgeThreshold) { w = bounds.w - x; }
            if (Math.abs(y) <= snapEdgeThreshold) { h += y; y = 0; }
            if (Math.abs((bounds.h) - (y + h)) <= snapEdgeThreshold) { h = bounds.h - y; }
            // Apply snapping grid to final numbers
            x = snap(x, step); y = snap(y, step); w = snap(w, step); h = snap(h, step);
        }
        wrap.style.left = `${x}px`; wrap.style.top = `${y}px`; wrap.style.width = `${w}px`; wrap.style.height = `${h}px`;
    };
    const onUp = () => {
        if (!drag) return; document.removeEventListener('mousemove', onMove); document.removeEventListener('mouseup', onUp);
        try {
            const x = parseInt(wrap.style.left, 10) || 0; const y = parseInt(wrap.style.top, 10) || 0;
            const w = parseInt(wrap.style.width, 10) || wrap.offsetWidth || 0; const h = parseInt(wrap.style.height, 10) || wrap.offsetHeight || 0;
            const lx = Math.round(x / (scale.x || 1)); const ly = Math.round(y / (scale.y || 1));
            const lw = Math.max(40, Math.round(w / (scale.x || 1))); const lh = Math.max(40, Math.round(h / (scale.y || 1)));
            if (!editor.currentConfig) editor.currentConfig = editor.getDefaultConfig();
            editor.currentConfig.layout = editor.currentConfig.layout || {};
            editor.currentConfig.layout.position = { x: lx, y: ly };
            editor.currentConfig.layout.width = lw; editor.currentConfig.layout.height = lh;
            editor.currentConfig.layout.x_position = lx; editor.currentConfig.layout.y_position = ly;
            editor.setControlValue('canvas-position-x', lx); editor.setControlValue('canvas-position-y', ly);
            editor.setControlValue('canvas-width', lw); editor.setControlValue('canvas-height', lh);
            editor.markUnsaved();
            (editor.generatePreviewDebounced ? editor.generatePreviewDebounced() : editor.generatePreview());
        } catch (_) {}
        drag = null;
    };
    wrap.addEventListener('mousedown', (e) => {
        const handle = e.target.closest('.cc-block-handle');
        const rect = { x: parseInt(wrap.style.left,10)||0, y: parseInt(wrap.style.top,10)||0, w: parseInt(wrap.style.width,10)||wrap.offsetWidth, h: parseInt(wrap.style.height,10)||wrap.offsetHeight };
        if (handle) { drag = { mode: 'resize', dir: handle.dataset.dir || 'br', startX: e.clientX, startY: e.clientY, orig: rect }; } else { drag = { mode: 'move', dir: '', startX: e.clientX, startY: e.clientY, orig: rect }; }
        e.preventDefault(); document.addEventListener('mousemove', onMove); document.addEventListener('mouseup', onUp);
    });
        // Precision dialog: dblclick or contextmenu on wrap opens a geometry editor with presets AND background settings
        function openPrecisionDialog(){
                try {
                        // ensure config exists
                        if (!editor.currentConfig) editor.currentConfig = editor.getDefaultConfig();
                        const cfg = editor.currentConfig.layout = editor.currentConfig.layout || {};
                        const cur = {
                                x: (typeof cfg.x==='number'?cfg.x:cfg.position?.x) ?? 0,
                                y: (typeof cfg.y==='number'?cfg.y:cfg.position?.y) ?? 0,
                                w: (typeof cfg.width==='number'?cfg.width:cfg.w) ?? (parseInt(wrap.style.width,10)||960),
                                h: (typeof cfg.height==='number'?cfg.height:cfg.h) ?? (parseInt(wrap.style.height,10)||200)
                        };
                        
                        // Get current background settings
                        const bg = editor.currentConfig.background || {};
                        const ov = editor.currentConfig.overlay || {};
                        const bgType = bg.type || 'color';
                        const bgColor = bg.color || '#1a1a2e';
                        const borderRadius = bg.border_radius || 0;
                        const borderWidth = bg.border_width || 0;
                        const borderColor = bg.border_color || '#000000';
                        const borderStyle = bg.border_style || 'solid';
                        const gradColor1 = bg.gradient_color1 || '#1a1a2e';
                        const gradColor2 = bg.gradient_color2 || '#16213e';
                        const gradDirection = bg.gradient_direction || 180;
                        // Overlay: prefer background.overlay_* but fall back to overlay object
                        const overlayColor = bg.overlay_color || ov.color || '#000000';
                        const overlayOpacity = bg.overlay_opacity !== undefined ? bg.overlay_opacity : (ov.opacity !== undefined ? ov.opacity : 0);
                        const bgImageUrl = bg.image_url || '';
                        
                        const existing = document.getElementById('ccve-geom-precision'); if (existing) existing.remove();
                        const dlg = document.createElement('div'); dlg.id='ccve-geom-precision'; dlg.className='ccve-geom-precision-dialog';
                        dlg.innerHTML = `
                            <div class="ccve-gp-inner" style="max-height: 80vh; overflow-y: auto;">
                                <h3 style="position: sticky; top: -16px; background: #1f2937; margin: -16px -16px 12px; padding: 12px 16px; z-index: 1;">📐 Block Settings</h3>
                                
                                <div style="font-weight: 600; margin-bottom: 8px; color: #94a3b8;">Geometry</div>
                                <div style="display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 8px; margin-bottom: 8px;">
                                    <label style="margin:0;">X <input type="number" id="ccve-gp-x" value="${cur.x}"></label>
                                    <label style="margin:0;">Y <input type="number" id="ccve-gp-y" value="${cur.y}"></label>
                                    <label style="margin:0;">Width <input type="number" id="ccve-gp-w" value="${cur.w}"></label>
                                    <label style="margin:0;">Height <input type="number" id="ccve-gp-h" value="${cur.h}"></label>
                                </div>
                                <label>Preset
                                    <select id="ccve-gp-preset">
                                        <option value="">— choose preset —</option>
                                        <optgroup label="Thirds">
                                            <option value="lower-third">Lower Third (1280×240 bottom)</option>
                                            <option value="upper-third">Upper Third (1280×240 top)</option>
                                            <option value="center-third">Center Third (1280×240 middle)</option>
                                        </optgroup>
                                        <optgroup label="Halves">
                                            <option value="left-half">Left Half (640×720)</option>
                                            <option value="right-half">Right Half (640×720)</option>
                                            <option value="top-half">Top Half (1280×360)</option>
                                            <option value="bottom-half">Bottom Half (1280×360)</option>
                                        </optgroup>
                                        <optgroup label="Quarters">
                                            <option value="upper-left-quarter">Upper Left Quarter (640×360)</option>
                                            <option value="upper-right-quarter">Upper Right Quarter (640×360)</option>
                                            <option value="lower-left-quarter">Lower Left Quarter (640×360)</option>
                                            <option value="lower-right-quarter">Lower Right Quarter (640×360)</option>
                                        </optgroup>
                                        <optgroup label="Featured + Grid">
                                            <option value="featured-grid-hero">Featured Hero (1280×480 top)</option>
                                            <option value="featured-grid-item-1">Grid Item 1 (320×240 bottom-left)</option>
                                            <option value="featured-grid-item-2">Grid Item 2 (320×240)</option>
                                            <option value="featured-grid-item-3">Grid Item 3 (320×240)</option>
                                            <option value="featured-grid-item-4">Grid Item 4 (320×240 bottom-right)</option>
                                        </optgroup>
                                        <optgroup label="Full Screen">
                                            <option value="full-screen">Full Screen (1280×720)</option>
                                        </optgroup>
                                    </select>
                                </label>
                                
                                <hr style="margin: 16px 0; border: none; border-top: 1px solid #334155;" />
                                <div style="font-weight: 600; margin-bottom: 8px; color: #94a3b8;">🎨 Background</div>
                                <label>Type <select id="ccve-gp-bg-type">
                                    <option value="color" ${bgType==='color'?'selected':''}>Solid Color</option>
                                    <option value="gradient" ${bgType==='gradient'?'selected':''}>Gradient</option>
                                    <option value="image" ${bgType==='image'?'selected':''}>Image</option>
                                </select></label>
                                
                                <div id="ccve-gp-bg-color-section" style="display: ${bgType==='color'?'block':'none'};">
                                    <label>Background Color <input type="color" id="ccve-gp-bg-color" value="${bgColor}" /></label>
                                </div>
                                
                                <div id="ccve-gp-bg-gradient-section" style="display: ${bgType==='gradient'?'block':'none'};">
                                    <div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px;">
                                        <label style="margin:0;">Color 1 <input type="color" id="ccve-gp-bg-grad1" value="${gradColor1}" /></label>
                                        <label style="margin:0;">Color 2 <input type="color" id="ccve-gp-bg-grad2" value="${gradColor2}" /></label>
                                        <label style="margin:0;">Dir (°) <input type="number" id="ccve-gp-bg-grad-dir" value="${gradDirection}" min="0" max="360" /></label>
                                    </div>
                                </div>
                                
                                <div id="ccve-gp-bg-image-section" style="display: ${bgType==='image'?'block':'none'};">
                                    <label>Image URL <input type="text" id="ccve-gp-bg-image-url" value="${bgImageUrl}" style="width: 100%;" /></label>
                                    <button type="button" id="ccve-gp-bg-select-image" style="margin-top: 4px; padding: 6px 12px; background: #374151; border: 1px solid #4b5563; border-radius: 4px; cursor: pointer; color: #fff;">📁 Media Library</button>
                                </div>
                                
                                <hr style="margin: 16px 0; border: none; border-top: 1px solid #334155;" />
                                <div style="font-weight: 600; margin-bottom: 8px; color: #94a3b8;">Overlay</div>
                                <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 8px;">
                                    <label style="margin:0;">Color <input type="color" id="ccve-gp-overlay-color" value="${overlayColor}" /></label>
                                    <label style="margin:0;">Opacity <input type="number" id="ccve-gp-overlay-opacity" value="${overlayOpacity}" min="0" max="1" step="0.05" /></label>
                                </div>
                                
                                <hr style="margin: 16px 0; border: none; border-top: 1px solid #334155;" />
                                <div style="font-weight: 600; margin-bottom: 8px; color: #94a3b8;">Border</div>
                                <div style="display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 8px;">
                                    <label style="margin:0;">Width <input type="number" id="ccve-gp-border-width" value="${borderWidth}" min="0" max="20" /></label>
                                    <label style="margin:0;">Color <input type="color" id="ccve-gp-border-color" value="${borderColor}" /></label>
                                    <label style="margin:0;">Style <select id="ccve-gp-border-style">
                                        <option value="solid" ${borderStyle==='solid'?'selected':''}>Solid</option>
                                        <option value="dashed" ${borderStyle==='dashed'?'selected':''}>Dashed</option>
                                        <option value="dotted" ${borderStyle==='dotted'?'selected':''}>Dotted</option>
                                    </select></label>
                                    <label style="margin:0;">Radius <input type="number" id="ccve-gp-border-radius" value="${borderRadius}" min="0" max="100" /></label>
                                </div>
                                
                                <div class="ccve-gp-actions" style="position: sticky; bottom: -16px; background: #1f2937; margin: 16px -16px -16px; padding: 12px 16px; border-top: 1px solid #334155;">
                                    <button type="button" id="ccve-gp-apply">Apply</button>
                                    <button type="button" id="ccve-gp-cancel">Cancel</button>
                                </div>
                            </div>`;
                        document.body.appendChild(dlg);
                        
                        // Background type change handler
                        const bgTypeSelect = dlg.querySelector('#ccve-gp-bg-type');
                        bgTypeSelect?.addEventListener('change', () => {
                            const t = bgTypeSelect.value;
                            dlg.querySelector('#ccve-gp-bg-color-section').style.display = t==='color'?'block':'none';
                            dlg.querySelector('#ccve-gp-bg-gradient-section').style.display = t==='gradient'?'block':'none';
                            dlg.querySelector('#ccve-gp-bg-image-section').style.display = t==='image'?'block':'none';
                        });
                        
                        // Media library button
                        const selectImageBtn = dlg.querySelector('#ccve-gp-bg-select-image');
                        selectImageBtn?.addEventListener('click', () => {
                            if(typeof wp !== 'undefined' && wp.media) {
                                const frame = wp.media({ title: 'Select Background Image', multiple: false });
                                frame.on('select', () => {
                                    const att = frame.state().get('selection').first().toJSON();
                                    const urlInput = dlg.querySelector('#ccve-gp-bg-image-url');
                                    if(urlInput) urlInput.value = att.url || '';
                                });
                                frame.open();
                            }
                        });
                        
                        const W = 1280, H = 720; // logical canvas
                        const presetSel = dlg.querySelector('#ccve-gp-preset');
                        presetSel.addEventListener('change',()=>{
                                const v = presetSel.value; 
                                const xEl=dlg.querySelector('#ccve-gp-x'); 
                                const yEl=dlg.querySelector('#ccve-gp-y'); 
                                const wEl=dlg.querySelector('#ccve-gp-w'); 
                                const hEl=dlg.querySelector('#ccve-gp-h');
                                // Preset geometry map (1280×720 canvas)
                                const presets = {
                                        'lower-third': { x: 0, y: H-240, w: 1280, h: 240 },
                                        'upper-third': { x: 0, y: 0, w: 1280, h: 240 },
                                        'center-third': { x: 0, y: Math.floor((H-240)/2), w: 1280, h: 240 },
                                        'left-half': { x: 0, y: 0, w: 640, h: 720 },
                                        'right-half': { x: 640, y: 0, w: 640, h: 720 },
                                        'top-half': { x: 0, y: 0, w: 1280, h: 360 },
                                        'bottom-half': { x: 0, y: H-360, w: 1280, h: 360 },
                                        'upper-left-quarter': { x: 0, y: 0, w: 640, h: 360 },
                                        'upper-right-quarter': { x: 640, y: 0, w: 640, h: 360 },
                                        'lower-left-quarter': { x: 0, y: 360, w: 640, h: 360 },
                                        'lower-right-quarter': { x: 640, y: 360, w: 640, h: 360 },
                                        // Featured + Grid (hero 1280×480 + 4 grid items 320×240 below)
                                        'featured-grid-hero': { x: 0, y: 0, w: 1280, h: 480 },
                                        'featured-grid-item-1': { x: 0, y: 480, w: 320, h: 240 },
                                        'featured-grid-item-2': { x: 320, y: 480, w: 320, h: 240 },
                                        'featured-grid-item-3': { x: 640, y: 480, w: 320, h: 240 },
                                        'featured-grid-item-4': { x: 960, y: 480, w: 320, h: 240 },
                                        'full-screen': { x: 0, y: 0, w: 1280, h: 720 }
                                };
                                const p = presets[v];
                                if (p) {
                                        xEl.value = String(p.x);
                                        yEl.value = String(p.y);
                                        wEl.value = String(p.w);
                                        hEl.value = String(p.h);
                                }
                        });
                        const close=()=>{ try { dlg.remove(); } catch(_){} };
                        dlg.querySelector('#ccve-gp-cancel').addEventListener('click', close);
                        dlg.querySelector('#ccve-gp-apply').addEventListener('click', ()=>{
                                try {
                                        // Apply geometry
                                        const nx = Math.max(0, parseInt(dlg.querySelector('#ccve-gp-x').value,10)||0);
                                        const ny = Math.max(0, parseInt(dlg.querySelector('#ccve-gp-y').value,10)||0);
                                        const nw = Math.max(40, parseInt(dlg.querySelector('#ccve-gp-w').value,10)||960);
                                        const nh = Math.max(40, parseInt(dlg.querySelector('#ccve-gp-h').value,10)||200);
                                        editor.currentConfig.layout.position = { x: nx, y: ny };
                                        editor.currentConfig.layout.width = nw; editor.currentConfig.layout.height = nh;
                                        editor.setControlValue && editor.setControlValue('canvas-position-x', nx);
                                        editor.setControlValue && editor.setControlValue('canvas-position-y', ny);
                                        editor.setControlValue && editor.setControlValue('canvas-width', nw);
                                        editor.setControlValue && editor.setControlValue('canvas-height', nh);
                                        
                                        // Apply background settings
                                        if(!editor.currentConfig.background) editor.currentConfig.background = {};
                                        const newBg = editor.currentConfig.background;
                                        newBg.type = dlg.querySelector('#ccve-gp-bg-type')?.value || 'color';
                                        newBg.color = dlg.querySelector('#ccve-gp-bg-color')?.value || '#1a1a2e';
                                        newBg.gradient_color1 = dlg.querySelector('#ccve-gp-bg-grad1')?.value || '#1a1a2e';
                                        newBg.gradient_color2 = dlg.querySelector('#ccve-gp-bg-grad2')?.value || '#16213e';
                                        newBg.gradient_direction = parseInt(dlg.querySelector('#ccve-gp-bg-grad-dir')?.value || 180);
                                        newBg.image_url = dlg.querySelector('#ccve-gp-bg-image-url')?.value || '';
                                        newBg.overlay_color = dlg.querySelector('#ccve-gp-overlay-color')?.value || '#000000';
                                        newBg.overlay_opacity = parseFloat(dlg.querySelector('#ccve-gp-overlay-opacity')?.value || 0);
                                        newBg.border_width = parseInt(dlg.querySelector('#ccve-gp-border-width')?.value || 0);
                                        newBg.border_color = dlg.querySelector('#ccve-gp-border-color')?.value || '#000000';
                                        newBg.border_style = dlg.querySelector('#ccve-gp-border-style')?.value || 'solid';
                                        newBg.border_radius = parseInt(dlg.querySelector('#ccve-gp-border-radius')?.value || 0);
                                        
                                        // SYNC overlay settings to the primary overlay object
                                        // This ensures save/load and Scenes rendering sees correct values
                                        if(!editor.currentConfig.overlay) editor.currentConfig.overlay = {};
                                        editor.currentConfig.overlay.color = newBg.overlay_color;
                                        editor.currentConfig.overlay.opacity = newBg.overlay_opacity;
                                        editor.currentConfig.overlay.enabled = newBg.overlay_opacity > 0;
                                        
                                        // SYNC background.layers array to include overlay layer if opacity > 0
                                        if(!Array.isArray(newBg.layers)) newBg.layers = [];
                                        const existingOverlayIdx = newBg.layers.findIndex(l => l && l.kind === 'overlay');
                                        if(newBg.overlay_opacity > 0) {
                                            if(existingOverlayIdx === -1) {
                                                // Add overlay layer at beginning (topmost)
                                                newBg.layers.unshift({ kind: 'overlay', enabled: true });
                                            } else {
                                                newBg.layers[existingOverlayIdx].enabled = true;
                                            }
                                        } else {
                                            if(existingOverlayIdx !== -1) {
                                                newBg.layers[existingOverlayIdx].enabled = false;
                                            }
                                        }
                                        
                                        // Apply gradient colors array for renderer compatibility
                                        if(newBg.type === 'gradient') {
                                            newBg.gradient_colors = [newBg.gradient_color1, newBg.gradient_color2];
                                        }
                                        
                                        // Apply background styling to the stage
                                        try {
                                            const bgLayerEl = document.getElementById('canvas-background-layer');
                                            const overlayEl = document.getElementById('canvas-overlay-layer');
                                            const stageElement = document.getElementById('block-stage');
                                            
                                            if(bgLayerEl) {
                                                if(newBg.type === 'color') {
                                                    bgLayerEl.style.background = newBg.color;
                                                } else if(newBg.type === 'gradient') {
                                                    bgLayerEl.style.background = `linear-gradient(${newBg.gradient_direction}deg, ${newBg.gradient_color1}, ${newBg.gradient_color2})`;
                                                } else if(newBg.type === 'image' && newBg.image_url) {
                                                    bgLayerEl.style.background = `url(${newBg.image_url}) center/cover no-repeat`;
                                                }
                                                bgLayerEl.style.borderRadius = `${newBg.border_radius}px`;
                                            }
                                            
                                            if(overlayEl && newBg.overlay_opacity > 0) {
                                                overlayEl.style.background = newBg.overlay_color;
                                                overlayEl.style.opacity = newBg.overlay_opacity;
                                            } else if(overlayEl) {
                                                overlayEl.style.background = 'transparent';
                                                overlayEl.style.opacity = 0;
                                            }
                                            
                                            if(stageElement) {
                                                stageElement.style.borderWidth = `${newBg.border_width}px`;
                                                stageElement.style.borderColor = newBg.border_color;
                                                stageElement.style.borderStyle = newBg.border_style;
                                                stageElement.style.borderRadius = `${newBg.border_radius}px`;
                                            }
                                        } catch(_) {}
                                        
                                        editor.markUnsaved && editor.markUnsaved();
                                        updateBlockEditorRectFromConfig(editor);
                                        editor.triggerPreview && editor.triggerPreview(false);
                                } catch(_) {}
                                close();
                        });
                } catch(_) {}
        }
        wrap.addEventListener('dblclick', (e)=>{
                // Only when double-clicking the empty wrap overlay (not on token/legacy layers)
                const hitToken = e.target.closest?.('[data-layer-id]');
                const hitLegacy = e.target.closest?.('.ccve-legacy-layer');
                if (hitToken || hitLegacy) return;
                openPrecisionDialog();
        });
        wrap.addEventListener('contextmenu', (e)=>{
                const hitToken = e.target.closest?.('[data-layer-id]');
                const hitLegacy = e.target.closest?.('.ccve-legacy-layer');
                if (hitToken || hitLegacy) return; e.preventDefault();
                openPrecisionDialog();
        });
    const onWindowResize = () => { try { updateBlockEditorRectFromConfig(editor); } catch (_) {} };
    window.addEventListener('resize', onWindowResize);
    const obs = new MutationObserver(() => { if (!document.body.contains(wrap)) { window.removeEventListener('resize', onWindowResize); obs.disconnect(); } });
    obs.observe(document.body, { childList: true, subtree: true });
}

// Inject precision dialog CSS once
(()=>{ if(document.getElementById('ccve-geom-precision-style')) return; const s=document.createElement('style'); s.id='ccve-geom-precision-style'; s.textContent=`
  .ccve-geom-precision-dialog { position:fixed; top:50%; left:50%; transform:translate(-50%,-50%); background:#1f2937; color:#fff; padding:16px; border:1px solid #334155; border-radius:8px; z-index:4002; width:340px; font:13px system-ui,sans-serif; }
  .ccve-geom-precision-dialog h3 { margin:0 0 10px; font-size:14px; }
  .ccve-geom-precision-dialog label { display:flex; flex-direction:column; gap:4px; margin:6px 0; font-weight:600; }
  .ccve-geom-precision-dialog input, .ccve-geom-precision-dialog select { width:100%; background:#0b1220; border:1px solid #334155; color:#fff; padding:6px 8px; border-radius:4px; box-sizing:border-box; }
  .ccve-geom-precision-dialog .ccve-gp-actions { display:flex; justify-content:flex-end; gap:8px; margin-top:12px; }
  .ccve-geom-precision-dialog button { background:#2563eb; border:none; padding:6px 12px; color:#fff; cursor:pointer; border-radius:4px; font-weight:600; }
  .ccve-geom-precision-dialog button#ccve-gp-cancel { background:#64748b; }
`; document.head.appendChild(s); })();

export const blockStageGeometryApi = { updateBlockEditorRectFromConfig, bindBlockEditorInteractions };
