import { noop, safeCall, safeAddListener } from "../utils/safeCall.js";
import { clamp, clamp01 } from "../features/viewer/state.js";
import { t } from "../app/i18n.js";
import { normalizeVideoFps } from "../utils/mediaFps.js";

const MAX_MINOR_TICKS = 400;
const SEEK_RANGE_MAX = 1000;
const STEP_FLASH_MS = 220;
const FPS_OVERRIDE_EPSILON = 0.001;

function chooseNiceTimeStep(seconds: any, targetTicks: any) {
    const duration = Number(seconds);
    const target = Math.max(1, Number(targetTicks) || 1);
    if (!Number.isFinite(duration) || duration <= 0) return 1;
    const raw = duration / target;
    const pow = 10 ** Math.floor(Math.log10(Math.max(raw, 0.001)));
    const normalized = raw / pow;
    const nice = normalized <= 1 ? 1 : normalized <= 2 ? 2 : normalized <= 5 ? 5 : 10;
    return Math.max(0.001, nice * pow);
}

function setAbortableTimeout(signal: any, ms: any, fn: any) {
    try {
        if (signal?.aborted) return noop;
        const id = setTimeout(
            () => {
                try {
                    if (signal?.aborted) return;
                    fn?.();
                } catch (e: any) {
                    console.debug?.(e);
                }
            },
            Math.max(0, Math.floor(Number(ms) || 0)),
        );

        const onAbort = () => {
            try {
                clearTimeout(id);
            } catch (e: any) {
                console.debug?.(e);
            }
        };
        try {
            signal?.addEventListener?.("abort", onAbort, { once: true });
        } catch (e: any) {
            console.debug?.(e);
        }

        return () => {
            try {
                clearTimeout(id);
            } catch (e: any) {
                console.debug?.(e);
            }
            try {
                signal?.removeEventListener?.("abort", onAbort);
            } catch (e: any) {
                console.debug?.(e);
            }
        };
    } catch {
        return noop;
    }
}

function pad2(n: any) {
    const v = Math.floor(Number(n) || 0);
    return v < 10 ? `0${v}` : String(v);
}

function formatTime(seconds: any) {
    const s = Number(seconds);
    if (!Number.isFinite(s) || s < 0) return "0:00";
    const total = Math.floor(s);
    const h = Math.floor(total / 3600);
    const m = Math.floor((total % 3600) / 60);
    const sec = total % 60;
    if (h > 0) return `${h}:${pad2(m)}:${pad2(sec)}`;
    return `${m}:${pad2(sec)}`;
}

function createBtn(className: any, text: any, title: any) {
    const b = document.createElement("button");
    b.type = "button";
    b.className = `mjr-video-btn ${className || ""}`.trim();
    if (title) b.title = title;
    try {
        b.setAttribute("aria-label", title || text || "Button");
    } catch (e: any) {
        console.debug?.(e);
    }
    b.textContent = text;
    return b;
}

function createIconBtn(className: any, iconClass: any, title: any, ariaLabel: any) {
    const b = document.createElement("button");
    b.type = "button";
    b.className = `mjr-video-btn ${className || ""}`.trim();
    if (title) b.title = title;
    try {
        b.setAttribute("aria-label", ariaLabel || title || "Button");
    } catch (e: any) {
        console.debug?.(e);
    }

    const icon = document.createElement("span");
    icon.className = `pi ${iconClass || ""}`.trim();
    icon.setAttribute("aria-hidden", "true");
    b.appendChild(icon);

    return { btn: b, icon };
}

function createNumberInput(className: string, { min, max, step, value, title, ariaLabel, widthPx }: Record<string, any> = {}) {
    const i = document.createElement("input");
    i.type = "number";
    i.className = `mjr-video-num ${className || ""}`.trim();
    if (title) i.title = title;
    if (ariaLabel) i.setAttribute("aria-label", ariaLabel);
    if (min != null) i.min = String(min);
    if (max != null) i.max = String(max);
    if (step != null) i.step = String(step);
    if (value != null) i.value = String(value);
    if (widthPx != null) i.style.width = `${widthPx}px`;
    return i;
}

function _resolveVideoControlsVariant(opts: any) {
    try {
        if (opts?.variant === "preview") return "preview";
        if (opts?.variant === "viewerbar") return "viewerbar";
        return "viewer";
    } catch {
        return "viewer";
    }
}

function _resolveInitialFps(opts: any) {
    try {
        const v = Number(opts?.initialFps);
        return Number.isFinite(v) && v > 0 ? v : null;
    } catch {
        return null;
    }
}

function _isSameFps(a: unknown, b: unknown) {
    const na = Number(a);
    const nb = Number(b);
    return Number.isFinite(na) && Number.isFinite(nb) && Math.abs(na - nb) <= FPS_OVERRIDE_EPSILON;
}

function _mountPreviewControls(video: any, hostEl: any) {
    const unsubs: any[] = [];
    try {
        // Preview thumbnails should loop continuously (muted).
        video.controls = false;
        video.loop = true;
        video.muted = true;
        video.playsInline = true;
        video.autoplay = true;
    } catch (e: any) {
        console.debug?.(e);
    }

    const controls = document.createElement("div");
    controls.className = "mjr-video-controls mjr-video-controls--preview";
    try {
        controls.setAttribute("role", "group");
        controls.setAttribute("aria-label", t("video.previewControls", "Video preview controls"));
    } catch (e: any) {
        console.debug?.(e);
    }

    const btn = document.createElement("button");
    btn.type = "button";
    btn.className = "mjr-video-preview-btn";
    btn.title = t("video.playPause", "Play/Pause");
    try {
        btn.setAttribute("aria-label", t("video.playPause", "Play/Pause"));
    } catch (e: any) {
        console.debug?.(e);
    }

    const icon = document.createElement("span");
    icon.className = "pi pi-play";
    try {
        icon.setAttribute("aria-hidden", "true");
    } catch (e: any) {
        console.debug?.(e);
    }
    btn.appendChild(icon);
    controls.appendChild(btn);

    const setIcon = () => {
        try {
            const paused = Boolean(video?.paused);
            icon.className = `pi ${paused ? "pi-play" : "pi-pause"}`;
        } catch (e: any) {
            console.debug?.(e);
        }
    };

    const tryPlay = () => {
        try {
            const p = video.play?.();
            if (p && typeof p.catch === "function") p.catch(() => {});
        } catch (e: any) {
            console.debug?.(e);
        }
    };

    const toggle = (e: any) => {
        try {
            e?.stopPropagation?.();
        } catch (e: any) {
            console.debug?.(e);
        }
        try {
            if (video.paused) {
                tryPlay();
            } else {
                video.pause?.();
            }
        } catch (e: any) {
            console.debug?.(e);
        }
        setIcon();
    };

    try {
        hostEl.appendChild(controls);
    } catch (e: any) {
        console.debug?.(e);
    }

    // Best-effort autoplay.
    try {
        tryPlay();
    } catch (e: any) {
        console.debug?.(e);
    }
    unsubs.push(safeAddListener(video, "loadedmetadata", () => tryPlay(), { passive: true }));
    unsubs.push(safeAddListener(video, "canplay", () => tryPlay(), { passive: true }));

    unsubs.push(safeAddListener(btn, "click", toggle));
    unsubs.push(safeAddListener(video, "play", setIcon, { passive: true }));
    unsubs.push(safeAddListener(video, "pause", setIcon, { passive: true }));
    unsubs.push(safeAddListener(video, "ended", () => tryPlay(), { passive: true }));
    try {
        setIcon();
    } catch (e: any) {
        console.debug?.(e);
    }

    return {
        controlsEl: controls,
        destroy: () => {
            try {
                for (const u of unsubs) safeCall(() => u?.());
            } catch (e: any) {
                console.debug?.(e);
            }
            try {
                controls.remove?.();
            } catch (e: any) {
                console.debug?.(e);
            }
        },
    };
}

/**
 * Mount custom video controls on top of a <video> element.
 * Must never throw (viewer stability).
 *
 * Viewer variant adds Nuke-style range + frame controls (in/out, step, loop/once).
 *
 * @param {HTMLMediaElement} video
 * @param {{variant?: 'viewer'|'preview'|'viewerbar', mediaKind?: 'video'|'audio', hostEl?: HTMLElement, fullscreenEl?: HTMLElement, initialFps?: number, initialFrameCount?: number, initialPlaybackRate?: number}} opts
 * @returns {{controlsEl: HTMLElement|null, destroy: () => void, setMediaInfo?: (info: {fps?: number, frameCount?: number}) => void, setPlaybackRate?: (rate:number)=>number, getPlaybackRate?: ()=>number, adjustPlaybackRate?: (delta:number)=>number, togglePlay?: ()=>boolean, stepFrames?: (direction:number)=>boolean}}
 */
export function mountVideoControls(video: any, opts: Record<string, any> = {}) {
    try {
        const variant = _resolveVideoControlsVariant(opts);
        const mediaKind = String(opts?.mediaKind || "video").toLowerCase();
        const isAudioMedia = mediaKind === "audio";
        const isViewerBar = variant === "viewerbar";
        const showTimelineRuler = variant !== "preview";
        const advanced = showTimelineRuler;
        // Volume slider is toggled from the sound icon to keep the bar compact.
        const showVolumeSlider = true;
        const initialFps = _resolveInitialFps(opts);
        const hostEl = opts?.hostEl || video?.parentElement;
        if (!video || !hostEl) return { controlsEl: null, destroy: noop };

        // ---------------------------------------------------------------------
        // Preview variant: minimal play/pause overlay + continuous looping
        // ---------------------------------------------------------------------
        if (variant === "preview") {
            return _mountPreviewControls(video, hostEl);
        }

        // We manage looping ourselves (Loop/Once + in/out range); disable native looping to avoid conflicts.
        try {
            video.loop = false;
        } catch (e: any) {
            console.debug?.(e);
        }

        safeCall(() => hostEl.classList?.add("mjr-video-host"));
        safeCall(() => video.classList?.add("mjr-video-el"));

        safeCall(() => {
            const cs = window.getComputedStyle?.(hostEl);
            if (cs?.position === "static") hostEl.style.position = "relative";
        });

        const controls = document.createElement("div");
        controls.className = `mjr-video-controls mjr-video-controls--${variant}`;
        if (isViewerBar) controls.classList.add("mjr-video-controls--modern");
        if (isAudioMedia) controls.classList.add("mjr-video-controls--audio");
        controls.dataset.mjrLayout = "regular";
        controls.setAttribute("role", "group");
        controls.setAttribute(
            "aria-label",
            isAudioMedia
                ? t("video.audioControls", "Audio controls")
                : t("video.controls", "Video controls"),
        );

        const rowTop = document.createElement("div");
        rowTop.className = "mjr-video-row mjr-video-row--top";
        const rowBottom = document.createElement("div");
        rowBottom.className = "mjr-video-row mjr-video-row--bottom";
        controls.appendChild(rowTop);
        controls.appendChild(rowBottom);

        const seekWrap = document.createElement("div");
        seekWrap.className = "mjr-video-seek-wrap";

        const seek = document.createElement("input");
        seek.className = "mjr-video-range mjr-video-range--seek";
        seek.type = "range";
        seek.min = "0";
        seek.max = String(SEEK_RANGE_MAX);
        seek.step = "1";
        seek.value = "0";
        seek.setAttribute("aria-label", t("video.seek", "Seek"));
        seek.title = isAudioMedia
            ? t("video.seekThroughAudio", "Seek through audio")
            : t("video.seekThrough", "Seek through video");

        const seekOverlay = document.createElement("div");
        seekOverlay.className = "mjr-video-seek-overlay";

        // Seekbar range zones (more reliable than styling <input type="range"> across browsers).
        // Only used in advanced mode (viewer/viewerbar).
        let seekZones: any = null;
        let leftTrimZone: any = null;
        let selectedZone: any = null;
        let rightTrimZone: any = null;
        if (advanced) {
            seekZones = document.createElement("div");
            seekZones.className = "mjr-video-seek-zones";

            leftTrimZone = document.createElement("div");
            leftTrimZone.className = "mjr-video-seek-zone mjr-video-seek-zone--leftTrim";

            selectedZone = document.createElement("div");
            selectedZone.className = "mjr-video-seek-zone mjr-video-seek-zone--selected";

            rightTrimZone = document.createElement("div");
            rightTrimZone.className = "mjr-video-seek-zone mjr-video-seek-zone--rightTrim";

            seekZones.appendChild(leftTrimZone);
            seekZones.appendChild(selectedZone);
            seekZones.appendChild(rightTrimZone);
        }

        const tickBar = document.createElement("div");
        tickBar.className = "mjr-video-seek-ticks";
        const labelsBar = document.createElement("div");
        labelsBar.className = "mjr-video-seek-labels";
        const inMark = document.createElement("div");
        inMark.className = "mjr-video-seek-mark mjr-video-seek-mark--in";
        const outMark = document.createElement("div");
        outMark.className = "mjr-video-seek-mark mjr-video-seek-mark--out";
        const playhead = document.createElement("div");
        playhead.className = "mjr-video-seek-playhead";
        const playheadLabel = document.createElement("div");
        playheadLabel.className = "mjr-video-seek-playhead-label";
        seekOverlay.appendChild(tickBar);
        seekOverlay.appendChild(labelsBar);
        seekOverlay.appendChild(playhead);
        seekOverlay.appendChild(playheadLabel);

        // Draggable I/O handles (bigger hit area than the thin markers).
        const inHandle = document.createElement("div");
        inHandle.className = "mjr-video-seek-handle mjr-video-seek-handle--in";
        inHandle.title = t("video.dragSetIn", "Drag to set In");
        inHandle.setAttribute("aria-label", t("video.dragSetIn", "Drag to set In"));

        const outHandle = document.createElement("div");
        outHandle.className = "mjr-video-seek-handle mjr-video-seek-handle--out";
        outHandle.title = t("video.dragSetOut", "Drag to set Out");
        outHandle.setAttribute("aria-label", t("video.dragSetOut", "Drag to set Out"));

        seekWrap.appendChild(seek);
        if (seekZones) seekWrap.appendChild(seekZones);
        seekWrap.appendChild(seekOverlay);
        if (advanced) {
            // Marks are separate from the non-interactive overlay so they can be dragged directly.
            seekWrap.appendChild(inMark);
            seekWrap.appendChild(outMark);
            seekWrap.appendChild(inHandle);
            seekWrap.appendChild(outHandle);
        }

        const timeLabel = document.createElement("span");
        timeLabel.className = "mjr-video-time";
        timeLabel.textContent = "0:00 / 0:00";
        timeLabel.title = t("video.currentTimeTotal", "Current time / Total duration");

        const rangeCountLabel = document.createElement("span");
        rangeCountLabel.className = "mjr-video-range-count";
        rangeCountLabel.textContent = "";
        try {
            rangeCountLabel.style.display = "none";
        } catch (e: any) {
            console.debug?.(e);
        }

        const timeGroup = document.createElement("div");
        timeGroup.className = "mjr-video-timegroup";
        timeGroup.appendChild(timeLabel);
        if (advanced) timeGroup.appendChild(rangeCountLabel);

        const frameLabel = document.createElement("span");
        frameLabel.className = "mjr-video-frame";
        frameLabel.textContent = "F: 0";
        frameLabel.title = t("video.currentFrame", "Current frame number");

        const playBtn = createBtn(
            "mjr-video-btn--play",
            t("btn.play", "Play"),
            t("video.playPauseSpace", "Play/Pause (Space)"),
        );
        const prevFrameBtn = createBtn(
            "mjr-video-btn--step",
            "<",
            t("video.stepBack", "Step back"),
        );
        const nextFrameBtn = createBtn(
            "mjr-video-btn--step",
            ">",
            t("video.stepForward", "Step forward"),
        );
        const toInBtn = createBtn(
            "mjr-video-btn--jump mjr-video-btn--in",
            "|<",
            t("video.goToIn", "Go to In"),
        );
        const toOutBtn = createBtn(
            "mjr-video-btn--jump mjr-video-btn--out",
            ">|",
            t("video.goToOut", "Go to Out"),
        );

        const setInBtn = createBtn(
            "mjr-video-btn--mark mjr-video-btn--in",
            "I",
            t("video.setInFromCurrent", "Set In from current frame"),
        );
        const setOutBtn = createBtn(
            "mjr-video-btn--mark mjr-video-btn--out",
            "O",
            t("video.setOutFromCurrent", "Set Out from current frame"),
        );
        const loopIcon = createIconBtn(
            "mjr-video-btn--toggle",
            "pi-refresh",
            t("video.loopPlaybackInRange", "Loop playback in range"),
            t("video.loop", "Loop"),
        );
        const loopBtn = loopIcon.btn;

        const inInput = createNumberInput("mjr-video-num--in", {
            min: 0,
            step: 1,
            value: 0,
            title: t("video.inFrame", "In frame"),
            ariaLabel: t("video.inFrame", "In frame"),
            widthPx: 72,
        });
        const outInput = createNumberInput("mjr-video-num--out", {
            min: 0,
            step: 1,
            value: 0,
            title: t("video.outFrame", "Out frame"),
            ariaLabel: t("video.outFrame", "Out frame"),
            widthPx: 72,
        });
        const stepInput = createNumberInput("mjr-video-num--step", {
            min: 1,
            step: 1,
            value: 1,
            title: t("video.frameIncrement", "Frame increment"),
            ariaLabel: t("video.frameIncrement", "Frame increment"),
            widthPx: 56,
        });
        const fpsInput = createNumberInput("mjr-video-num--fps", {
            min: 1,
            step: 0.001,
            value: normalizeVideoFps(initialFps || 30),
            title: t("video.fpsStepping", "FPS (used for frame stepping)"),
            ariaLabel: t("video.fps", "FPS"),
            widthPx: 56,
        });
        const speedSelect = document.createElement("select");
        speedSelect.className = "mjr-video-num mjr-video-num--speed";
        speedSelect.title = t("video.playbackSpeed", "Playback speed");
        speedSelect.setAttribute("aria-label", t("video.playbackSpeed", "Playback speed"));
        speedSelect.style.width = "74px";
        const SPEED_OPTIONS = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 2, 3, 5, 10];
        for (const rate of SPEED_OPTIONS) {
            const opt = document.createElement("option");
            opt.value = String(rate);
            opt.textContent = `${rate}x`;
            speedSelect.appendChild(opt);
        }

        const muteIcon = createIconBtn(
            "mjr-video-btn--mute",
            "pi-volume-up",
            t("video.mute", "Mute"),
            t("video.mute", "Mute"),
        );
        const muteBtn = muteIcon.btn;
        const volumeWrap = document.createElement("div");
        volumeWrap.className = "mjr-video-volume-wrap";
        volumeWrap.style.cssText = "display:none; align-items:center; position:relative;";
        let volume: any = null;
        if (showVolumeSlider) {
            volume = document.createElement("input");
            volume.className = "mjr-video-range mjr-video-range--volume";
            volume.type = "range";
            volume.min = "0";
            volume.max = "1";
            volume.step = "0.02";
            volume.value = String(clamp01(Number(video.volume) || 0));
            volume.setAttribute("aria-label", t("video.volume", "Volume"));
            volume.title = t("video.volume", "Volume");
            try {
                volume.style.width = "120px";
            } catch (e: any) {
                console.debug?.(e);
            }
            volumeWrap.appendChild(volume);
        }

        const inGroup = document.createElement("div");
        inGroup.className = "mjr-video-group mjr-video-group--in";
        const inLabel = document.createElement("span");
        inLabel.textContent = "In";
        inLabel.title = t("video.resetInToStart", "Reset In to start");
        inLabel.style.cssText = "cursor:pointer; user-select:none;";
        if (advanced) {
            inGroup.appendChild(inLabel);
            inGroup.appendChild(inInput);
        }

        const outGroup = document.createElement("div");
        outGroup.className = "mjr-video-group mjr-video-group--out";
        const outLabel = document.createElement("span");
        outLabel.textContent = "Out";
        outLabel.title = t("video.resetOutToEnd", "Reset Out to end");
        outLabel.style.cssText = "cursor:pointer; user-select:none;";
        if (advanced) {
            outGroup.appendChild(outLabel);
            outGroup.appendChild(outInput);
        }

        const leftAdjustGroup = document.createElement("div");
        leftAdjustGroup.className = "mjr-video-group mjr-video-group--adjust-left";
        if (advanced) {
            // Requested: keep current frame next to the FPS controls in the bottom row.
            leftAdjustGroup.appendChild(setInBtn);
            if (!isAudioMedia) {
                leftAdjustGroup.appendChild(document.createTextNode(t("video.step", "Step")));
                leftAdjustGroup.appendChild(stepInput);
                leftAdjustGroup.appendChild(document.createTextNode(t("video.fps", "FPS")));
                leftAdjustGroup.appendChild(fpsInput);
            }
            leftAdjustGroup.appendChild(frameLabel);
        }

        const rightAdjustGroup = document.createElement("div");
        rightAdjustGroup.className = "mjr-video-group mjr-video-group--adjust-right";
        if (advanced) {
            rightAdjustGroup.appendChild(timeGroup);
            rightAdjustGroup.appendChild(loopBtn);
        }
        const speedGroup = document.createElement("div");
        speedGroup.className = "mjr-video-group mjr-video-group--speed";
        speedGroup.appendChild(document.createTextNode(t("video.speed", "Speed")));
        speedGroup.appendChild(speedSelect);

        // Bottom row: center transport, right-side extra controls
        const bottomLeft = document.createElement("div");
        bottomLeft.className = "mjr-video-bottom mjr-video-bottom--left";
        const transport = document.createElement("div");
        transport.className = "mjr-video-transport";
        const bottomRight = document.createElement("div");
        bottomRight.className = "mjr-video-bottom mjr-video-bottom--right";

        transport.appendChild(toInBtn);
        if (!isAudioMedia) transport.appendChild(prevFrameBtn);
        transport.appendChild(playBtn);
        if (!isAudioMedia) transport.appendChild(nextFrameBtn);
        transport.appendChild(toOutBtn);

        if (advanced) bottomLeft.appendChild(leftAdjustGroup);
        if (advanced) bottomRight.appendChild(rightAdjustGroup);
        bottomRight.appendChild(speedGroup);
        bottomRight.appendChild(muteBtn);
        if (advanced) bottomRight.appendChild(setOutBtn);
        if (volume) bottomRight.appendChild(volumeWrap);

        if (isViewerBar) {
            const timelineStrip = document.createElement("div");
            timelineStrip.className = "mjr-video-bar-timeline";
            if (advanced) timelineStrip.appendChild(inGroup);
            timelineStrip.appendChild(seekWrap);
            if (advanced) timelineStrip.appendChild(outGroup);

            const actionsStrip = document.createElement("div");
            actionsStrip.className = "mjr-video-bar-actions";

            const actionsLeft = document.createElement("div");
            actionsLeft.className = "mjr-video-bar-side mjr-video-bar-side--left";
            if (advanced) actionsLeft.appendChild(leftAdjustGroup);

            const actionsCenter = document.createElement("div");
            actionsCenter.className = "mjr-video-bar-center";
            actionsCenter.appendChild(transport);

            const actionsRight = document.createElement("div");
            actionsRight.className = "mjr-video-bar-side mjr-video-bar-side--right";
            if (advanced) actionsRight.appendChild(rightAdjustGroup);
            actionsRight.appendChild(speedGroup);
            actionsRight.appendChild(muteBtn);
            if (advanced) actionsRight.appendChild(setOutBtn);
            if (volume) actionsRight.appendChild(volumeWrap);

            actionsStrip.appendChild(actionsLeft);
            actionsStrip.appendChild(actionsCenter);
            actionsStrip.appendChild(actionsRight);

            controls.replaceChildren(timelineStrip, actionsStrip);
        } else {
            if (advanced) rowTop.appendChild(frameLabel);
            if (advanced) rowTop.appendChild(inGroup);
            rowTop.appendChild(seekWrap);
            if (advanced) rowTop.appendChild(outGroup);
            rowTop.appendChild(timeGroup);

            rowBottom.appendChild(bottomLeft);
            rowBottom.appendChild(transport);
            rowBottom.appendChild(bottomRight);
        }

        // Ensure the controls overlay never triggers viewer panning/zoom handlers.
        const stop = (e: any) => {
            try {
                e.stopPropagation?.();
            } catch (e: any) {
                console.debug?.(e);
            }
        };
        const preventStop = (e: any) => {
            try {
                e.preventDefault?.();
            } catch (e: any) {
                console.debug?.(e);
            }
            stop(e);
        };

        const unsubs: any[] = [];
        const timersAC = (() => {
            try {
                return new AbortController();
            } catch {
                return {
                    signal: { aborted: false, addEventListener: noop, removeEventListener: noop },
                    abort: noop,
                };
            }
        })();
        unsubs.push(() => {
            try {
                timersAC.abort();
            } catch (e: any) {
                console.debug?.(e);
            }
        });

        const applyResponsiveLayout = () => {
            try {
                const width = Number(hostEl?.clientWidth) || Number(controls?.clientWidth) || 0;
                let layout = "regular";
                if (width > 0 && width < 560) layout = "stacked";
                else if (width > 0 && width < 860) layout = "compact";
                controls.dataset.mjrLayout = layout;
            } catch (e: any) {
                console.debug?.(e);
            }
        };

        applyResponsiveLayout();

        try {
            if (typeof ResizeObserver === "function" && hostEl) {
                // Coalesce ResizeObserver bursts (e.g. window drag) into a single
                // layout recalc per frame to avoid layout thrash.
                const raf =
                    typeof requestAnimationFrame === "function" ? requestAnimationFrame : null;
                const caf =
                    typeof cancelAnimationFrame === "function" ? cancelAnimationFrame : null;
                let roFrame = 0;
                const scheduleLayout = raf
                    ? () => {
                          if (roFrame) return;
                          roFrame = raf(() => {
                              roFrame = 0;
                              applyResponsiveLayout();
                          });
                      }
                    : () => applyResponsiveLayout();
                const ro = new ResizeObserver(scheduleLayout);
                ro.observe(hostEl);
                unsubs.push(() => {
                    try {
                        if (roFrame && caf) caf(roFrame);
                        ro.disconnect();
                    } catch (e: any) {
                        console.debug?.(e);
                    }
                });
            }
        } catch (e: any) {
            console.debug?.(e);
        }
        // Must NOT run in capture phase, otherwise it blocks pointerdown on child controls
        // like the draggable In/Out handles. We stop bubbling instead, and rely on the
        // window-capture guards below to prevent viewer pan/zoom handlers.
        unsubs.push(safeAddListener(controls, "pointerdown", stop));
        unsubs.push(safeAddListener(controls, "dblclick", preventStop, { capture: true }));
        unsubs.push(
            safeAddListener(controls, "wheel", preventStop, { capture: true, passive: false }),
        );

        // We intentionally do NOT stop pointer events at the window capture phase, because that would
        // prevent child controls (like draggable In/Out handles) from receiving pointerdown.
        // Pan/zoom suppression is handled in `viewer/panzoom.js` by ignoring events originating inside
        // `.mjr-video-controls`.
        unsubs.push(
            safeAddListener(
                window,
                "dblclick",
                (e) => {
                    try {
                        if (controls.contains?.(e?.target as Node)) preventStop(e);
                    } catch (e: any) {
                        console.debug?.(e);
                    }
                },
                { capture: true },
            ),
        );
        unsubs.push(
            safeAddListener(
                window,
                "wheel",
                (e) => {
                    try {
                        if (controls.contains?.(e?.target as Node)) preventStop(e);
                    } catch (e: any) {
                        console.debug?.(e);
                    }
                },
                { capture: true, passive: false },
            ),
        );

        const state: Record<string, any> = {
            outFrame: null,
            frameCount: null,
            loop: advanced,
            pingpong: false,
            once: false,
            playbackRate: Math.max(0.25, Math.min(10, Number(opts?.initialPlaybackRate) || 1)),
            _seeking: false,
            _ppReverse: false,
            _ppRafId: null,
            _userInteracted: false,
        };
        state.nativeFps = initialFps ? normalizeVideoFps(initialFps, 30) : null;
        state.fps = state.nativeFps || normalizeVideoFps(fpsInput.value, 30);

        const isFpsOverridden = () => {
            const nativeFps = Number(state.nativeFps);
            const fps = Number(state.fps);
            return Number.isFinite(nativeFps) && nativeFps > 0 && !_isSameFps(fps, nativeFps);
        };

        const updateFpsInputState = (updateValue = false) => {
            try {
                if (!fpsInput || isAudioMedia) return;
                const nativeFps = Number(state.nativeFps);
                const overridden = isFpsOverridden();
                const baseTitle = t("video.fpsStepping", "FPS (used for frame stepping)");
                fpsInput.classList.toggle("is-overridden", overridden);
                if (Number.isFinite(nativeFps) && nativeFps > 0) {
                    fpsInput.dataset.defaultFps = String(nativeFps);
                    fpsInput.title = `${baseTitle} - Source FPS: ${nativeFps}`;
                    if (overridden) fpsInput.title += " - Modified";
                } else {
                    delete fpsInput.dataset.defaultFps;
                    fpsInput.title = baseTitle;
                }
                if (updateValue && !fpsInput.matches?.(":focus")) {
                    fpsInput.value = String(normalizeVideoFps(state.fps, state.nativeFps || 30));
                }
            } catch (e: any) {
                console.debug?.(e);
            }
        };
        updateFpsInputState(true);

        // Auto-unmute once the user interacts with the video controls.
        // This bypasses autoplay restrictions: most browsers allow unmuted playback after a user gesture.
        const tryAutoUnmute = () => {
            if (state._userInteracted) return;
            state._userInteracted = true;
            try {
                // Only unmute if the video is currently muted due to autoplay restrictions
                // (not if user explicitly muted via the mute button).
                if (video.muted) {
                    video.muted = false;
                    updateVolumeUI?.();
                }
            } catch (e: any) {
                console.debug?.(e);
            }
        };

        let _stepFlashCancel: any = null;
        const flashFrameStep = () => {
            if (!advanced) return;
            try {
                frameLabel.classList.add("is-step");
                try {
                    _stepFlashCancel?.();
                } catch (e: any) {
                    console.debug?.(e);
                }
                _stepFlashCancel = setAbortableTimeout(timersAC.signal, STEP_FLASH_MS, () => {
                    try {
                        frameLabel.classList.remove("is-step");
                    } catch (e: any) {
                        console.debug?.(e);
                    }
                });
            } catch (e: any) {
                console.debug?.(e);
            }
        };
        unsubs.push(() => {
            try {
                _stepFlashCancel?.();
            } catch (e: any) {
                console.debug?.(e);
            }
            _stepFlashCancel = null;
            try {
                frameLabel?.classList?.remove?.("is-step");
            } catch (e: any) {
                console.debug?.(e);
            }
        });

        const setToggleBtn = (btn: any, on: any) => {
            try {
                if (!btn) return;
                if (on) btn.classList.add("is-on");
                else btn.classList.remove("is-on");
            } catch (e: any) {
                console.debug?.(e);
            }
        };

        const setPlaybackRate = (nextRate: any) => {
            try {
                const n = Number(nextRate);
                if (!Number.isFinite(n) || n <= 0) return state.playbackRate;
                const rate = Math.max(0.25, Math.min(10, Math.round(n * 100) / 100));
                state.playbackRate = rate;
                try {
                    video.playbackRate = rate;
                } catch (e: any) {
                    console.debug?.(e);
                }
                try {
                    if (!speedSelect.matches?.(":focus")) speedSelect.value = String(rate);
                } catch (e: any) {
                    console.debug?.(e);
                }
                return rate;
            } catch {
                return state.playbackRate;
            }
        };

        const applyLoopOnceUI = () => {
            try {
                setToggleBtn(loopBtn, Boolean(state.loop || state.pingpong));
                try {
                    if (loopIcon?.icon) {
                        if (state.pingpong) {
                            loopIcon.icon.className = "pi pi-sort-alt";
                            loopBtn.title = t(
                                "video.pingpongPlayback",
                                "Ping-pong playback (forward then reverse)",
                            );
                        } else {
                            loopIcon.icon.className = "pi pi-refresh";
                            loopBtn.title = t(
                                "video.loopPlaybackInRange",
                                "Loop playback in range",
                            );
                        }
                    }
                } catch (e: any) {
                    console.debug?.(e);
                }
            } catch (e: any) {
                console.debug?.(e);
            }
        };

        const durationFrames = () => {
            try {
                const override = Number(state.frameCount);
                if (Number.isFinite(override) && override > 0)
                    return Math.max(1, Math.floor(override));
                const d = Number(video?.duration);
                const fps = normalizeVideoFps(state.fps, 30);
                if (!Number.isFinite(d) || d <= 0) return 0;
                return Math.max(0, Math.floor(d * fps));
            } catch {
                return 0;
            }
        };

        const currentFrame = (timeOverride: number | null | undefined = null) => {
            try {
                const sourceTime = timeOverride == null ? video?.currentTime : timeOverride;
                const t = Number(sourceTime);
                const fps = normalizeVideoFps(state.fps, 30);
                if (!Number.isFinite(t) || t < 0) return 0;
                // Use floor rather than round so the frame counter matches the
                // currently displayed frame instead of jumping ahead mid-frame.
                return Math.max(0, Math.floor(t * fps + 1e-6));
            } catch {
                return 0;
            }
        };

        const frameToTime = (frame: any) => {
            const fps = normalizeVideoFps(state.fps, 30);
            const f = Math.max(0, Number(frame) || 0);
            return f / fps;
        };

        const normalizeRange = () => {
            try {
                const maxF = durationFrames();
                if (maxF <= 0) return;
                const inF = state.inFrame == null ? 0 : clamp(state.inFrame, 0, maxF);
                const outF = state.outFrame == null ? maxF : clamp(state.outFrame, 0, maxF);
                if (outF < inF) {
                    state.inFrame = outF;
                    state.outFrame = inF;
                } else {
                    state.inFrame = inF;
                    state.outFrame = outF;
                }
            } catch (e: any) {
                console.debug?.(e);
            }
        };

        const getEffectiveInOut = () => {
            try {
                const maxF = durationFrames();
                const inF = state.inFrame == null ? 0 : clamp(state.inFrame, 0, maxF);
                const outF = state.outFrame == null ? maxF : clamp(state.outFrame, 0, maxF);
                return { inF, outF, maxF };
            } catch {
                return { inF: 0, outF: 0, maxF: 0 };
            }
        };

        const getSeekRangeMax = () => {
            try {
                if (!advanced || isAudioMedia) return SEEK_RANGE_MAX;
                const frames = durationFrames();
                if (Number.isFinite(frames) && frames > SEEK_RANGE_MAX) {
                    return Math.max(SEEK_RANGE_MAX, Math.floor(frames));
                }
            } catch (e: any) {
                console.debug?.(e);
            }
            return SEEK_RANGE_MAX;
        };

        const syncSeekRangeMax = () => {
            try {
                seek.max = String(getSeekRangeMax());
            } catch (e: any) {
                console.debug?.(e);
            }
        };

        const setPlayLabel = () => {
            try {
                const isPlaying = !video?.paused || state._ppReverse;
                playBtn.textContent = isPlaying
                    ? t("video.pause", "Pause")
                    : t("video.play", "Play");
            } catch (e: any) {
                console.debug?.(e);
            }
        };

        const setMuteLabel = () => {
            try {
                const muted = Boolean(video?.muted) || (Number(video?.volume) || 0) <= 0.001;
                try {
                    muteIcon.icon.className = `pi ${muted ? "pi-volume-off" : "pi-volume-up"}`;
                } catch (e: any) {
                    console.debug?.(e);
                }
                const muteLabel = muted ? t("video.unmute", "Unmute") : t("video.mute", "Mute");
                muteBtn.title = muteLabel;
                muteBtn.setAttribute("aria-label", muteLabel);
            } catch (e: any) {
                console.debug?.(e);
            }
        };

        const updateTimeUI = (timeOverride: number | null | undefined = null) => {
            try {
                const d = Number(video?.duration);
                const sourceTime = timeOverride == null ? video?.currentTime : timeOverride;
                const t = Number(sourceTime);
                const durationOk = Number.isFinite(d) && d > 0;

                timeLabel.textContent = `${formatTime(t)} / ${durationOk ? formatTime(d) : "0:00"}`;
                seek.disabled = !durationOk;

                if (durationOk) {
                    const p = clamp01((t || 0) / d);
                    syncSeekRangeMax();
                    const v = Math.round(p * getSeekRangeMax());
                    if (!Number.isNaN(v) && !state._seeking && !seek.matches?.(":active")) {
                        seek.value = String(v);
                    }
                    try {
                        playhead.style.left = `${p * 100}%`;
                    } catch (e: any) {
                        console.debug?.(e);
                    }
                } else {
                    seek.value = "0";
                    try {
                        playhead.style.left = "0%";
                    } catch (e: any) {
                        console.debug?.(e);
                    }
                }

                const maxF = advanced ? durationFrames() : 0;
                const cf = advanced ? currentFrame(t) : 0;
                if (showTimelineRuler) {
                    if (advanced) frameLabel.textContent = isAudioMedia
                        ? `T: ${formatTime(t)} / ${formatTime(d)}`
                        : `F: ${cf} / ${maxF}`;
                    try {
                        const durOk = Number.isFinite(d) && d > 0;
                        if (durOk) {
                            const p = clamp01((t || 0) / d);
                            playheadLabel.style.left = `${p * 100}%`;
                            playheadLabel.textContent = isAudioMedia ? formatTime(t) : String(cf);
                            playheadLabel.style.display = "";
                        } else {
                            playheadLabel.style.display = "none";
                        }
                    } catch (e: any) {
                        console.debug?.(e);
                    }
                }

                if (advanced) {
                    if (!inInput.matches?.(":focus")) inInput.value = String(state.inFrame ?? 0);
                    if (!outInput.matches?.(":focus"))
                        outInput.value = String(state.outFrame ?? maxF);

                    // Show selected playback range frame count near timecode (only when trimmed).
                    try {
                        const { inF, outF, maxF: mx } = getEffectiveInOut();
                        const fullRange = inF <= 0 && outF >= mx;
                        const count = Math.max(0, Math.floor(outF) - Math.floor(inF) + 1);
                        if (!fullRange && mx > 0) {
                            rangeCountLabel.textContent = isAudioMedia
                                ? `R: ${formatTime(count / normalizeVideoFps(state.fps, 30))}`
                                : `R: ${count}f`;
                            rangeCountLabel.style.display = "";
                        } else {
                            rangeCountLabel.style.display = "none";
                        }
                    } catch (e: any) {
                        console.debug?.(e);
                    }
                }
            } catch (e: any) {
                console.debug?.(e);
            }
        };

        const updateAudioTimelineRuler = () => {
            if (!showTimelineRuler || !isAudioMedia) return;
            try {
                const duration = Number(video?.duration);
                if (!Number.isFinite(duration) || duration <= 0) {
                    tickBar.style.backgroundImage = "";
                    labelsBar.replaceChildren();
                    try {
                        labelsBar.dataset.mjrLabelKey = "";
                    } catch (e: any) {
                        console.debug?.(e);
                    }
                    return;
                }

                const minorSeconds = chooseNiceTimeStep(duration, 80);
                const majorSeconds = chooseNiceTimeStep(duration, 8);
                const minorPct = (minorSeconds / duration) * 100;
                const majorPct = (majorSeconds / duration) * 100;

                if (Number.isFinite(minorPct) && minorPct > 0.02) {
                    const minor = `repeating-linear-gradient(to right, rgba(255,255,255,0.16) 0, rgba(255,255,255,0.16) 1px, transparent 1px, transparent ${minorPct}%)`;
                    const major = `repeating-linear-gradient(to right, rgba(255,255,255,0.3) 0, rgba(255,255,255,0.3) 1px, transparent 1px, transparent ${majorPct}%)`;
                    tickBar.style.backgroundImage = `${major}, ${minor}`;
                } else {
                    tickBar.style.backgroundImage = "";
                }

                const key = `audio|${Math.round(duration * 1000)}|${Math.round(majorSeconds * 1000)}`;
                if (labelsBar?.dataset?.mjrLabelKey === key) return;
                labelsBar.dataset.mjrLabelKey = key;
                labelsBar.replaceChildren();

                const makeLabel = (seconds: any) => {
                    const s = document.createElement("span");
                    s.className = "mjr-video-seek-label";
                    const value = Math.max(0, Math.min(duration, Number(seconds) || 0));
                    s.style.left = `${clamp01(value / duration) * 100}%`;
                    s.textContent = formatTime(value);
                    return s;
                };

                labelsBar.appendChild(makeLabel(0));
                for (let seconds = majorSeconds; seconds < duration; seconds += majorSeconds) {
                    labelsBar.appendChild(makeLabel(seconds));
                }
                labelsBar.appendChild(makeLabel(duration));
            } catch (e: any) {
                console.debug?.(e);
            }
        };

        const updateSeekRangeStyle = () => {
            if (!advanced) {
                updateAudioTimelineRuler();
                return;
            }
            try {
                const { inF, outF, maxF } = getEffectiveInOut();
                if (!Number.isFinite(maxF) || maxF <= 0) return;
                const inPct = clamp01(inF / maxF) * 100;
                const outPct = clamp01(outF / maxF) * 100;
                const fullRange = inF <= 0 && outF >= maxF;

                // Prefer overlay zones over range background for cross-browser reliability.
                try {
                    seek.style.background = "";
                } catch (e: any) {
                    console.debug?.(e);
                }

                try {
                    const inP = clamp01(inPct / 100) * 100;
                    const outP = clamp01(outPct / 100) * 100;
                    const selLeft = Math.min(inP, outP);
                    const selRight = Math.max(inP, outP);
                    if (seekZones && leftTrimZone && selectedZone && rightTrimZone) {
                        // 0..In (leftTrim) is intentionally kept visually neutral (see CSS).
                        leftTrimZone.style.left = "0%";
                        leftTrimZone.style.width = `${selLeft}%`;

                        selectedZone.style.left = `${selLeft}%`;
                        selectedZone.style.width = `${Math.max(0, selRight - selLeft)}%`;

                        rightTrimZone.style.left = `${selRight}%`;
                        rightTrimZone.style.width = `${Math.max(0, 100 - selRight)}%`;

                        try {
                            seekZones.classList.toggle("is-trimmed", !fullRange);
                            seekZones.classList.toggle("is-fullrange", fullRange);
                        } catch (e: any) {
                            console.debug?.(e);
                        }
                    }
                } catch (e: any) {
                    console.debug?.(e);
                }
                try {
                    inMark.style.left = `${inPct}%`;
                    outMark.style.left = `${outPct}%`;
                } catch (e: any) {
                    console.debug?.(e);
                }
                try {
                    inHandle.style.left = `${inPct}%`;
                    outHandle.style.left = `${outPct}%`;
                } catch (e: any) {
                    console.debug?.(e);
                }

                if (isAudioMedia) {
                    updateAudioTimelineRuler();
                    return;
                }

                // Nuke-like tick ruler. Clamp tick density so we don't create thousands of ticks for long clips.
                try {
                    const targetTicks = MAX_MINOR_TICKS; // max minor ticks
                    const minFramesPerTick = Math.max(1, Math.floor(maxF / targetTicks));
                    const framesPerTick = Math.max(
                        minFramesPerTick,
                        Math.floor(Number(state.step) || 1),
                    );
                    const minorPct = (framesPerTick / maxF) * 100;
                    const majorPct = minorPct * 10;
                    if (Number.isFinite(minorPct) && minorPct > 0.02) {
                        const minor = `repeating-linear-gradient(to right, rgba(255,255,255,0.16) 0, rgba(255,255,255,0.16) 1px, transparent 1px, transparent ${minorPct}%)`;
                        const major = `repeating-linear-gradient(to right, rgba(255,255,255,0.28) 0, rgba(255,255,255,0.28) 1px, transparent 1px, transparent ${majorPct}%)`;
                        tickBar.style.backgroundImage = `${major}, ${minor}`;
                    } else {
                        tickBar.style.backgroundImage = "";
                    }

                    // Frame number labels (major ticks). Keep count small to avoid overlap.
                    const rebuildLabels = () => {
                        try {
                            const key = `${maxF}|${framesPerTick}`;
                            if (labelsBar?.dataset?.mjrLabelKey === key) return;
                            labelsBar.dataset.mjrLabelKey = key;
                        } catch (e: any) {
                            console.debug?.(e);
                        }
                        try {
                            labelsBar.replaceChildren();
                        } catch (e: any) {
                            console.debug?.(e);
                        }
                        const MAX_LABELS = 22;
                        let majorFrames = Math.max(1, framesPerTick * 10);
                        try {
                            while (majorFrames > 0 && Math.ceil(maxF / majorFrames) > MAX_LABELS)
                                majorFrames *= 2;
                        } catch (e: any) {
                            console.debug?.(e);
                        }

                        const makeLabel = (frame: any) => {
                            const s = document.createElement("span");
                            s.className = "mjr-video-seek-label";
                            const pct = clamp01(frame / maxF) * 100;
                            s.style.left = `${pct}%`;
                            s.textContent = String(Math.floor(frame));
                            return s;
                        };

                        try {
                            labelsBar.appendChild(makeLabel(0));
                        } catch (e: any) {
                            console.debug?.(e);
                        }
                        for (let f = majorFrames; f < maxF; f += majorFrames) {
                            try {
                                labelsBar.appendChild(makeLabel(f));
                            } catch (e: any) {
                                console.debug?.(e);
                            }
                        }
                        try {
                            labelsBar.appendChild(makeLabel(maxF));
                        } catch (e: any) {
                            console.debug?.(e);
                        }
                    };
                    rebuildLabels();
                } catch (e: any) {
                    console.debug?.(e);
                }
            } catch (e: any) {
                console.debug?.(e);
            }
        };

        const applyRangeChange = ({ prefer = null }: { prefer?: string | null } = {}) => {
            if (!advanced) return;
            try {
                normalizeRange();
                const { inF, outF } = getEffectiveInOut();
                const cf = currentFrame();
                if (prefer === "in") {
                    goToFrame(inF);
                } else if (prefer === "out") {
                    if (cf > outF) goToFrame(outF);
                } else {
                    // If outside the range, clamp into it (Nuke-like).
                    if (cf < inF) goToFrame(inF);
                    else if (cf > outF) goToFrame(outF);
                }
            } catch (e: any) {
                console.debug?.(e);
            }
        };

        const resetInToStart = () => {
            try {
                state.inFrame = 0;
                normalizeRange();
                updateTimeUI();
                updateSeekRangeStyle();
                applyRangeChange({ prefer: "in" });
            } catch (e: any) {
                console.debug?.(e);
            }
        };

        const resetOutToEnd = () => {
            try {
                const { maxF } = getEffectiveInOut();
                state.outFrame = Math.max(0, Number(maxF) || 0);
                normalizeRange();
                updateTimeUI();
                updateSeekRangeStyle();
                applyRangeChange({ prefer: "out" });
            } catch (e: any) {
                console.debug?.(e);
            }
        };

        const _cancelPingpongReverse = () => {
            try {
                if (state._ppRafId != null) {
                    cancelAnimationFrame(state._ppRafId);
                    state._ppRafId = null;
                }
            } catch (e: any) {
                console.debug?.(e);
            }
        };
        unsubs.push(_cancelPingpongReverse);

        const _startPingpongReverse = () => {
            try {
                _cancelPingpongReverse();
                state._ppReverse = true;
                video.pause?.();
                setPlayLabel();
                const fps = normalizeVideoFps(state.fps, 30);
                const rate = Math.max(0.25, Number(state.playbackRate) || 1);
                const intervalMs = 1000 / (fps * rate);
                let lastTime = performance.now();

                const stepBack = (now: any) => {
                    try {
                        if (!state._ppReverse || !state.pingpong) {
                            state._ppReverse = false;
                            setPlayLabel();
                            return;
                        }
                        const dt = now - lastTime;
                        if (dt >= intervalMs) {
                            lastTime = now - (dt % intervalMs);
                            const { inF } = getEffectiveInOut();
                            const cf = currentFrame();
                            if (cf <= inF) {
                                // Reached start  -  switch to forward
                                state._ppReverse = false;
                                goToFrame(inF);
                                const p = video.play?.();
                                if (p && typeof p.catch === "function") p.catch(() => {});
                                setPlayLabel();
                                updateTimeUI();
                                return;
                            }
                            const stepSize = Math.max(1, Math.floor(Number(state.step) || 1));
                            goToFrame(cf - stepSize);
                            updateTimeUI();
                        }
                        state._ppRafId = requestAnimationFrame(stepBack);
                    } catch (e: any) {
                        console.debug?.(e);
                        state._ppReverse = false;
                        setPlayLabel();
                    }
                };
                state._ppRafId = requestAnimationFrame(stepBack);
            } catch (e: any) {
                console.debug?.(e);
                state._ppReverse = false;
            }
        };

        const resetPlayerAll = () => {
            try {
                const maxF = durationFrames();
                state.inFrame = 0;
                state.outFrame = maxF > 0 ? maxF : null;
                state.step = 1;
                state.loop = Boolean(advanced);
                state.pingpong = false;
                state._ppReverse = false;
                _cancelPingpongReverse();
                state.once = false;
                setPlaybackRate(1);
                try {
                    stepInput.value = "1";
                } catch (e: any) {
                    console.debug?.(e);
                }
                try {
                    if (!speedSelect.matches?.(":focus")) speedSelect.value = "1";
                } catch (e: any) {
                    console.debug?.(e);
                }
                normalizeRange();
                applyLoopOnceUI();
                updateTimeUI();
                updateSeekRangeStyle();
                applyRangeChange({ prefer: "in" });
            } catch (e: any) {
                console.debug?.(e);
            }
        };

        const updateVolumeUI = () => {
            try {
                const v = clamp01(Number(video?.volume) || 0);
                try {
                    if (volume && !volume.matches?.(":active")) volume.value = String(v);
                } catch (e: any) {
                    console.debug?.(e);
                }
                setMuteLabel();
            } catch (e: any) {
                console.debug?.(e);
            }
        };

        const goToFrame = (frame: any) => {
            try {
                const { maxF } = getEffectiveInOut();
                const f = clamp(frame, 0, maxF > 0 ? maxF : Infinity);
                video.currentTime = frameToTime(f);
            } catch (e: any) {
                console.debug?.(e);
            }
            updateTimeUI();
        };

        const stepFrames = (direction: any) => {
            tryAutoUnmute();
            try {
                const inc = Math.max(1, Math.floor(Number(state.step) || 1));
                const { inF, outF } = getEffectiveInOut();
                const cf = currentFrame();
                let next = cf + direction * inc;
                if (state.loop) {
                    if (next < inF) next = outF;
                    if (next > outF) next = inF;
                } else {
                    next = clamp(next, inF, outF);
                }
                try {
                    video.pause?.();
                } catch (e: any) {
                    console.debug?.(e);
                }
                goToFrame(next);
                flashFrameStep();
            } catch (e: any) {
                console.debug?.(e);
            }
        };

        const ensureInRangeBeforePlay = () => {
            if (!advanced) return;
            try {
                normalizeRange();
                const { inF, outF } = getEffectiveInOut();
                const cf = currentFrame();
                if (cf < inF || cf > outF) goToFrame(inF);
            } catch (e: any) {
                console.debug?.(e);
            }
        };

        const togglePlay = () => {
            tryAutoUnmute();
            try {
                if (state._ppReverse) {
                    // Stop pingpong reverse and pause
                    state._ppReverse = false;
                    _cancelPingpongReverse();
                    setPlayLabel();
                    return;
                }
                if (video.paused) {
                    ensureInRangeBeforePlay();
                    const p = video.play?.();
                    if (p && typeof p.catch === "function") p.catch(() => {});
                } else {
                    video.pause?.();
                }
            } catch (e: any) {
                console.debug?.(e);
            }
            setPlayLabel();
        };

        // Click on video toggles play/pause (common UX).
        unsubs.push(
            safeAddListener(video, "click", (e: any) => {
                try {
                    if (e?.target !== video) return;
                } catch (e: any) {
                    console.debug?.(e);
                }
                togglePlay();
            }),
        );

        unsubs.push(
            safeAddListener(playBtn, "click", (e: any) => {
                stop(e);
                togglePlay();
            }),
        );
        unsubs.push(
            safeAddListener(prevFrameBtn, "click", (e: any) => {
                stop(e);
                stepFrames(-1);
            }),
        );
        unsubs.push(
            safeAddListener(nextFrameBtn, "click", (e: any) => {
                stop(e);
                stepFrames(1);
            }),
        );
        unsubs.push(
            safeAddListener(toInBtn, "click", (e: any) => {
                stop(e);
                const { inF } = getEffectiveInOut();
                goToFrame(inF);
                flashFrameStep();
            }),
        );
        unsubs.push(
            safeAddListener(toOutBtn, "click", (e: any) => {
                stop(e);
                const { outF } = getEffectiveInOut();
                goToFrame(outF);
                flashFrameStep();
            }),
        );

        // Seeking (range slider)
        const seekToClientX = (clientX: any) => {
            try {
                const d = Number(video?.duration);
                if (!Number.isFinite(d) || d <= 0) return false;
                const rect = seekWrap.getBoundingClientRect?.();
                const width = Number(rect?.width) || 0;
                if (!(width > 0)) return false;
                const x = clamp((Number(clientX) || 0) - Number(rect.left || 0), 0, width);
                const p = clamp01(x / width);
                const nextTime = p * d;
                video.currentTime = nextTime;
                syncSeekRangeMax();
                seek.value = String(Math.round(p * getSeekRangeMax()));
                updateTimeUI(nextTime);
                return true;
            } catch (e: any) {
                console.debug?.(e);
                return false;
            }
        };

        const seekDrag: Record<string, any> = { active: false, pointerId: null, ac: null };

        const endSeekDrag = (e: any = null) => {
            if (!seekDrag.active) return;
            if (e) preventStop(e);
            seekDrag.active = false;
            state._seeking = false;
            try {
                seekWrap.releasePointerCapture?.(seekDrag.pointerId);
            } catch (err: any) {
                console.debug?.(err);
            }
            seekDrag.pointerId = null;
            try {
                seekDrag.ac?.abort?.();
            } catch (err: any) {
                console.debug?.(err);
            }
            seekDrag.ac = null;
            updateTimeUI();
        };

        const moveSeekDrag = (e: any) => {
            if (!seekDrag.active) return;
            preventStop(e);
            seekToClientX(e.clientX);
        };

        const startSeekDrag = (e: any) => {
            try {
                if (e?.button != null && e.button !== 0) return;
                if (e?.target?.closest?.(".mjr-video-seek-handle, .mjr-video-seek-mark")) return;
            } catch (err: any) {
                console.debug?.(err);
            }
            preventStop(e);
            tryAutoUnmute();
            state._seeking = true;
            seekDrag.active = true;
            seekDrag.pointerId = e?.pointerId ?? null;
            seekToClientX(e?.clientX);
            try {
                seekWrap.setPointerCapture?.(seekDrag.pointerId);
            } catch (err: any) {
                console.debug?.(err);
            }
            try {
                seekDrag.ac?.abort?.();
            } catch (err: any) {
                console.debug?.(err);
            }
            try {
                const ac = new AbortController();
                seekDrag.ac = ac;
                window.addEventListener("pointermove", moveSeekDrag, {
                    passive: false,
                    capture: true,
                    signal: ac.signal,
                });
                window.addEventListener("pointerup", endSeekDrag, {
                    passive: false,
                    capture: true,
                    signal: ac.signal,
                });
                window.addEventListener("pointercancel", endSeekDrag, {
                    passive: false,
                    capture: true,
                    signal: ac.signal,
                });
                window.addEventListener("blur", endSeekDrag, { signal: ac.signal });
            } catch (err: any) {
                console.debug?.(err);
            }
        };

        unsubs.push(() => endSeekDrag());
        unsubs.push(safeAddListener(seekWrap, "pointerdown", startSeekDrag, { passive: false }));
        unsubs.push(
            safeAddListener(seek, "pointerdown", () => {
                state._seeking = true;
            }),
        );
        unsubs.push(
            safeAddListener(seek, "pointerup", () => {
                if (!seekDrag.active) state._seeking = false;
            }),
        );
        unsubs.push(
            safeAddListener(seek, "pointercancel", () => {
                if (!seekDrag.active) state._seeking = false;
            }),
        );
        unsubs.push(
            safeAddListener(seek, "input", (e: any) => {
                stop(e);
                tryAutoUnmute();
                try {
                    const d = Number(video?.duration);
                    if (!Number.isFinite(d) || d <= 0) return;
                    const v = Number(seek.value);
                    const p = clamp01((Number.isFinite(v) ? v : 0) / getSeekRangeMax());
                    video.currentTime = p * d;
                } catch (e: any) {
                    console.debug?.(e);
                }
                updateTimeUI();
            }),
        );

        if (advanced) {
            unsubs.push(
                safeAddListener(setInBtn, "click", (e: any) => {
                    stop(e);
                    state.inFrame = currentFrame();
                    normalizeRange();
                    updateTimeUI();
                    updateSeekRangeStyle();
                    applyRangeChange({ prefer: "in" });
                }),
            );
            unsubs.push(
                safeAddListener(setOutBtn, "click", (e: any) => {
                    stop(e);
                    state.outFrame = currentFrame();
                    normalizeRange();
                    updateTimeUI();
                    updateSeekRangeStyle();
                    applyRangeChange({ prefer: "out" });
                }),
            );
            unsubs.push(
                safeAddListener(inInput, "change", (e: any) => {
                    stop(e);
                    try {
                        const v = Number(inInput.value);
                        state.inFrame = Number.isFinite(v) ? Math.max(0, Math.floor(v)) : null;
                        normalizeRange();
                    } catch (e: any) {
                        console.debug?.(e);
                    }
                    updateTimeUI();
                    updateSeekRangeStyle();
                    applyRangeChange({ prefer: "in" });
                }),
            );
            unsubs.push(
                safeAddListener(outInput, "change", (e: any) => {
                    stop(e);
                    try {
                        const v = Number(outInput.value);
                        state.outFrame = Number.isFinite(v) ? Math.max(0, Math.floor(v)) : null;
                        normalizeRange();
                    } catch (e: any) {
                        console.debug?.(e);
                    }
                    updateTimeUI();
                    updateSeekRangeStyle();
                    applyRangeChange({ prefer: "out" });
                }),
            );
            unsubs.push(
                safeAddListener(stepInput, "change", (e: any) => {
                    stop(e);
                    try {
                        state.step = Math.max(1, Math.floor(Number(stepInput.value) || 1));
                        stepInput.value = String(state.step);
                    } catch (e: any) {
                        console.debug?.(e);
                    }
                }),
            );
            unsubs.push(
                safeAddListener(fpsInput, "change", (e: any) => {
                    stop(e);
                    try {
                        state.fps = normalizeVideoFps(fpsInput.value, 30);
                        fpsInput.value = String(state.fps);
                        updateFpsInputState(false);
                        normalizeRange();
                    } catch (e: any) {
                        console.debug?.(e);
                    }
                    updateTimeUI();
                    updateSeekRangeStyle();
                }),
            );
            unsubs.push(
                safeAddListener(loopBtn, "click", (e: any) => {
                    stop(e);
                    // Cycle: off -> loop -> pingpong -> off
                    if (!state.loop && !state.pingpong) {
                        state.loop = true;
                        state.pingpong = false;
                    } else if (state.loop && !state.pingpong) {
                        state.loop = false;
                        state.pingpong = true;
                    } else {
                        state.loop = false;
                        state.pingpong = false;
                    }
                    if (state.loop || state.pingpong) state.once = false;
                    // Cancel any active pingpong reverse animation
                    if (!state.pingpong) {
                        state._ppReverse = false;
                        _cancelPingpongReverse();
                    }
                    applyLoopOnceUI();
                }),
            );
            unsubs.push(
                safeAddListener(inLabel, "click", (e: any) => {
                    stop(e);
                    resetInToStart();
                }),
            );
            unsubs.push(
                safeAddListener(outLabel, "click", (e: any) => {
                    stop(e);
                    resetOutToEnd();
                }),
            );
            unsubs.push(
                safeAddListener(rangeCountLabel, "click", (e: any) => {
                    stop(e);
                    resetPlayerAll();
                }),
            );
            try {
                rangeCountLabel.title = t("video.resetPlayerControls", "Reset player controls");
                rangeCountLabel.style.cursor = "pointer";
                rangeCountLabel.style.userSelect = "none";
            } catch (e: any) {
                console.debug?.(e);
            }
        }

        unsubs.push(
            safeAddListener(muteBtn, "click", (e: any) => {
                stop(e);
                try {
                    video.muted = !video.muted;
                    if (volumeWrap) {
                        volumeWrap.style.display = video.muted ? "none" : "inline-flex";
                    }
                } catch (e: any) {
                    console.debug?.(e);
                }
                updateVolumeUI();
            }),
        );
        unsubs.push(
            safeAddListener(muteBtn, "contextmenu", (e: any) => {
                preventStop(e);
                try {
                    if (!volumeWrap) return;
                    const open = volumeWrap.style.display !== "none";
                    volumeWrap.style.display = open ? "none" : "inline-flex";
                } catch (e: any) {
                    console.debug?.(e);
                }
                updateVolumeUI();
            }),
        );
        unsubs.push(
            safeAddListener(
                window,
                "pointerdown",
                (e) => {
                    try {
                        if (!volumeWrap || volumeWrap.style.display === "none") return;
                        if (muteBtn.contains?.(e?.target as Node) || volumeWrap.contains?.(e?.target as Node))
                            return;
                        volumeWrap.style.display = "none";
                    } catch (e: any) {
                        console.debug?.(e);
                    }
                },
                { capture: true },
            ),
        );
        if (volume) {
            unsubs.push(
                safeAddListener(volume, "input", (e: any) => {
                    stop(e);
                    try {
                        const v = clamp01(Number(volume.value) || 0);
                        video.volume = v;
                        if (v > 0.001) video.muted = false;
                    } catch (e: any) {
                        console.debug?.(e);
                    }
                    updateVolumeUI();
                }),
            );
        }
        unsubs.push(
            safeAddListener(speedSelect, "change", (e: any) => {
                stop(e);
                try {
                    setPlaybackRate(Number(speedSelect.value) || 1);
                } catch (e: any) {
                    console.debug?.(e);
                }
                try {
                    // Release focus so Left/Right keep navigating between assets
                    // instead of being swallowed by the focused <select>.
                    speedSelect.blur?.();
                } catch (e: any) {
                    console.debug?.(e);
                }
            }),
        );
        unsubs.push(
            safeAddListener(video, "ratechange", () => {
                try {
                    setPlaybackRate(Number(video.playbackRate) || state.playbackRate || 1);
                } catch (e: any) {
                    console.debug?.(e);
                }
            }),
        );
        const enforceRange = () => {
            if (!advanced) return;
            try {
                if (state._seeking) return;
                if (video?.paused) return;

                const { inF, outF, maxF } = getEffectiveInOut();
                if (maxF <= 0) return;
                // Only enforce when the user has a non-full range selected.
                const fullRange = inF <= 0 && outF >= maxF;
                if (fullRange && !state.loop && !state.pingpong && !state.once) return;

                // During pingpong reverse phase, don't enforce normal range logic
                if (state._ppReverse) return;

                const cf = currentFrame();
                const eps = Math.max(1, Math.floor(Number(state.step) || 1));

                if (cf >= outF - eps) {
                    if (state.pingpong) {
                        _startPingpongReverse();
                        return;
                    } else if (state.loop) {
                        goToFrame(inF);
                        try {
                            const p = video.play?.();
                            if (p && typeof p.catch === "function") p.catch(() => {});
                        } catch (e: any) {
                            console.debug?.(e);
                        }
                    } else if (state.once) {
                        try {
                            video.pause?.();
                        } catch (e: any) {
                            console.debug?.(e);
                        }
                        goToFrame(outF);
                    } else {
                        // Default behavior when a range is set: stop at Out (Nuke-like playback range).
                        try {
                            video.pause?.();
                        } catch (e: any) {
                            console.debug?.(e);
                        }
                        goToFrame(outF);
                    }
                } else if (cf < inF) {
                    goToFrame(inF);
                }
            } catch (e: any) {
                console.debug?.(e);
            }
        };

        const playbackUiSync: Record<string, any> = {
            rafId: null,
            rvfcId: null,
        };

        const cancelPlaybackUiSync = () => {
            try {
                if (
                    playbackUiSync.rvfcId != null &&
                    typeof video?.cancelVideoFrameCallback === "function"
                ) {
                    video.cancelVideoFrameCallback(playbackUiSync.rvfcId);
                }
            } catch (e: any) {
                console.debug?.(e);
            }
            playbackUiSync.rvfcId = null;
            try {
                if (playbackUiSync.rafId != null && typeof cancelAnimationFrame === "function") {
                    cancelAnimationFrame(playbackUiSync.rafId);
                }
            } catch (e: any) {
                console.debug?.(e);
            }
            playbackUiSync.rafId = null;
        };

        const tickPlaybackUiSync = (_now = 0, meta: any = null) => {
            playbackUiSync.rafId = null;
            playbackUiSync.rvfcId = null;
            try {
                safeCall(updateTimeUI, meta?.mediaTime);
                safeCall(enforceRange);
            } catch (e: any) {
                console.debug?.(e);
            }

            const shouldContinue = Boolean(state._ppReverse) || !video?.paused;
            if (!shouldContinue || timersAC.signal?.aborted) return;

            try {
                if (typeof video?.requestVideoFrameCallback === "function" && !state._ppReverse) {
                    playbackUiSync.rvfcId = video.requestVideoFrameCallback(tickPlaybackUiSync);
                    return;
                }
            } catch (e: any) {
                console.debug?.(e);
            }

            try {
                if (typeof requestAnimationFrame === "function") {
                    playbackUiSync.rafId = requestAnimationFrame((nextNow) => {
                        tickPlaybackUiSync(nextNow, { mediaTime: Number(video?.currentTime) || 0 });
                    });
                }
            } catch (e: any) {
                console.debug?.(e);
            }
        };

        const startPlaybackUiSync = () => {
            cancelPlaybackUiSync();
            const shouldContinue = Boolean(state._ppReverse) || !video?.paused;
            if (!shouldContinue || timersAC.signal?.aborted) return;
            tickPlaybackUiSync(0, { mediaTime: Number(video?.currentTime) || 0 });
        };

        unsubs.push(cancelPlaybackUiSync);

        // Keep UI synced with media events.
        unsubs.push(
            safeAddListener(video, "play", () => {
                safeCall(setPlayLabel);
                startPlaybackUiSync();
            }),
        );
        for (const ev of ["pause", "ended"]) {
            unsubs.push(
                safeAddListener(video, ev, () => {
                    cancelPlaybackUiSync();
                    safeCall(setPlayLabel);
                    safeCall(updateTimeUI);
                }),
            );
        }
        for (const ev of ["timeupdate", "loadedmetadata", "durationchange", "seeked"]) {
            unsubs.push(safeAddListener(video, ev, () => safeCall(updateTimeUI)));
        }
        unsubs.push(safeAddListener(video, "timeupdate", enforceRange));
        // `timeupdate` can be too coarse to reliably catch the last frames of short clips.
        // Ensure looping works even when the video reaches its natural end.
        unsubs.push(
            safeAddListener(
                video,
                "ended",
                () => {
                    if (!advanced) return;
                    try {
                        const { inF, outF, maxF } = getEffectiveInOut();
                        const fullRange = inF <= 0 && outF >= maxF;
                        if (state.pingpong && !state._ppReverse) {
                            _startPingpongReverse();
                            return;
                        }
                        if (!state.loop && !fullRange) return;
                        goToFrame(inF);
                        try {
                            const p = video.play?.();
                            if (p && typeof p.catch === "function") p.catch(() => {});
                        } catch (e: any) {
                            console.debug?.(e);
                        }
                    } catch (e: any) {
                        console.debug?.(e);
                    }
                },
                { passive: true },
            ),
        );
        if (showTimelineRuler) {
            unsubs.push(
                safeAddListener(video, "loadedmetadata", () => {
                    if (!advanced) {
                        updateSeekRangeStyle();
                        return;
                    }
                    try {
                        const maxF = durationFrames();
                        if (maxF > 0 && state.inFrame == null && state.outFrame == null) {
                            state.inFrame = 0;
                            state.outFrame = maxF;
                            normalizeRange();
                        }
                    } catch (e: any) {
                        console.debug?.(e);
                    }
                    updateSeekRangeStyle();
                }),
            );
            unsubs.push(
                safeAddListener(video, "durationchange", () => safeCall(updateSeekRangeStyle)),
            );
        }
        if (advanced) {
            unsubs.push(
                safeAddListener(video, "mjr:frameStep", () => {
                    safeCall(flashFrameStep);
                }),
            );
        }
        for (const ev of ["volumechange"]) {
            unsubs.push(safeAddListener(video, ev, () => safeCall(updateVolumeUI)));
        }

        // Initial sync
        try {
            state.fps = normalizeVideoFps(fpsInput.value, state.nativeFps || 30);
            updateFpsInputState(true);
            state.step = Math.max(1, Math.floor(Number(stepInput.value) || 1));
            normalizeRange();
            applyLoopOnceUI();
            setPlaybackRate(state.playbackRate);
        } catch (e: any) {
            console.debug?.(e);
        }
        safeCall(setPlayLabel);
        safeCall(updateTimeUI);
        safeCall(updateSeekRangeStyle);
        safeCall(updateVolumeUI);
        try {
            if (!video?.paused || state._ppReverse) {
                startPlaybackUiSync();
            }
        } catch (e: any) {
            console.debug?.(e);
        }

        const setMediaInfo = (info: Record<string, any> = {}) => {
            let oldMax = 0;
            let hadAutoFullOut = false;
            try {
                oldMax = Math.max(0, durationFrames());
                hadAutoFullOut =
                    oldMax > 0 && state.outFrame != null && state.outFrame >= oldMax - 1;
            } catch (e: any) {
                console.debug?.(e);
            }

            try {
                const fps = Number(info?.fps);
                if (Number.isFinite(fps) && fps > 0) {
                    const fpsSource = String(info?.fpsSource || info?.source || "");
                    if (fpsSource === "rvfc" && Number(state.nativeFps) > 0) return;
                    const wasOverridden = isFpsOverridden();
                    state.nativeFps = normalizeVideoFps(fps, state.nativeFps || 30);
                    if (!wasOverridden) state.fps = state.nativeFps;
                    try {
                        updateFpsInputState(true);
                    } catch (e: any) {
                        console.debug?.(e);
                    }
                }
            } catch (e: any) {
                console.debug?.(e);
            }
            try {
                const fc = Number(info?.frameCount);
                state.frameCount = Number.isFinite(fc) && fc > 0 ? Math.floor(fc) : null;
            } catch {
                state.frameCount = null;
            }
            try {
                const nextMax = Math.max(0, durationFrames());
                // If the out-point was previously pinned to the media's full extent,
                // keep that behavior when later metadata reveals a larger frame range.
                if (hadAutoFullOut && nextMax > oldMax + 0.5) {
                    state.outFrame = null;
                }
                normalizeRange();
                applyLoopOnceUI();
                updateTimeUI();
                updateSeekRangeStyle();
            } catch (e: any) {
                console.debug?.(e);
            }
        };

        // Best-effort: initialize from caller-provided media info (metadata/fps hints).
        try {
            if (advanced) {
                const initFps = Number(opts?.initialFps);
                const initFrames = Number(opts?.initialFrameCount);
                if (Number.isFinite(initFps) || Number.isFinite(initFrames)) {
                    setMediaInfo({ fps: initFps, frameCount: initFrames });
                }
            }
        } catch (e: any) {
            console.debug?.(e);
        }

        // Drag In/Out handles on the seek bar.
        if (advanced) {
            const drag: Record<string, any> = { active: false, which: null, pointerId: null, ac: null, captureEl: null };

            const frameFromClientX = (clientX: any) => {
                try {
                    const rect = seekWrap.getBoundingClientRect();
                    const x = clamp((Number(clientX) || 0) - rect.left, 0, rect.width || 1);
                    const pct = rect.width > 0 ? x / rect.width : 0;
                    const { maxF } = getEffectiveInOut();
                    return clamp(Math.round(pct * maxF), 0, maxF);
                } catch {
                    return 0;
                }
            };

            const startDrag = (e: any, which: any) => {
                preventStop(e);
                try {
                    drag.ac?.abort?.();
                } catch (e: any) {
                    console.debug?.(e);
                }
                drag.ac = null;
                drag.active = true;
                drag.which = which;
                drag.pointerId = e.pointerId;

                // Capture on the actual handle so move/up events still fire even if the pointer leaves the seek bar.
                // Some browsers are picky about capturing on non-target elements.
                try {
                    drag.captureEl = e.currentTarget || null;
                } catch {
                    drag.captureEl = null;
                }
                try {
                    drag.captureEl?.setPointerCapture?.(e.pointerId);
                } catch (e: any) {
                    console.debug?.(e);
                }
                try {
                    seekWrap.setPointerCapture?.(e.pointerId);
                } catch (e: any) {
                    console.debug?.(e);
                }

                try {
                    const ac = new AbortController();
                    drag.ac = ac;
                    // Use document-level listeners during active drag for robustness.
                    window.addEventListener("pointermove", moveDrag, {
                        passive: false,
                        capture: true,
                        signal: ac.signal,
                    });
                    window.addEventListener("pointerup", endDrag, {
                        passive: false,
                        capture: true,
                        signal: ac.signal,
                    });
                    window.addEventListener("pointercancel", endDrag, {
                        passive: false,
                        capture: true,
                        signal: ac.signal,
                    });
                } catch (e: any) {
                    console.debug?.(e);
                }

                const f = frameFromClientX(e.clientX);
                if (which === "in") state.inFrame = f;
                else state.outFrame = f;
                normalizeRange();
                updateTimeUI();
                updateSeekRangeStyle();
                applyRangeChange({ prefer: which });
            };

            const moveDrag = (e: any) => {
                if (!drag.active) return;
                preventStop(e);
                const f = frameFromClientX(e.clientX);
                if (drag.which === "in") state.inFrame = f;
                else state.outFrame = f;
                normalizeRange();
                updateTimeUI();
                updateSeekRangeStyle();
            };

            const endDrag = (e: any) => {
                if (!drag.active) return;
                preventStop(e);
                drag.active = false;
                try {
                    seekWrap.releasePointerCapture?.(drag.pointerId);
                } catch (e: any) {
                    console.debug?.(e);
                }
                try {
                    drag.captureEl?.releasePointerCapture?.(drag.pointerId);
                } catch (e: any) {
                    console.debug?.(e);
                }
                drag.captureEl = null;
                drag.pointerId = null;
                try {
                    applyRangeChange({ prefer: drag.which });
                } catch (e: any) {
                    console.debug?.(e);
                }
                try {
                    drag.ac?.abort?.();
                } catch (e: any) {
                    console.debug?.(e);
                }
                drag.ac = null;
            };

            unsubs.push(
                safeAddListener(inHandle, "pointerdown", (e: any) => startDrag(e, "in"), {
                    passive: false,
                }),
            );
            unsubs.push(
                safeAddListener(outHandle, "pointerdown", (e: any) => startDrag(e, "out"), {
                    passive: false,
                }),
            );
            // Allow dragging the thin In/Out markers too (Nuke-like).
            unsubs.push(
                safeAddListener(inMark, "pointerdown", (e: any) => startDrag(e, "in"), {
                    passive: false,
                }),
            );
            unsubs.push(
                safeAddListener(outMark, "pointerdown", (e: any) => startDrag(e, "out"), {
                    passive: false,
                }),
            );
            unsubs.push(safeAddListener(seekWrap, "pointermove", moveDrag, { passive: false }));
            unsubs.push(safeAddListener(seekWrap, "pointerup", endDrag, { passive: false }));
            unsubs.push(safeAddListener(seekWrap, "pointercancel", endDrag, { passive: false }));
        }

        safeCall(() => hostEl.appendChild(controls));

        return {
            controlsEl: controls,
            setMediaInfo,
            setPlaybackRate: (rate: any) => {
                try {
                    return setPlaybackRate(rate);
                } catch {
                    return state.playbackRate || 1;
                }
            },
            getPlaybackRate: () => {
                try {
                    return Number(state.playbackRate) || 1;
                } catch {
                    return 1;
                }
            },
            adjustPlaybackRate: (delta: any) => {
                try {
                    const d = Number(delta);
                    if (!Number.isFinite(d)) return state.playbackRate || 1;
                    return setPlaybackRate((Number(state.playbackRate) || 1) + d);
                } catch {
                    return state.playbackRate || 1;
                }
            },
            togglePlay: () => {
                try {
                    togglePlay();
                    return true;
                } catch {
                    return false;
                }
            },
            stepFrames: (direction: any) => {
                try {
                    stepFrames(direction);
                    return true;
                } catch {
                    return false;
                }
            },
            setInPoint: () => {
                if (!advanced) return false;
                try {
                    state.inFrame = currentFrame();
                    normalizeRange();
                    updateTimeUI();
                    updateSeekRangeStyle();
                    applyRangeChange({ prefer: "in" });
                    return true;
                } catch {
                    return false;
                }
            },
            setOutPoint: () => {
                if (!advanced) return false;
                try {
                    state.outFrame = currentFrame();
                    normalizeRange();
                    updateTimeUI();
                    updateSeekRangeStyle();
                    applyRangeChange({ prefer: "out" });
                    return true;
                } catch {
                    return false;
                }
            },
            goToIn: () => {
                if (!advanced) return false;
                try {
                    const { inF } = getEffectiveInOut();
                    goToFrame(inF);
                    flashFrameStep();
                    return true;
                } catch {
                    return false;
                }
            },
            goToOut: () => {
                if (!advanced) return false;
                try {
                    const { outF } = getEffectiveInOut();
                    goToFrame(outF);
                    flashFrameStep();
                    return true;
                } catch {
                    return false;
                }
            },
            destroy: () => {
                for (const u of unsubs) safeCall(u);
                safeCall(() => controls.remove());
            },
        };
    } catch {
        return { controlsEl: null, destroy: noop };
    }
}
