// ==========================================
// drag-engine.js: MOVE, RESIZE, & ROTATE MATH
// ==========================================

/**
 * Snap a dragged overlay to siblings / page edges.
 * Supports:
 *  - same-edge align (left↔left, right↔right, top↔top, bottom↔bottom)
 *  - abut (left↔right, right↔left, top↔bottom, bottom↔top) — critical for snip+extend
 *  - center to parent / sibling
 * Coordinates are page-container CSS px (pre-zoom). SNAP is ~10 screen px.
 */
window.calculateSnapping = function(el, parent, newLeft, newTop, opts) {
    const options = opts && typeof opts === "object" ? opts : {};
    // Slightly larger magnet for image snippets (table lines are unforgiving)
    const isImg = el && el.classList && el.classList.contains("overlayImg");
    const screenSnap = options.screenSnap != null ? options.screenSnap : (isImg ? 12 : 10);
    const zoom = window.currentZoom || 1;
    const SNAP = Math.max(1.5, screenSnap / zoom);

    const parentRect = parent.getBoundingClientRect();
    let res = { x: newLeft, y: newTop };

    const elW = parseFloat(el.style.width) || el.offsetWidth || 0;
    const elH = parseFloat(el.style.height) || el.offsetHeight || 0;

    // Collect candidate X/Y snap targets with guide positions (page coords)
    const xTargets = []; // { value: pageX for res.x, guide: pageX for line }
    const yTargets = [];

    // Page edges + center
    xTargets.push({ value: 0, guide: 0 });
    yTargets.push({ value: 0, guide: 0 });
    if (elW > 0) {
        xTargets.push({ value: parent.offsetWidth - elW, guide: parent.offsetWidth });
        xTargets.push({ value: (parent.offsetWidth - elW) / 2, guide: parent.offsetWidth / 2 });
    }
    if (elH > 0) {
        yTargets.push({ value: parent.offsetHeight - elH, guide: parent.offsetHeight });
        yTargets.push({ value: (parent.offsetHeight - elH) / 2, guide: parent.offsetHeight / 2 });
    }

    parent.querySelectorAll(".overlayImg, .textOverlay, .shapeOverlay, .formFieldOverlay").forEach((sibling) => {
        if (sibling === el) return;
        if (sibling.classList.contains("stencil-box") || sibling.classList.contains("selection-marquee")) return;

        const sLeft = parseFloat(sibling.style.left);
        const sTop = parseFloat(sibling.style.top);
        if (!Number.isFinite(sLeft) || !Number.isFinite(sTop)) return;
        const sW = parseFloat(sibling.style.width) || sibling.offsetWidth || 0;
        const sH = parseFloat(sibling.style.height) || sibling.offsetHeight || 0;
        const sRight = sLeft + sW;
        const sBottom = sTop + sH;

        // Horizontal: align / abut → resulting res.x
        xTargets.push({ value: sLeft, guide: sLeft });                         // left = left
        xTargets.push({ value: sRight - elW, guide: sRight });                  // right = right
        xTargets.push({ value: sRight, guide: sRight });                        // left = right (abut right of sib)
        xTargets.push({ value: sLeft - elW, guide: sLeft });                    // right = left (abut left of sib)
        xTargets.push({ value: sLeft + sW / 2 - elW / 2, guide: sLeft + sW / 2 }); // centers

        // Vertical: align / abut → resulting res.y
        yTargets.push({ value: sTop, guide: sTop });                            // top = top
        yTargets.push({ value: sBottom - elH, guide: sBottom });                // bottom = bottom
        yTargets.push({ value: sBottom, guide: sBottom });                      // top = bottom (extend below)
        yTargets.push({ value: sTop - elH, guide: sTop });                      // bottom = top (stack above)
        yTargets.push({ value: sTop + sH / 2 - elH / 2, guide: sTop + sH / 2 }); // centers
    });

    let bestX = null;
    let bestXDist = SNAP;
    for (let i = 0; i < xTargets.length; i++) {
        const t = xTargets[i];
        if (!Number.isFinite(t.value)) continue;
        const d = Math.abs(res.x - t.value);
        if (d < bestXDist) {
            bestXDist = d;
            bestX = t;
        }
    }
    if (bestX) {
        res.x = bestX.value;
        window.showVerticalGuide(parentRect.left + bestX.guide * zoom);
    }

    let bestY = null;
    let bestYDist = SNAP;
    for (let i = 0; i < yTargets.length; i++) {
        const t = yTargets[i];
        if (!Number.isFinite(t.value)) continue;
        const d = Math.abs(res.y - t.value);
        if (d < bestYDist) {
            bestYDist = d;
            bestY = t;
        }
    }
    if (bestY) {
        res.y = bestY.value;
        window.showHorizontalGuide(parentRect.top + bestY.guide * zoom);
    }

    // Pixel-lock: whole page CSS px so table lines don't land on half-pixels
    res.x = Math.round(res.x);
    res.y = Math.round(res.y);
    return res;
};

/** Round overlay geometry to whole CSS pixels (anti-blur for snips). */
window.pixelSnapOverlayBox = function(el) {
    if (!el || !el.style) return;
    const left = parseFloat(el.style.left);
    const top = parseFloat(el.style.top);
    const w = parseFloat(el.style.width);
    const h = parseFloat(el.style.height);
    if (Number.isFinite(left)) el.style.left = Math.round(left) + "px";
    if (Number.isFinite(top)) el.style.top = Math.round(top) + "px";
    if (Number.isFinite(w) && w > 0) el.style.width = Math.round(w) + "px";
    if (Number.isFinite(h) && h > 0) el.style.height = Math.round(h) + "px";
};

// --- The Master Drag Engine ---
window.makeDraggable = function(el, resizeHandle = null, dragHandle = null) {
    el.addEventListener("mousedown", e => {
        if (APP.isXRayMode) return;
        if (APP.pendingSignatureSrc || APP.pendingImageSrc) return;
        
        const isFormEl = el.classList.contains("formFieldOverlay");
        const isStencil = el.classList.contains("stencil-box");
        // Workspace isolation: never drag the inactive layer.
        // Stencil/group boxes are allowed in both modes (they only wrap the active layer's selection).
        if (!isStencil) {
            if (APP.workspaceMode === "form" && !isFormEl) return;
            if (APP.workspaceMode !== "form" && isFormEl) return;
        }

        const isClickingHandle = e.target === resizeHandle || e.target === dragHandle;
        const isSmartText = APP.currentMode === "text" && el.classList.contains("textOverlay");
        const isSmartShape = (APP.currentMode === "rect" || APP.currentMode === "circle" || APP.currentMode === "line" || APP.currentMode === "table") && el.classList.contains("shapeOverlay");
        const isSmartForm = window.isFormFieldMode && window.isFormFieldMode(APP.currentMode) && isFormEl;
        const isSmartRedact = APP.currentMode === "redact" && el.dataset && el.dataset.redact === "1";
        
        if (!isClickingHandle && APP.currentMode !== "select" && APP.currentMode !== "edit" && !isSmartText && !isSmartShape && !isSmartForm && !isSmartRedact) return;

        const isGroupDrag = APP.multiSelectedItems.has(el) || el.classList.contains("stencil-box");
        
        if (!isGroupDrag && APP.multiSelectedItems.size > 0) {
            window.clearMultiSelection();
        }
        
        if (!isGroupDrag) window.setActiveOverlay(el);
        
        if (e.target.closest(".textContent")) return;
        if (isClickingHandle) {
            if (document.activeElement && document.activeElement.isContentEditable) {
                document.activeElement.blur();
            }
        }

        let dragging = false;
        let resizing = false;
		let rotating = false;
        let targetEl = el;
        let lockedAxis = null;
        
        // ✨ THE FIX: Track the initial parent so History Undo knows where to put it back!
        let initialParent = targetEl.parentElement; 
		
		let startCenterX = 0, startCenterY = 0, startAngle = 0, startRotation = 0;
        
        let groupInitialState = [];
		let stencilInitialState = null;
        if (isGroupDrag) {
            if (window.hideGroupToolbar) window.hideGroupToolbar(); 
            groupInitialState = Array.from(APP.multiSelectedItems).map(item => ({
                el: item,
                startParent: item.parentElement, // ✨ Track group parent
                startLeft: parseFloat(item.style.left) || 0,
                startTop: parseFloat(item.style.top) || 0
            }));

            if (window.activeStencil) {
                stencilInitialState = {
                    el: window.activeStencil,
                    startParent: window.activeStencil.parentElement, 
                    startLeft: parseFloat(window.activeStencil.style.left) || 0,
                    startTop: parseFloat(window.activeStencil.style.top) || 0
                };
            }
        }

        if (e.altKey) {
            // Shared rebind + CREATE_NODE (same path as Ctrl+V paste)
            const clone = (typeof window.cloneOverlayElement === "function")
                ? window.cloneOverlayElement(el)
                : el.cloneNode(true);
            if (!clone) { /* fall through without clone */ }
            else {
                el.parentElement.appendChild(clone);
                window.setActiveOverlay(clone);
                const targetContainer = el.parentElement;
                if (window.CcsProcessor) {
                    window.CcsProcessor.commit(
                        window.CcsProcessor.build.createNode(clone, "Clone Item")
                    );
                }
                targetEl = clone;
                initialParent = targetContainer;
            }
        }
		if (e.target.classList.contains("rotateHandle")) {
            rotating = true;
            
            // 1. Save the current rotation
            const currentTransform = targetEl.style.transform || "";
            const match = currentTransform.match(/rotate\(([\d.-]+)deg\)/);
            startRotation = match ? parseFloat(match[1]) : 0;
            
            // 2. Temporarily un-rotate the element to get its pure physical boundaries
            targetEl.style.transform = "none";
            const rawRect = targetEl.getBoundingClientRect();
            
            // 3. Read exactly where the CSS transform-origin is set for this specific shape
            const computedStyle = window.getComputedStyle(targetEl);
            let originX = rawRect.width / 2;
            let originY = rawRect.height / 2;
            
            if (computedStyle.transformOrigin) {
                const origins = computedStyle.transformOrigin.split(" ");
                const pxX = parseFloat(origins[0]);
                const pxY = parseFloat(origins[1]);
                
                // ✨ THE FIX: We must check for NaN because 0px is a valid coordinate!
                // The || operator treats 0 as false, which broke lines that pivot on the left edge.
                if (!isNaN(pxX)) originX = pxX;
                if (!isNaN(pxY)) originY = pxY;
            }
            
            // 4. Because transform-origin is the ONE point that NEVER moves during rotation, 
            // we now have our absolute mathematical pivot point!
            startCenterX = rawRect.left + originX;
            startCenterY = rawRect.top + originY;
            
            // 5. Put the rotation back instantly (the user won't even see a flicker)
            targetEl.style.transform = currentTransform;
            
            // Calculate the initial angle of the mouse relative to this perfect center
            startAngle = Math.atan2(e.clientY - startCenterY, e.clientX - startCenterX) * (180 / Math.PI);
        }
        else if (resizeHandle && e.target === resizeHandle && !e.altKey) {
            resizing = true;
        } 
        else if (!dragHandle || e.target === dragHandle || targetEl.contains(e.target)) {
            dragging = true;
        }

        let startGlobalX = e.clientX;
        let startGlobalY = e.clientY;
        
        let startScrollTop = APP.DOM.viewer.scrollTop || 0;
        let startScrollLeft = APP.DOM.viewer.scrollLeft || 0;
        
        let startLeft = parseFloat(targetEl.style.left) || 0;
        let startTop = parseFloat(targetEl.style.top) || 0;
        let startW = parseFloat(targetEl.style.width) || targetEl.offsetWidth;
        let startH = parseFloat(targetEl.style.height) || targetEl.offsetHeight;
        
        if (dragging || resizing || rotating) { // ✨ Added rotating
            e.preventDefault();
            e.stopPropagation();
        }
        
        // We now also track transform for undo/redo
        let initialStyles = { left: targetEl.style.left, top: targetEl.style.top, width: targetEl.style.width, height: targetEl.style.height, transform: targetEl.style.transform };
        
        const onMouseMove = (moveEvent) => {
            if (!dragging && !resizing && !rotating) return;
            targetEl.classList.add("is-dragging");
            window.hideGuides();
            
            const scrollDx = (APP.DOM.viewer.scrollLeft || 0) - startScrollLeft;
            const scrollDy = (APP.DOM.viewer.scrollTop || 0) - startScrollTop;
            
            let dx = (moveEvent.clientX - startGlobalX + scrollDx) / window.currentZoom;
            let dy = (moveEvent.clientY - startGlobalY + scrollDy) / window.currentZoom;
            
            // ✨ THE ROTATION ENGINE
            if (rotating) {
                // Calculate current mouse angle relative to center
                const currentMouseAngle = Math.atan2(moveEvent.clientY - startCenterY, moveEvent.clientX - startCenterX) * (180 / Math.PI);
                let finalAngle = startRotation + (currentMouseAngle - startAngle);
                
                // Bonus: Hold Shift while rotating to snap to 15-degree increments!
                if (moveEvent.shiftKey) {
                    finalAngle = Math.round(finalAngle / 15) * 15;
                }
                
                targetEl.style.transform = `rotate(${finalAngle}deg)`;
                if (window.syncOverlayChrome) window.syncOverlayChrome(targetEl);
            }
            
            if (dragging) {
                // ✨ THE MAGIC: Cross-Page Hover Detection & Reparenting
                let hoveredPage = null;
                const pages = document.querySelectorAll(".pageContainer");
                pages.forEach(page => {
                    const rect = page.getBoundingClientRect();
                    if (moveEvent.clientX >= rect.left && moveEvent.clientX <= rect.right &&
                        moveEvent.clientY >= rect.top && moveEvent.clientY <= rect.bottom) {
                        hoveredPage = page;
                    }
                });

                if (hoveredPage) {
                    const itemsToCheck = isGroupDrag ? groupInitialState.map(g => g.el) : [targetEl];
                    itemsToCheck.forEach(el => {
                        const currentParent = el.parentElement;
                        if (currentParent && currentParent !== hoveredPage && currentParent.classList.contains("pageContainer")) {
                            
                            // Calculate DOM physical offset so we can adjust math transparently
                            const oldRect = currentParent.getBoundingClientRect();
                            const newRect = hoveredPage.getBoundingClientRect();
                            
                            const shiftX = (oldRect.left - newRect.left) / window.currentZoom;
                            const shiftY = (oldRect.top - newRect.top) / window.currentZoom;

                            // Adjust the mathematical starting origin so the item doesn't jump
                            if (isGroupDrag) {
                                const stateObj = groupInitialState.find(g => g.el === el);
                                if (stateObj) {
                                    stateObj.startLeft += shiftX;
                                    stateObj.startTop += shiftY;
                                } else if (stencilInitialState && stencilInitialState.el === el) {
                                    // ✨ Shift the stencil origin so it doesn't jump
                                    stencilInitialState.startLeft += shiftX;
                                    stencilInitialState.startTop += shiftY;
                                }
                            } else {
                                startLeft += shiftX;
                                startTop += shiftY;
                            }
                            
                            // Move the physical DOM node instantly
                            hoveredPage.appendChild(el);
                        }
                    });
                }

                if (isGroupDrag) {
                    // ✨ PREVENT GROUPS FROM DRAGGING OFF THE TOP/LEFT
                    // Find the bounding box of the group so we don't distort it when clamping
                    let minLeft = Infinity;
                    let minTop = Infinity;
                    groupInitialState.forEach(item => {
                        if (item.startLeft < minLeft) minLeft = item.startLeft;
                        if (item.startTop < minTop) minTop = item.startTop;
                    });
                    
                    // Clamp the master movement deltas if they try to push past 0!
                    if (minLeft + dx < 0) dx = -minLeft;
                    if (minTop + dy < 0) dy = -minTop;

                    groupInitialState.forEach(item => {
                        item.el.style.left = (item.startLeft + dx) + "px";
                        item.el.style.top = (item.startTop + dy) + "px";
                    });
					if (stencilInitialState) {
                        stencilInitialState.el.style.left = (stencilInitialState.startLeft + dx) + "px";
                        stencilInitialState.el.style.top = (stencilInitialState.startTop + dy) + "px";
                    }
                } else {
                    let newLeft = startLeft + dx;
                    let newTop = startTop + dy;
                    if (moveEvent.shiftKey) {
                        if (!lockedAxis && (Math.abs(dx) > 3 || Math.abs(dy) > 3)) {
                            lockedAxis = Math.abs(dx) > Math.abs(dy) ? 'x' : 'y';
                        }
                        if (lockedAxis === 'x') newTop = startTop;
                        else if (lockedAxis === 'y') newLeft = startLeft;
                        else { newLeft = startLeft; newTop = startTop; }
                    } else {
                        lockedAxis = null;
                    }
                    const parent = targetEl.closest(".pageContainer");
                    if (!parent) return;
                    // Snap by default (edge-align + abut for snip/extend).
                    // Hold Ctrl/Meta while dragging for free placement (no magnet).
                    // Note: Alt is reserved for clone-on-drag — never use it here.
                    const freeMove = moveEvent.ctrlKey || moveEvent.metaKey;
                    if (!freeMove) {
                        const snapped = window.calculateSnapping(targetEl, parent, newLeft, newTop);
                        newLeft = snapped.x;
                        newTop = snapped.y;
                    } else {
                        // Free move still pixel-locks so snips don't go half-pixel blurry
                        newLeft = Math.round(newLeft);
                        newTop = Math.round(newTop);
                    }
                    
		    // ✨ PREVENT SINGLE ITEMS FROM DRAGGING OFF-SCREEN
                    // 1. Hard lock the Top and Left edges at exactly 0
                    newLeft = Math.max(0, newLeft);
                    newTop = Math.max(0, newTop);
                    
                    // 2. Shrink the bounding box to 10px so the handle can slide completely flush 
                    // against the right and bottom edges of the canvas without falling off!
                    const maxLeft = parent.offsetWidth - 5;
                    const maxTop = parent.offsetHeight - 5;
                    newLeft = Math.min(newLeft, maxLeft);
                    newTop = Math.min(newTop, maxTop);

                    targetEl.style.left = newLeft + "px";
                    targetEl.style.top = newTop + "px";
		}

	    }
            if (resizing) {
                let newW = startW + dx;
                let newH = startH + dy;

                // ✨ ASPECT RATIO LOCK
                if (moveEvent.shiftKey && startH !== 0) {
                    const ratio = startW / startH;
                    // Force the height to mathematically align with the width change
                    newH = newW / ratio; 
                }

                targetEl.style.minWidth = "0px";
                targetEl.style.minHeight = "0px";

                // Form fields (esp. radios/checks): allow very small widgets
                if (targetEl.classList.contains("formFieldOverlay")) {
                    const ft = targetEl.dataset.fieldType;
                    if (ft === "checkbox" || ft === "radio") {
                        const side = Math.max(1, Math.max(newW, newH));
                        targetEl.style.width = side + "px";
                        targetEl.style.height = side + "px";
                    } else {
                        targetEl.style.width = Math.max(1, newW) + "px";
                        targetEl.style.height = Math.max(1, newH) + "px";
                    }
                } else {
                    // Lines double as quick redact bars: free width + height (thickness)
                    const isLine = targetEl.classList.contains("shape-line");
                    const minW = isLine ? 4 : 20;
                    targetEl.style.width = Math.max(minW, newW) + "px";

                    if (targetEl.classList.contains("textOverlay")) {
                        const content = targetEl.querySelector(".textContent");
                        if (content) {
                            content.style.whiteSpace = "normal";
                            content.style.overflowWrap = "break-word";
                        }
                        targetEl.style.height = "auto"; // Text usually manages its own height
                    } else if (isLine) {
                        // Allow vertical thicken for redaction cover; keep at least 1px stroke
                        const h = Math.max(1, newH);
                        targetEl.style.height = h + "px";
                        // Keep thickness spinner in the shape toolbar in sync
                        const thickInput = targetEl.querySelector(".textControls input[type='number']");
                        if (thickInput) thickInput.value = String(Math.round(h));
                    } else {
                        targetEl.style.height = Math.max(5, newH) + "px";
                    }
                }
            }
            
            if (targetEl) window.adjustToolbarPosition(targetEl);
            
            const rect = APP.DOM.viewer.getBoundingClientRect();
            if (moveEvent.clientY < rect.top + APP.SCROLL_ZONE) window.startAutoScroll(-1);
            else if (moveEvent.clientY > rect.bottom - APP.SCROLL_ZONE) window.startAutoScroll(1);
            else window.stopAutoScroll();
        };
        
        const onMouseUp = () => {
            if (dragging && isGroupDrag) {
                const hasMoved = groupInitialState.some(item => 
                    parseFloat(item.el.style.left) !== item.startLeft || 
                    parseFloat(item.el.style.top) !== item.startTop ||
                    item.el.parentElement !== item.startParent
                );
                
                if (hasMoved) {
                    const before = groupInitialState.map(i => ({el: i.el, parent: i.startParent, left: i.startLeft + "px", top: i.startTop + "px"}));
                    const after = groupInitialState.map(i => ({el: i.el, parent: i.el.parentElement, left: i.el.style.left, top: i.el.style.top}));
                    
                    // ✨ 1. CALCULATE THE STENCIL BOUNDS BEFORE & AFTER
                    let beforeBounds = null;
                    let afterBounds = null;

                    if (stencilInitialState) {
                        const sWidth = parseFloat(stencilInitialState.el.style.width) || 0;
                        const sHeight = parseFloat(stencilInitialState.el.style.height) || 0;
                        
                        beforeBounds = {
                            left: stencilInitialState.startLeft, top: stencilInitialState.startTop,
                            width: sWidth, height: sHeight,
                            right: stencilInitialState.startLeft + sWidth, bottom: stencilInitialState.startTop + sHeight,
                            centerX: stencilInitialState.startLeft + (sWidth / 2), centerY: stencilInitialState.startTop + (sHeight / 2)
                        };

                        const currentLeft = parseFloat(stencilInitialState.el.style.left) || 0;
                        const currentTop = parseFloat(stencilInitialState.el.style.top) || 0;

                        afterBounds = {
                            left: currentLeft, top: currentTop,
                            width: sWidth, height: sHeight,
                            right: currentLeft + sWidth, bottom: currentTop + sHeight,
                            centerX: currentLeft + (sWidth / 2), centerY: currentTop + (sHeight / 2)
                        };
                    }

                    if (window.CcsProcessor) {
                        const items = groupInitialState.map((item) => ({
                            el: item.el,
                            before: {
                                left: item.startLeft + "px",
                                top: item.startTop + "px",
                                width: item.el.style.width || "",
                                height: item.el.style.height || "",
                                transform: item.el.style.transform || "",
                                parentId: window.CcsProcessor.ensureId(item.startParent, "pg")
                            },
                            after: window.CcsProcessor.snapshotTransform(item.el)
                        }));
                        window.CcsProcessor.commit(
                            window.CcsProcessor.build.transforms(items, `Move ${after.length} Items`)
                        );
                    }

                    if (window.activeStencil) {
                        const s = window.activeStencil;
                        window.activeMarqueeBounds = {
                            left: parseFloat(s.style.left), 
                            top: parseFloat(s.style.top),
                            width: parseFloat(s.style.width),
                            height: parseFloat(s.style.height),
                            right: parseFloat(s.style.left) + parseFloat(s.style.width),
                            bottom: parseFloat(s.style.top) + parseFloat(s.style.height),
                            centerX: parseFloat(s.style.left) + (parseFloat(s.style.width) / 2),
                            centerY: parseFloat(s.style.top) + (parseFloat(s.style.height) / 2)
                        };
                    }
                
                    if (window.showGroupToolbar) window.showGroupToolbar();
                }
            }
            else if (dragging || resizing || rotating) {
                const endParent = targetEl.parentElement;
                
                // ✨ Ensure transform changes trigger history pushes!
                if (targetEl.style.left !== initialStyles.left || targetEl.style.top !== initialStyles.top || targetEl.style.width !== initialStyles.width || targetEl.style.height !== initialStyles.height || targetEl.style.transform !== initialStyles.transform || initialParent !== endParent) {
                    
                    const before = { ...initialStyles };
                    const after = { left: targetEl.style.left, top: targetEl.style.top, width: targetEl.style.width, height: targetEl.style.height, transform: targetEl.style.transform };
                    
                    let actionName = "Move Overlay";
                    if (resizing) actionName = "Resize Overlay";
                    if (rotating) actionName = "Rotate Overlay";

                    if (window.CcsProcessor) {
                        const beforeSnap = Object.assign({}, before, {
                            parentId: window.CcsProcessor.ensureId(initialParent, "pg")
                        });
                        const afterSnap = Object.assign({}, after, {
                            parentId: window.CcsProcessor.ensureId(endParent, "pg")
                        });
                        window.CcsProcessor.commit(
                            window.CcsProcessor.build.transform(targetEl, beforeSnap, afterSnap, actionName)
                        );
                    }
                }
            }
            targetEl.classList.remove("is-dragging");

            // Whole-pixel geometry after move/resize (prevents 0.5px table-line gaps)
            if ((dragging || resizing) && targetEl && typeof window.pixelSnapOverlayBox === "function") {
                window.pixelSnapOverlayBox(targetEl);
            }
            if (isGroupDrag && groupInitialState.length && typeof window.pixelSnapOverlayBox === "function") {
                groupInitialState.forEach((item) => {
                    if (item.el) window.pixelSnapOverlayBox(item.el);
                });
            }
            
            if (targetEl && window.adjustToolbarPosition) window.adjustToolbarPosition(targetEl);

            // Keep AcroForm twin geometry aligned when designer shells move/resize
            if (targetEl && targetEl.classList && targetEl.classList.contains("formFieldOverlay")
                && typeof window.syncNativeWidgetGeometryFromDesigner === "function") {
                window.syncNativeWidgetGeometryFromDesigner(targetEl);
            }
            if (isGroupDrag && groupInitialState.length) {
                groupInitialState.forEach((item) => {
                    if (item.el && item.el.classList && item.el.classList.contains("formFieldOverlay")
                        && typeof window.syncNativeWidgetGeometryFromDesigner === "function") {
                        window.syncNativeWidgetGeometryFromDesigner(item.el);
                    }
                });
            }
	    
	    window.stopAutoScroll();
            window.hideGuides();
            window.removeEventListener("mousemove", onMouseMove);
            window.removeEventListener("mouseup", onMouseUp);
        };
        
        window.addEventListener("mousemove", onMouseMove);
        window.addEventListener("mouseup", onMouseUp);
    });
};
