import { TWMixin } from "./TWMixin2.js";
import { updateAnimations } from "../elements/updateAnimations.js";
import { __decorate } from "../_virtual/_@oxc-project_runtime@0.95.0/helpers/decorate.js";
import { ContextMixin } from "./ContextMixin.js";
import { findRootTemporal } from "../elements/findRootTemporal.js";
import { ICONS, phosphorIcon } from "./icons.js";
import { getPreviewPresentationMode, getPreviewResolutionScale, getRenderMode, getShowStats, getShowThumbnailTimestamps, isNativeCanvasApiAvailable, setPreviewPresentationMode, setRenderMode, setShowStats, setShowThumbnailTimestamps } from "../preview/previewSettings.js";
import { previewSettingsContext } from "./previewSettingsContext.js";
import { AdaptiveResolutionTracker } from "../preview/AdaptiveResolutionTracker.js";
import { RenderStats } from "../preview/RenderStats.js";
import { DomStatsStrategy } from "../preview/statsTrackingStrategy.js";
import "./EFFitScale.js";
import { EFTimegroup } from "../elements/EFTimegroup.js";
import { provide } from "@lit/context";
import { LitElement, css, html } from "lit";
import { customElement, eventOptions, property, state } from "lit/decorators.js";
import { createRef, ref } from "lit/directives/ref.js";

//#region src/gui/EFWorkbench.ts
/** Debounce delay before considering the preview "at rest" after motion stops */
const REST_DEBOUNCE_MS = 200;
let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement)) {
	constructor(..._args) {
		super(..._args);
		this.rendering = false;
		this.panZoomTransform = {
			x: 0,
			y: 0,
			scale: 1
		};
		this.isExporting = false;
		this.exportProgress = null;
		this.exportStatus = "idle";
		this.previewSettings = {
			presentationMode: getPreviewPresentationMode(),
			renderMode: getRenderMode(),
			resolutionScale: getPreviewResolutionScale(),
			showStats: getShowStats(),
			showThumbnailTimestamps: getShowThumbnailTimestamps()
		};
		this.renderMode = this.previewSettings.renderMode;
		this.presentationMode = this.previewSettings.presentationMode;
		this.previewResolutionScale = this.previewSettings.resolutionScale;
		this.exportOptions = {
			includeAudio: true,
			scale: 1,
			useInOut: false,
			inMs: 0,
			outMs: 0
		};
		this.exportAbortController = null;
		this.previewIsLoading = false;
		this.isPlaying = false;
		this.isScrubbing = false;
		this.isAtRest = true;
		this.currentAdaptiveScale = 1;
		this.showStats = this.previewSettings.showStats;
		this.themeMode = this.getInitialTheme();
		this.renderStats = null;
		this.systemThemeMediaQuery = null;
		this.systemThemeListener = null;
		this.domStatsStrategy = null;
		this.isScrubbingRef = { current: false };
		this.restDebounceTimer = null;
		this.playingCheckInterval = null;
		this.adaptiveTracker = null;
		this.savePanZoomDebounceTimer = null;
		this.canvasPreviewRef = createRef();
		this.canvasPreviewResult = null;
		this.canvasAnimationFrame = null;
		this.boundHandleTransformChanged = this.handleTransformChanged.bind(this);
		this.focusOverlay = createRef();
		this.lastCanvasZoom = 1;
		this.zoomReinitTimeout = null;
		this.drawOverlays = () => {
			const focusOverlay = this.focusOverlay.value;
			if (focusOverlay) if (this.focusedElement) {
				focusOverlay.style.display = "block";
				const rect = this.focusedElement.getBoundingClientRect();
				Object.assign(focusOverlay.style, {
					position: "fixed",
					top: `${rect.top}px`,
					left: `${rect.left}px`,
					width: `${rect.width}px`,
					height: `${rect.height}px`
				});
				requestAnimationFrame(this.drawOverlays);
			} else focusOverlay.style.display = "none";
		};
	}
	static {
		this.styles = [css`
      :host {
        display: grid;
        grid-template-rows: auto 1fr 280px;
        grid-template-columns: 280px 1fr;
        width: 100%;
        height: 100%;
        overflow: hidden;
        background-color: var(--ef-color-bg);
        
        /* Component tokens (reference globals from ef-theme.css) */
        --workbench-bg: var(--ef-color-bg);
        --workbench-overlay-border: var(--ef-color-primary);
        --workbench-overlay-bg: var(--ef-color-primary-subtle);
        --toolbar-bg: var(--ef-color-bg-elevated);
        --toolbar-border: var(--ef-color-border-subtle);
      }
      
      /* Utility classes (not relying on external Tailwind) */
      .grid {
        display: grid;
      }
      
      .overflow-hidden {
        overflow: hidden;
      }
      
      .fixed {
        position: fixed;
      }
      
      .inset-0 {
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
      }
      
      .h-full {
        height: 100%;
      }
      
      .w-full {
        width: 100%;
      }
      
      .toolbar {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 8px;
        padding: 8px 12px;
        background: var(--toolbar-bg);
        border-bottom: 1px solid var(--toolbar-border);
        flex-shrink: 0;
        font-family: ui-sans-serif, system-ui, -apple-system, sans-serif;
        position: relative;
        z-index: 20;
      }
      
      .toolbar-left {
        display: flex;
        align-items: center;
        gap: 8px;
      }
      
      .toolbar-right {
        display: flex;
        align-items: center;
        gap: 8px;
      }
      
      .toolbar-btn {
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 6px;
        padding: 6px 12px;
        background: var(--ef-color-bg-inset);
        border: 1px solid var(--ef-color-border-subtle);
        border-radius: 6px;
        color: var(--ef-color-text);
        font-size: 12px;
        font-weight: 600;
        cursor: pointer;
        transition: all 0.15s ease;
      }
      
      .toolbar-btn:hover {
        background: var(--ef-color-hover);
        border-color: var(--ef-color-border);
      }
      
      .toolbar-btn.active {
        background: var(--ef-color-primary-subtle);
        border-color: var(--ef-color-primary);
        color: var(--ef-color-primary-hover);
      }
      
      .toolbar-btn.primary {
        background: var(--ef-color-primary);
        border-color: transparent;
        color: white;
        font-weight: 600;
      }
      
      .toolbar-btn.primary:hover {
        background: var(--ef-color-primary-hover);
      }
      
      .toolbar-icon-btn {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 32px;
        height: 32px;
        padding: 0;
        background: var(--ef-color-bg-inset);
        border: 1px solid var(--ef-color-border-subtle);
        border-radius: 6px;
        color: var(--ef-color-text);
        cursor: pointer;
        transition: all 0.15s ease;
      }
      
      .toolbar-icon-btn:hover {
        background: var(--ef-color-hover);
        border-color: var(--ef-color-border);
      }
      
      .toolbar-icon-btn.active {
        background: var(--ef-color-primary-subtle);
        border-color: var(--ef-color-primary);
        color: var(--ef-color-primary-hover);
      }
      
      .mode-indicator {
        display: inline-flex;
        align-items: center;
        gap: 4px;
        padding: 2px 8px;
        border-radius: 10px;
        font-size: 10px;
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: 0.5px;
        white-space: nowrap;
      }
      
      .mode-indicator.dom {
        background: color-mix(in srgb, var(--ef-color-success) 15%, transparent);
        color: var(--ef-color-success);
        border: 1px solid color-mix(in srgb, var(--ef-color-success) 30%, transparent);
      }
      
      .mode-indicator.canvas {
        background: color-mix(in srgb, var(--ef-color-type-image) 15%, transparent);
        color: var(--ef-color-type-image);
        border: 1px solid color-mix(in srgb, var(--ef-color-type-image) 30%, transparent);
      }
      
      .canvas-container {
        position: relative;
        overflow: hidden;
        flex: 1;
        display: grid;
        grid-template-columns: 100%;
        grid-template-rows: 100%;
        min-height: 0;
        background: var(--ef-color-bg);
      }
      
      .canvas-container ::slotted(*) {
        width: 100%;
        height: 100%;
        grid-column: 1;
        grid-row: 1;
      }
      
      .canvas-overlay {
        position: absolute;
        inset: 0;
        pointer-events: none;
        z-index: 1;
      }

      .preview-loading-overlay {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        height: 2px;
        overflow: hidden;
        z-index: 8;
        pointer-events: none;
        background: var(--ef-color-loading-spinner-track, rgba(255, 255, 255, 0.1));
      }

      .preview-loading-bar {
        position: absolute;
        top: 0;
        height: 100%;
        width: 40%;
        background: var(--ef-color-loading-spinner-fill, rgba(255, 255, 255, 0.8));
        animation: preview-sweep 1.4s ease-in-out infinite;
      }

      @keyframes preview-sweep {
        0% { left: -40%; }
        100% { left: 140%; }
      }
      
      .clone-content {
        position: absolute;
        transform-origin: 0 0;
      }
      
      .playback-stats {
        position: absolute;
        top: 8px;
        left: 8px;
        width: 200px;
        background: color-mix(in srgb, var(--ef-color-bg-elevated) 90%, transparent);
        backdrop-filter: blur(4px);
        border-radius: 6px;
        padding: 8px 12px;
        font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
        font-size: 11px;
        color: var(--ef-color-text);
        z-index: 10;
        pointer-events: none;
        line-height: 1.5;
      }
      
      .playback-stats .stat-row {
        display: flex;
        justify-content: space-between;
        gap: 8px;
      }
      
      .playback-stats .stat-label {
        color: var(--ef-color-text-muted);
        flex-shrink: 0;
        width: 85px;
      }
      
      .playback-stats .stat-value {
        font-weight: 600;
        text-align: right;
        flex: 1;
        font-variant-numeric: tabular-nums;
      }
      
      .playback-stats .stat-value.good {
        color: var(--ef-color-success);
      }
      
      .playback-stats .stat-value.warning {
        color: var(--ef-color-warning);
      }
      
      .playback-stats .stat-value.bad {
        color: var(--ef-color-danger);
      }
      
      .pressure-histogram {
        display: flex;
        align-items: flex-end;
        gap: 1px;
        height: 24px;
        margin-top: 8px;
        padding-top: 8px;
        border-top: 1px solid var(--ef-color-border-subtle);
      }
      
      .pressure-histogram .bar {
        flex: 1;
        min-width: 2px;
        max-width: 4px;
        border-radius: 1px 1px 0 0;
        transition: height 0.1s ease-out;
      }
      
      .pressure-histogram .bar.nominal {
        background: var(--ef-color-success);
        height: 25%;
      }
      
      .pressure-histogram .bar.fair {
        background: var(--ef-color-warning);
        height: 50%;
      }
      
      .pressure-histogram .bar.serious {
        background: var(--ef-color-warning);
        height: 75%;
      }
      
      .pressure-histogram .bar.critical {
        background: var(--ef-color-danger);
        height: 100%;
      }
      
      .pressure-histogram-label {
        display: flex;
        justify-content: space-between;
        margin-top: 4px;
        font-size: 9px;
        color: var(--ef-color-text-subtle);
      }
      
      .dropdown-panel {
        position: fixed;
        margin: 0;
        padding: 14px 16px;
        min-width: 260px;
        max-width: calc(100vw - 32px);
        background: var(--ef-color-bg-elevated);
        border: 1px solid var(--ef-color-border);
        border-radius: 10px;
        backdrop-filter: blur(12px);
        box-shadow: 0 8px 32px color-mix(in srgb, var(--ef-color-bg) 50%, transparent);
      }
      
      .dropdown-panel::backdrop {
        background: transparent;
      }
      
      .dropdown-panel:popover-open {
        /* Animation for opening */
        animation: popover-fade-in 0.15s ease-out;
      }
      
      @keyframes popover-fade-in {
        from {
          opacity: 0;
          transform: translateY(-4px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }
      
      .dropdown-header {
        display: flex;
        align-items: center;
        justify-content: space-between;
        margin-bottom: 12px;
        padding-bottom: 10px;
        border-bottom: 1px solid var(--ef-color-border-subtle);
      }
      
      .dropdown-title {
        color: var(--ef-color-text);
        font-size: 13px;
        font-weight: 600;
      }
      
      .dropdown-close {
        background: transparent;
        border: none;
        color: var(--ef-color-text-subtle);
        cursor: pointer;
      }
      
      .dropdown-section {
        background: var(--ef-color-bg-inset);
        border-radius: 8px;
        padding: 12px;
        margin-top: 10px;
      }
      
      .dropdown-label {
        color: var(--ef-color-text);
        font-size: 11px;
        font-weight: 600;
        margin-bottom: 6px;
      }
      
      .dropdown-description {
        margin-top: 8px;
        color: var(--ef-color-text-subtle);
        font-size: 10px;
        line-height: 1.4;
      }
      
      .button-group {
        display: flex;
        gap: 6px;
        margin-top: 6px;
      }
      
      .button-group-btn {
        flex: 1;
        padding: 6px 8px;
        border: 1px solid transparent;
        border-radius: 4px;
        font-size: 10px;
        font-weight: 500;
        cursor: pointer;
        transition: all 0.15s ease;
        background: transparent;
        color: var(--ef-color-text-muted);
      }
      
      .button-group-btn.active {
        background: var(--ef-color-selected);
        color: var(--ef-color-primary);
        border-color: var(--ef-color-primary-subtle);
      }
      
      .checkbox-label {
        display: flex;
        align-items: center;
        gap: 8px;
        cursor: pointer;
      }
      
      .checkbox-label input[type="checkbox"] {
        width: 14px;
        height: 14px;
        accent-color: var(--ef-color-primary);
        cursor: pointer;
      }
      
      .checkbox-label span {
        color: var(--ef-color-text);
        font-size: 12px;
        font-weight: 500;
      }
      
      .dropdown-select {
        width: 100%;
        padding: 6px 8px;
        background: var(--ef-color-bg-inset);
        border: 1px solid var(--ef-color-border);
        border-radius: 6px;
        color: var(--ef-color-text);
        font-size: 11px;
        cursor: pointer;
      }
      
      .dropdown-input {
        width: 100%;
        padding: 5px 7px;
        background: var(--ef-color-bg-inset);
        border: 1px solid var(--ef-color-border);
        border-radius: 4px;
        color: var(--ef-color-text);
        font-size: 11px;
      }
      
      .dropdown-input:disabled {
        opacity: 0.5;
        cursor: not-allowed;
        padding: 2px;
        line-height: 1;
        font-size: 14px;
        transition: color 0.15s;
      }
      
      .dropdown-close:hover {
        color: var(--ef-color-text-muted);
      }
    `];
	}
	#trackedTimegroup = null;
	#readyStateHandler = null;
	handleStageWheel(event) {
		event.preventDefault();
	}
	connectedCallback() {
		super.connectedCallback();
		this.applyTheme();
		if (!this.hasAttribute("rendering") && typeof window !== "undefined" && "FRAMEGEN_BRIDGE" in window) this.rendering = true;
		this.addEventListener("transform-changed", this.boundHandleTransformChanged);
		this.startMotionStateTracking();
		this.adaptiveTracker = new AdaptiveResolutionTracker({ onScaleChange: (scale) => {
			const oldScale = this.currentAdaptiveScale;
			this.currentAdaptiveScale = scale;
			if (this.previewResolutionScale === "auto" && this.presentationMode === "canvas" && !this.isAtRest) {
				if (this.canvasPreviewResult) {
					this.canvasPreviewResult.setResolutionScale(scale);
					console.log(`[EFWorkbench] Resolution changed ${(oldScale * 100).toFixed(0)}% → ${(scale * 100).toFixed(0)}% (instant)`);
				}
			}
		} });
		this.renderStats = new RenderStats(this.adaptiveTracker);
		if (typeof window !== "undefined") {
			this.systemThemeMediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
			this.systemThemeListener = () => {
				if (this.themeMode === "system") this.applyTheme();
			};
			this.systemThemeMediaQuery.addEventListener("change", this.systemThemeListener);
		}
	}
	disconnectedCallback() {
		super.disconnectedCallback();
		if (this.presentationMode === "dom") this.stopDomMode();
		else if (this.presentationMode === "canvas") this.stopCanvasMode();
		const timegroup = this.getTimegroup();
		if (timegroup) {
			timegroup.style.clipPath = "";
			timegroup.style.pointerEvents = "";
		}
		this.removeEventListener("transform-changed", this.boundHandleTransformChanged);
		if (this.systemThemeMediaQuery && this.systemThemeListener) this.systemThemeMediaQuery.removeEventListener("change", this.systemThemeListener);
		this.stopMotionStateTracking();
		if (typeof this.stopCacheStatsUpdates === "function") this.stopCacheStatsUpdates();
		if (this.adaptiveTracker) {
			this.adaptiveTracker.dispose();
			this.adaptiveTracker = null;
		}
		if (this.savePanZoomDebounceTimer !== null) {
			clearTimeout(this.savePanZoomDebounceTimer);
			this.savePanZoomDebounceTimer = null;
		}
		this.savePreviewPanZoom();
		if (this.#trackedTimegroup && this.#readyStateHandler) {
			this.#trackedTimegroup.removeEventListener("readystatechange", this.#readyStateHandler);
			this.#trackedTimegroup = null;
			this.#readyStateHandler = null;
		}
	}
	firstUpdated() {
		requestAnimationFrame(() => {
			this.restorePreviewPanZoom();
		});
		this.updateComplete.then(() => {
			if (this.presentationMode === "dom") this.initDomMode();
			else if (this.presentationMode === "canvas") this.initCanvasMode();
		});
		this.#syncTimegroupListener();
		const canvasSlot = this.shadowRoot?.querySelector("slot[name=\"canvas\"]");
		if (canvasSlot) canvasSlot.addEventListener("slotchange", () => {
			this.#syncTimegroupListener();
		});
	}
	handleTransformChanged(e) {
		this.panZoomTransform = e.detail;
		this.debouncedSavePreviewPanZoom();
		if (this.presentationMode === "canvas") {
			this.updateCanvasTransform();
			const zoomRatio = e.detail.scale / this.lastCanvasZoom;
			if (zoomRatio < .75 || zoomRatio > 1.33) {
				if (this.zoomReinitTimeout !== null) clearTimeout(this.zoomReinitTimeout);
				this.zoomReinitTimeout = window.setTimeout(() => {
					this.zoomReinitTimeout = null;
					if (this.presentationMode === "canvas" && this.canvasPreviewResult) {
						this.lastCanvasZoom = this.panZoomTransform.scale;
						const timegroup = this.getTimegroup();
						const canvasContainer = this.canvasPreviewRef.value;
						if (timegroup && canvasContainer) {
							const newScale = this.previewResolutionScale === "auto" ? this.getEffectiveResolutionScale(timegroup, canvasContainer) : this.getResolutionScale(timegroup, canvasContainer);
							this.canvasPreviewResult.setResolutionScale(newScale);
						}
					}
				}, 500);
			}
		}
	}
	getTimegroup() {
		const canvas = this.querySelector("[slot='canvas']");
		if (!canvas) return null;
		if (canvas instanceof EFTimegroup) return canvas;
		return canvas.querySelector("ef-timegroup");
	}
	#syncTimegroupListener() {
		const timegroup = this.getTimegroup();
		if (timegroup === this.#trackedTimegroup) return;
		if (this.#trackedTimegroup && this.#readyStateHandler) this.#trackedTimegroup.removeEventListener("readystatechange", this.#readyStateHandler);
		this.#trackedTimegroup = timegroup;
		if (!timegroup) {
			this.previewIsLoading = false;
			this.#readyStateHandler = null;
			return;
		}
		this.#readyStateHandler = () => {
			this.previewIsLoading = timegroup.contentReadyState === "loading";
		};
		timegroup.addEventListener("readystatechange", this.#readyStateHandler);
		this.previewIsLoading = timegroup.contentReadyState === "loading";
	}
	/**
	* Get the root timegroup ID for localStorage key generation.
	* Returns null if no root timegroup is found or it has no ID.
	*/
	getRootTimegroupId() {
		const timegroup = this.getTimegroup();
		if (!timegroup) return null;
		const rootTemporal = findRootTemporal(timegroup);
		if (rootTemporal instanceof EFTimegroup && rootTemporal.id) return rootTemporal.id;
		return null;
	}
	/**
	* Get localStorage key for preview pan/zoom state.
	*/
	getPreviewPanZoomStorageKey() {
		const rootId = this.getRootTimegroupId();
		return rootId ? `ef-workbench-panzoom-${rootId}` : null;
	}
	/**
	* Save preview pan/zoom to localStorage.
	*/
	savePreviewPanZoom() {
		const storageKey = this.getPreviewPanZoomStorageKey();
		if (!storageKey) return;
		try {
			const state$1 = {
				x: this.panZoomTransform.x,
				y: this.panZoomTransform.y,
				scale: this.panZoomTransform.scale
			};
			localStorage.setItem(storageKey, JSON.stringify(state$1));
		} catch (error) {
			console.warn("Failed to save preview pan/zoom to localStorage", error);
		}
	}
	/**
	* Restore preview pan/zoom from localStorage.
	*/
	restorePreviewPanZoom() {
		const storageKey = this.getPreviewPanZoomStorageKey();
		if (!storageKey) return;
		try {
			const stored = localStorage.getItem(storageKey);
			if (!stored) return;
			const state$1 = JSON.parse(stored);
			if (typeof state$1.x === "number" && typeof state$1.y === "number" && typeof state$1.scale === "number" && state$1.scale > 0) {
				const clampedScale = Math.max(.1, Math.min(5, state$1.scale));
				this.panZoomTransform = {
					x: state$1.x,
					y: state$1.y,
					scale: clampedScale
				};
				requestAnimationFrame(() => {
					const panZoomElement = this.querySelector("ef-pan-zoom");
					if (panZoomElement) {
						panZoomElement.x = this.panZoomTransform.x;
						panZoomElement.y = this.panZoomTransform.y;
						panZoomElement.scale = this.panZoomTransform.scale;
					}
					if (this.presentationMode === "canvas") this.updateCanvasTransform();
				});
			}
		} catch (error) {
			console.warn("Failed to restore preview pan/zoom from localStorage", error);
		}
	}
	/**
	* Debounced save of preview pan/zoom to avoid excessive localStorage writes.
	*/
	debouncedSavePreviewPanZoom() {
		if (this.savePanZoomDebounceTimer !== null) clearTimeout(this.savePanZoomDebounceTimer);
		this.savePanZoomDebounceTimer = window.setTimeout(() => {
			this.savePanZoomDebounceTimer = null;
			this.savePreviewPanZoom();
		}, 200);
	}
	/**
	* Start polling for motion state (playing/scrubbing).
	* We use polling because:
	* - Playing state comes from timegroup's playbackController
	* - Scrubbing state comes from isScrubbingRef (set by EFScrubber)
	*/
	startMotionStateTracking() {
		if (this.playingCheckInterval !== null) return;
		this.playingCheckInterval = window.setInterval(() => {
			this.updateMotionState();
		}, 50);
	}
	stopMotionStateTracking() {
		if (this.playingCheckInterval !== null) {
			clearInterval(this.playingCheckInterval);
			this.playingCheckInterval = null;
		}
		if (this.restDebounceTimer !== null) {
			clearTimeout(this.restDebounceTimer);
			this.restDebounceTimer = null;
		}
	}
	/**
	* Update motion state by checking timegroup and scrubbing ref.
	*/
	updateMotionState() {
		const timegroup = this.getTimegroup();
		const wasPlaying = this.isPlaying;
		const wasScrubbing = this.isScrubbing;
		this.isPlaying = timegroup?.playing ?? false;
		this.isScrubbing = this.isScrubbingRef.current;
		const wasInMotion = wasPlaying || wasScrubbing;
		const isInMotion = this.isPlaying || this.isScrubbing;
		if (isInMotion && !wasInMotion) this.handleMotionStart();
		else if (!isInMotion && wasInMotion) this.handleMotionStop();
	}
	/**
	* Pause or unpause the canvas overlay components (EFCanvas, SelectionOverlay)
	* to avoid layout-thrashing during playback.
	*/
	setOverlaysPaused(paused) {
		const canvasSlot = this.querySelector("[slot='canvas']");
		if (!canvasSlot) return;
		const efCanvas = canvasSlot.querySelector("ef-canvas");
		if (efCanvas && "paused" in efCanvas) efCanvas.paused = paused;
		const overlay = canvasSlot.querySelector("ef-canvas-selection-overlay") ?? this.querySelector("ef-canvas-selection-overlay");
		if (overlay && "paused" in overlay) overlay.paused = paused;
	}
	/**
	* Called when motion starts (playing or scrubbing began).
	*/
	handleMotionStart() {
		if (this.restDebounceTimer !== null) {
			clearTimeout(this.restDebounceTimer);
			this.restDebounceTimer = null;
		}
		this.isAtRest = false;
		this.setOverlaysPaused(true);
		if (this.previewResolutionScale === "auto" && this.adaptiveTracker) {
			const timegroup = this.getTimegroup();
			if (timegroup) {
				const compositionWidth = timegroup.offsetWidth || 1920;
				const compositionHeight = timegroup.offsetHeight || 1080;
				const rect = timegroup.getBoundingClientRect();
				const displayScale = Math.min(rect.width / compositionWidth, rect.height / compositionHeight);
				this.adaptiveTracker.initializeAtScale(displayScale);
				this.currentAdaptiveScale = this.adaptiveTracker.getRecommendedScale();
				if (this.canvasPreviewResult) this.canvasPreviewResult.setResolutionScale(this.currentAdaptiveScale);
			}
		}
	}
	/**
	* Called when motion stops (not playing and not scrubbing).
	* Starts a debounce timer before transitioning to rest state.
	*/
	handleMotionStop() {
		if (this.restDebounceTimer !== null) clearTimeout(this.restDebounceTimer);
		this.restDebounceTimer = window.setTimeout(() => {
			this.restDebounceTimer = null;
			this.transitionToRest();
		}, REST_DEBOUNCE_MS);
	}
	/**
	* Called after debounce period when we're confirmed to be at rest.
	*/
	transitionToRest() {
		this.isAtRest = true;
		this.setOverlaysPaused(false);
		if (this.previewResolutionScale === "auto" && this.presentationMode === "canvas") {
			this.adaptiveTracker?.reset();
			this.currentAdaptiveScale = 1;
			if (this.canvasPreviewResult) this.canvasPreviewResult.setResolutionScale(1);
		}
	}
	/**
	* Get the effective resolution scale based on current mode and motion state.
	* For "auto" mode, returns full resolution at rest, adaptive scale in motion.
	*/
	getEffectiveResolutionScale(timegroup, canvasContainer) {
		if (this.previewResolutionScale !== "auto") return this.getResolutionScale(timegroup, canvasContainer);
		const compositionWidth = timegroup.offsetWidth || 1920;
		const compositionHeight = timegroup.offsetHeight || 1080;
		const rect = timegroup.getBoundingClientRect();
		const displayedWidth = rect.width;
		const displayedHeight = rect.height;
		const displayScale = Math.min(displayedWidth / compositionWidth, displayedHeight / compositionHeight);
		if (this.isAtRest) {
			const scale = Math.max(.1, Math.min(1, displayScale));
			console.log(`[EFWorkbench] Auto mode (at rest): using display scale ${(scale * 100).toFixed(1)}%`);
			return scale;
		} else {
			const adaptiveScale = this.currentAdaptiveScale;
			const targetScale = Math.min(displayScale, adaptiveScale);
			const scale = Math.max(.1, Math.min(1, targetScale));
			console.log(`[EFWorkbench] Auto mode (in motion): adaptive=${adaptiveScale}, display=${displayScale.toFixed(2)}, final=${(scale * 100).toFixed(1)}%`);
			return scale;
		}
	}
	/**
	* Apply settings when dependencies are ready.
	* Called from updated() hook when settings change or dependencies become available.
	*/
	applySettings() {
		this.presentationMode = this.previewSettings.presentationMode;
		this.renderMode = this.previewSettings.renderMode;
		this.previewResolutionScale = this.previewSettings.resolutionScale;
		this.showStats = this.previewSettings.showStats;
	}
	async handlePresentationModeChange(mode) {
		if (mode === this.presentationMode) return;
		const previousMode = this.presentationMode;
		if (previousMode === "dom") this.stopDomMode();
		else if (previousMode === "canvas") this.stopCanvasMode();
		setPreviewPresentationMode(mode);
		this.previewSettings = {
			...this.previewSettings,
			presentationMode: mode
		};
		await this.updateComplete;
		if (mode === "dom") this.initDomMode();
		else if (mode === "canvas") this.initCanvasMode();
	}
	initDomMode() {
		if (this.presentationMode !== "dom") return;
		const timegroup = this.getTimegroup();
		if (!timegroup) {
			setTimeout(() => this.initDomMode(), 100);
			return;
		}
		const fitScale = this.querySelector("[slot='canvas']");
		if (!!(fitScale?.removeScale && fitScale?.paused !== void 0)) {
			fitScale.paused = true;
			fitScale.removeScale();
		}
		timegroup.proxyMode = false;
		timegroup.style.clipPath = "";
		timegroup.style.pointerEvents = "";
		if (this.showStats && this.adaptiveTracker) {
			this.domStatsStrategy = new DomStatsStrategy({
				timegroup,
				adaptiveTracker: this.adaptiveTracker
			});
			this.domStatsStrategy.start();
		}
	}
	stopDomMode() {
		if (this.domStatsStrategy) {
			this.domStatsStrategy.stop();
			this.domStatsStrategy = null;
		}
		const timegroup = this.getTimegroup();
		if (timegroup) {
			timegroup.style.clipPath = "inset(100%)";
			timegroup.style.pointerEvents = "none";
		}
		const fitScale = this.querySelector("[slot='canvas']");
		if (fitScale?.paused !== void 0) fitScale.paused = false;
	}
	/**
	* Get the resolution scale for canvas rendering (for fixed scale modes).
	*
	* Logic:
	* - Get actual displayed size from getBoundingClientRect()
	* - For "Full": render at displayed size (1:1 pixel mapping)
	* - For other settings: render at that % of displayed size
	* - Never exceed composition size (100%)
	*
	* Note: For "auto" mode, use getEffectiveResolutionScale() instead.
	*/
	getResolutionScale(timegroup, _canvasContainer) {
		if (this.previewResolutionScale === "auto") return this.getEffectiveResolutionScale(timegroup, _canvasContainer);
		const compositionWidth = timegroup.offsetWidth || 1920;
		const compositionHeight = timegroup.offsetHeight || 1080;
		const rect = timegroup.getBoundingClientRect();
		const displayedWidth = rect.width;
		const displayedHeight = rect.height;
		const displayScale = Math.min(displayedWidth / compositionWidth, displayedHeight / compositionHeight);
		const targetScale = this.previewResolutionScale === 1 ? displayScale : Math.min(displayScale, this.previewResolutionScale);
		return Math.max(.1, Math.min(1, targetScale));
	}
	async initCanvasMode() {
		if (this.presentationMode !== "canvas") return;
		const timegroup = this.getTimegroup();
		const canvasContainer = this.canvasPreviewRef.value;
		if (!timegroup || !canvasContainer) {
			setTimeout(() => this.initCanvasMode(), 100);
			return;
		}
		timegroup.proxyMode = false;
		timegroup.canvasPreviewActive = true;
		timegroup.style.clipPath = "";
		timegroup.style.pointerEvents = "none";
		canvasContainer.style.display = "block";
		const initialResolutionScale = this.previewResolutionScale === "auto" ? this.getEffectiveResolutionScale(timegroup, canvasContainer) : this.getResolutionScale(timegroup, canvasContainer);
		this.lastCanvasZoom = this.panZoomTransform.scale;
		try {
			await timegroup.seekTask.taskComplete;
			if (timegroup.playbackController) await new Promise((resolve) => setTimeout(resolve, 0));
			updateAnimations(timegroup);
			const { renderTimegroupToCanvas } = await import("../preview/renderTimegroupToCanvas.js");
			const result = renderTimegroupToCanvas(timegroup, {
				scale: 1,
				resolutionScale: initialResolutionScale
			});
			this.canvasPreviewResult = result;
			const { container, canvas, refresh } = result;
			canvas.classList.add("clone-content");
			canvasContainer.innerHTML = "";
			canvasContainer.appendChild(container);
			this.updateCanvasTransform();
			const loop = async () => {
				if (this.presentationMode !== "canvas") return;
				if (!this.isExporting) try {
					const renderStart = performance.now();
					await refresh();
					const renderTime = performance.now() - renderStart;
					if (this.renderStats) this.renderStats.recordFrame(renderTime, performance.now(), this.isAtRest);
					this.updateCanvasTransform();
				} catch (e) {
					console.error("Canvas refresh failed:", e);
				}
				this.canvasAnimationFrame = requestAnimationFrame(loop);
			};
			this.canvasAnimationFrame = requestAnimationFrame(loop);
		} catch (e) {
			console.error("Failed to init canvas mode:", e);
		}
	}
	stopCanvasMode() {
		if (this.canvasAnimationFrame !== null) {
			cancelAnimationFrame(this.canvasAnimationFrame);
			this.canvasAnimationFrame = null;
		}
		if (this.zoomReinitTimeout !== null) {
			clearTimeout(this.zoomReinitTimeout);
			this.zoomReinitTimeout = null;
		}
		this.canvasPreviewResult?.dispose();
		this.canvasPreviewResult = null;
		const timegroup = this.getTimegroup();
		if (timegroup) timegroup.canvasPreviewActive = false;
		const container = this.canvasPreviewRef.value;
		if (container) {
			container.innerHTML = "";
			container.style.display = "none";
		}
	}
	updateCanvasTransform() {
		if (this.presentationMode !== "canvas") return;
		const container = this.canvasPreviewRef.value;
		if (!container) return;
		const canvas = container.querySelector("canvas");
		if (!canvas) return;
		const { x, y, scale } = this.panZoomTransform;
		canvas.style.transform = `translate(${x}px, ${y}px) scale(${scale})`;
	}
	async initCanvasRenderer() {
		const timegroup = this.getTimegroup();
		if (!timegroup) return null;
		try {
			const { renderTimegroupToCanvas } = await import("../preview/renderTimegroupToCanvas.js");
			const { canvas, refresh } = renderTimegroupToCanvas(timegroup, 1);
			return {
				canvas,
				refresh
			};
		} catch (e) {
			console.error("Failed to init canvas renderer:", e);
			return null;
		}
	}
	/** Start video export with progress tracking */
	async startExport(options = {}) {
		const timegroup = this.getTimegroup();
		if (!timegroup) {
			console.error("No timegroup found for export");
			return;
		}
		if (this.isExporting) {
			console.warn("Export already in progress");
			return;
		}
		this.exportAbortController = new AbortController();
		this.isExporting = true;
		this.exportProgress = null;
		this.exportStatus = "rendering";
		try {
			const { renderTimegroupToVideo } = await import("../preview/renderTimegroupToVideo.js");
			await renderTimegroupToVideo(timegroup, {
				...options,
				signal: this.exportAbortController.signal,
				onProgress: (progress) => {
					this.exportProgress = progress;
				}
			});
			this.exportStatus = "complete";
			setTimeout(() => {
				this.isExporting = false;
				this.exportProgress = null;
				this.exportStatus = "idle";
				this.exportAbortController = null;
			}, 2e3);
		} catch (e) {
			const { RenderCancelledError } = await import("../preview/renderTimegroupToVideo.js");
			if (e instanceof RenderCancelledError) {
				console.log("Export cancelled by user");
				this.exportStatus = "cancelled";
				setTimeout(() => {
					this.isExporting = false;
					this.exportProgress = null;
					this.exportStatus = "idle";
					this.exportAbortController = null;
				}, 1500);
			} else {
				console.error("Export failed:", e);
				this.exportStatus = "error";
				setTimeout(() => {
					this.isExporting = false;
					this.exportProgress = null;
					this.exportStatus = "idle";
					this.exportAbortController = null;
				}, 3e3);
			}
		}
	}
	/** Cancel the current export */
	cancelExport() {
		if (this.exportAbortController) this.exportAbortController.abort();
	}
	positionPopover(popover, anchorId) {
		const anchor = this.shadowRoot?.getElementById(anchorId);
		if (!anchor) return;
		const anchorRect = anchor.getBoundingClientRect();
		const popoverRect = popover.getBoundingClientRect();
		const padding = 8;
		let top = anchorRect.bottom + padding;
		let left = anchorRect.right - popoverRect.width;
		if (left < padding) left = padding;
		if (left + popoverRect.width > window.innerWidth - padding) left = window.innerWidth - popoverRect.width - padding;
		if (top + popoverRect.height > window.innerHeight - padding) top = anchorRect.top - popoverRect.height - padding;
		popover.style.top = `${top}px`;
		popover.style.left = `${left}px`;
	}
	handleSettingsPopoverToggle(e) {
		const popover = e.target;
		if (e.newState === "open") requestAnimationFrame(() => {
			this.positionPopover(popover, "settings-btn");
		});
	}
	handleExportPopoverToggle(e) {
		const popover = e.target;
		if (e.newState === "open") {
			if (this.exportOptions.outMs === 0) {
				const timegroup = this.getTimegroup();
				if (timegroup) this.exportOptions = {
					...this.exportOptions,
					outMs: timegroup.durationMs
				};
			}
			requestAnimationFrame(() => {
				this.positionPopover(popover, "export-btn");
			});
		}
	}
	handleStartExport() {
		this.startExport({
			includeAudio: this.exportOptions.includeAudio,
			scale: this.exportOptions.scale,
			fromMs: this.exportOptions.useInOut ? this.exportOptions.inMs : void 0,
			toMs: this.exportOptions.useInOut ? this.exportOptions.outMs : void 0
		});
	}
	updateExportOption(key, value) {
		this.exportOptions = {
			...this.exportOptions,
			[key]: value
		};
	}
	formatTime(ms) {
		const totalSeconds = Math.floor(ms / 1e3);
		const minutes = Math.floor(totalSeconds / 60);
		const seconds = totalSeconds % 60;
		if (minutes > 0) return `${minutes}:${seconds.toString().padStart(2, "0")}`;
		return `${seconds}s`;
	}
	handleCancelClick() {
		this.cancelExport();
	}
	handleRenderModeChange(mode) {
		setRenderMode(mode);
		this.previewSettings = {
			...this.previewSettings,
			renderMode: mode
		};
	}
	handleShowStatsToggle(enabled) {
		setShowStats(enabled);
		this.previewSettings = {
			...this.previewSettings,
			showStats: enabled
		};
	}
	handleShowThumbnailTimestampsToggle(enabled) {
		setShowThumbnailTimestamps(enabled);
		this.previewSettings = {
			...this.previewSettings,
			showThumbnailTimestamps: enabled
		};
	}
	/**
	* Get initial theme from localStorage or default to 'dark'
	*/
	getInitialTheme() {
		if (typeof window === "undefined") return "dark";
		const stored = localStorage.getItem("ef-theme");
		if (stored === "light" || stored === "dark" || stored === "system") return stored;
		return "dark";
	}
	/**
	* Cycle through theme modes: light → dark → system → light
	*/
	handleThemeToggle() {
		const nextTheme = this.themeMode === "light" ? "dark" : this.themeMode === "dark" ? "system" : "light";
		this.themeMode = nextTheme;
		localStorage.setItem("ef-theme", nextTheme);
		this.applyTheme();
	}
	/**
	* Apply the current theme to the document and host element
	*/
	applyTheme() {
		const root = document.documentElement;
		let shouldBeDark = false;
		if (this.themeMode === "light") shouldBeDark = false;
		else if (this.themeMode === "dark") shouldBeDark = true;
		else shouldBeDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
		if (shouldBeDark) {
			root.classList.add("dark");
			root.classList.remove("light");
		} else {
			root.classList.add("light");
			root.classList.remove("dark");
		}
		if (shouldBeDark) {
			this.classList.add("dark");
			this.classList.remove("light");
		} else {
			this.classList.add("light");
			this.classList.remove("dark");
		}
	}
	/**
	* Reset and fit the preview to show all content centered.
	* Finds the pan-zoom element and calls fitToContent() on it.
	*/
	handleFitToContent() {
		const panZoomElement = this.querySelector("ef-pan-zoom");
		if (panZoomElement && typeof panZoomElement.fitToContent === "function") panZoomElement.fitToContent();
	}
	renderSettingsPopover() {
		const isAvailable = isNativeCanvasApiAvailable();
		return html`
      <div 
        id="settings-popover" 
        popover="auto"
        class="dropdown-panel"
        @toggle=${this.handleSettingsPopoverToggle}
      >
        <div class="dropdown-header">
          <span class="dropdown-title">Preview Settings</span>
          <button class="dropdown-close" popovertarget="settings-popover" popovertargetaction="hide">✕</button>
        </div>
        
        <!-- Presentation Mode Setting -->
        <div style="
          background: var(--ef-color-bg-inset);
          border-radius: 8px;
          padding: 12px;
          margin-bottom: 10px;
        ">
          <div class="dropdown-label" style="margin-bottom: 10px;">Presentation Mode</div>
          
          <div class="button-group">
            <button
              @click=${() => this.handlePresentationModeChange("dom")}
              class="button-group-btn ${this.presentationMode === "dom" ? "active" : ""}"
            >DOM</button>
            <button
              @click=${() => this.handlePresentationModeChange("canvas")}
              class="button-group-btn ${this.presentationMode === "canvas" ? "active" : ""}"
            >Canvas</button>
          </div>
          
          <div class="dropdown-description">
            ${this.presentationMode === "dom" ? "Default. Shows the real timegroup DOM directly." : "Renders to canvas each frame."}
          </div>
        </div>
        
        <!-- Render Mode Setting -->
        <div class="dropdown-section">
          <div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px;">
            <span class="dropdown-label">Render Mode</span>
            ${isAvailable ? html`
              <div style="display: flex; align-items: center; gap: 5px;">
                <span style="
                  display: inline-block;
                  width: 7px;
                  height: 7px;
                  border-radius: 50%;
                  background: var(--ef-color-success);
                "></span>
                <span style="color: var(--ef-color-success); font-size: 10px; font-weight: 500;">
                  Native Available
                </span>
              </div>
            ` : ""}
          </div>
          
          <div class="button-group">
            <button
              @click=${() => this.handleRenderModeChange("foreignObject")}
              class="button-group-btn ${this.renderMode === "foreignObject" ? "active" : ""}"
            >foreignObject</button>
            <button
              @click=${() => this.handleRenderModeChange("native")}
              ?disabled=${!isAvailable}
              class="button-group-btn ${this.renderMode === "native" ? "active" : ""}"
              style="
                cursor: ${isAvailable ? "pointer" : "not-allowed"};
                opacity: ${isAvailable ? "1" : "0.5"};
              "
            >native</button>
          </div>
          
          <div class="dropdown-description">
            ${this.renderMode === "foreignObject" ? "SVG foreignObject serialization. Works everywhere but slower." : "Chrome's drawElementImage API. Fastest, requires chrome://flags/#canvas-draw-element."}
          </div>
        </div>
        
        <!-- This section was already updated earlier in the dropdown-section refactor -->
        
        <!-- Show Performance Stats Setting -->
        <div class="dropdown-section">
          <label class="checkbox-label">
            <input
              type="checkbox"
              ?checked=${this.showStats}
              @change=${(e) => this.handleShowStatsToggle(e.target.checked)}
            />
            <span>Show Performance Stats</span>
          </label>
          
          <div class="dropdown-description">
            Display FPS, CPU pressure, and performance metrics overlay.
          </div>
        </div>
        
        <!-- Thumbnail Timestamps -->
        <div class="dropdown-section">
          <label class="checkbox-label">
            <input
              type="checkbox"
              ?checked=${this.previewSettings.showThumbnailTimestamps}
              @change=${(e) => this.handleShowThumbnailTimestampsToggle(e.target.checked)}
            />
            <span>Show Thumbnail Timestamps</span>
          </label>
          
          <div class="dropdown-description">
            Display timestamp overlay on timeline thumbnails for debugging.
          </div>
        </div>
      </div>
    `;
	}
	renderExportPopover() {
		const durationMs = this.getTimegroup()?.durationMs ?? 0;
		return html`
      <div 
        id="export-popover" 
        popover="auto"
        class="dropdown-panel"
        @toggle=${this.handleExportPopoverToggle}
      >
        <div class="dropdown-header">
          <span class="dropdown-title">Export Settings</span>
          <button class="dropdown-close" popovertarget="export-popover" popovertargetaction="hide">✕</button>
        </div>
        
        <!-- Scale -->
        <div style="margin-bottom: 10px;">
          <label class="dropdown-label" style="display: block; margin-bottom: 4px;">Scale</label>
          <select
            class="dropdown-select"
            .value=${String(this.exportOptions.scale)}
            @change=${(e) => this.updateExportOption("scale", Number(e.target.value))}
          >
            <option value="1">100% (Full)</option>
            <option value="0.75">75%</option>
            <option value="0.5">50%</option>
            <option value="0.25">25%</option>
          </select>
        </div>
        
        <!-- Audio -->
        <div style="margin-bottom: 10px;">
          <label class="checkbox-label">
            <input
              type="checkbox"
              ?checked=${this.exportOptions.includeAudio}
              @change=${(e) => this.updateExportOption("includeAudio", e.target.checked)}
            />
            <span>Include Audio</span>
          </label>
        </div>
        
        <!-- In/Out Range -->
        <div style="margin-bottom: 12px;">
          <label class="checkbox-label" style="margin-bottom: 6px;">
            <input
              type="checkbox"
              ?checked=${this.exportOptions.useInOut}
              @change=${(e) => this.updateExportOption("useInOut", e.target.checked)}
            />
            <span>Custom Range</span>
          </label>
          
          ${this.exportOptions.useInOut ? html`
            <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-top: 6px;">
              <div>
                <label class="dropdown-label" style="display: block; margin-bottom: 2px; font-size: 10px;">In (ms)</label>
                <input
                  type="number"
                  class="dropdown-input"
                  style="font-family: ui-monospace, monospace;"
                  min="0"
                  max=${durationMs}
                  .value=${String(this.exportOptions.inMs)}
                  @change=${(e) => this.updateExportOption("inMs", Number(e.target.value))}
                />
              </div>
              <div>
                <label class="dropdown-label" style="display: block; margin-bottom: 2px; font-size: 10px;">Out (ms)</label>
                <input
                  type="number"
                  class="dropdown-input"
                  style="font-family: ui-monospace, monospace;"
                  min="0"
                  max=${durationMs}
                  .value=${String(this.exportOptions.outMs)}
                  @change=${(e) => this.updateExportOption("outMs", Number(e.target.value))}
                />
              </div>
            </div>
            <div class="dropdown-description" style="margin-top: 4px;">
              Duration: ${this.formatTime(this.exportOptions.outMs - this.exportOptions.inMs)} / ${this.formatTime(durationMs)}
            </div>
          ` : html`
            <div class="dropdown-description">
              Full duration: ${this.formatTime(durationMs)}
            </div>
          `}
        </div>
        
        <!-- Start Export button -->
        <button
          class="toolbar-btn primary"
          style="width: 100%; justify-content: center;"
          @click=${this.handleStartExport}
          popovertarget="export-popover"
          popovertargetaction="hide"
        >
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
            <polygon points="23 7 16 12 23 17 23 7"></polygon>
            <rect x="1" y="5" width="15" height="14" rx="2" ry="2"></rect>
          </svg>
          Start Export
        </button>
      </div>
    `;
	}
	renderExportProgressPopover() {
		const p = this.exportProgress;
		const progressPercent = p ? Math.round(p.progress * 100) : 0;
		const isComplete = this.exportStatus === "complete";
		const isError = this.exportStatus === "error";
		const isCancelled = this.exportStatus === "cancelled";
		const isRendering = this.exportStatus === "rendering";
		let statusColor;
		let statusText;
		if (isComplete) {
			statusColor = "var(--ef-color-success)";
			statusText = "Complete!";
		} else if (isError) {
			statusColor = "var(--ef-color-danger)";
			statusText = "Failed";
		} else if (isCancelled) {
			statusColor = "var(--ef-color-warning)";
			statusText = "Cancelled";
		} else {
			statusColor = "var(--ef-color-primary)";
			statusText = `${progressPercent}%`;
		}
		return html`
      <div 
        id="export-progress-popover" 
        popover="manual"
        class="dropdown-panel" 
        style="min-width: 240px;"
      >
        <div class="dropdown-header">
          <span class="dropdown-title">Exporting</span>
          ${isRendering ? html`
            <button 
              class="dropdown-close" 
              style="color: var(--ef-color-danger);"
              @click=${this.handleCancelClick}
            >Cancel</button>
          ` : null}
        </div>
        
        ${isRendering && p !== null ? html`
          ${p.framePreviewCanvas ? html`
            <div style="margin-bottom: 10px; display: flex; justify-content: center;">
              ${p.framePreviewCanvas}
            </div>
            <style>
              ef-workbench canvas {
                border-radius: 4px;
                border: 1px solid var(--ef-color-border);
                max-width: 100%;
                height: auto;
              }
            </style>
          ` : null}
          
          <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 6px 12px; margin-bottom: 10px; font-family: ui-monospace, monospace; font-size: 10px;">
            <div>
              <div style="color: var(--ef-color-text-subtle);">Frames</div>
              <div style="color: var(--ef-color-text);">${p.currentFrame} / ${p.totalFrames}</div>
            </div>
            <div>
              <div style="color: var(--ef-color-text-subtle);">Time</div>
              <div style="color: var(--ef-color-text);">${this.formatTime(p.renderedMs)} / ${this.formatTime(p.totalDurationMs)}</div>
            </div>
            <div>
              <div style="color: var(--ef-color-text-subtle);">Speed</div>
              <div style="color: ${p.speedMultiplier >= 1 ? "var(--ef-color-success)" : "var(--ef-color-warning)"};">${p.speedMultiplier.toFixed(2)}x</div>
            </div>
            <div>
              <div style="color: var(--ef-color-text-subtle);">ETA</div>
              <div style="color: var(--ef-color-text);">${this.formatTime(p.estimatedRemainingMs)}</div>
            </div>
          </div>
        ` : null}
        
        <div style="height: 4px; background: var(--ef-color-bg-inset); border-radius: 2px; overflow: hidden;">
          <div style="
            height: 100%;
            width: ${progressPercent}%;
            background: ${statusColor};
            border-radius: 2px;
            transition: width 0.15s ease-out;
          "></div>
        </div>
        
        <div style="text-align: center; margin-top: 6px; font-size: 11px; font-weight: 600; color: ${statusColor};">
          ${statusText}
        </div>
      </div>
      
      <style>
        @keyframes spin {
          to { transform: rotate(360deg); }
        }
      </style>
    `;
	}
	renderToolbar() {
		return html`
      <div class="toolbar" part="toolbar">
        <div class="toolbar-left">
          <!-- Fit to content button -->
          <button 
            class="toolbar-icon-btn"
            @click=${this.handleFitToContent}
            title="Fit to Content (Reset Zoom & Center)"
          >
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
              <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
              <path d="M8 12h8M12 8v8"></path>
            </svg>
          </button>
        </div>
        
        <div class="toolbar-right">
          <!-- Mode indicator -->
          <span class="mode-indicator ${this.presentationMode}">
            ${this.presentationMode === "dom" ? "DOM" : html`
              Canvas ${getRenderMode() === "native" ? phosphorIcon(ICONS.lightning, 12) : phosphorIcon(ICONS.code, 12)}
            `}
          </span>
          
          <!-- Theme toggle button -->
          <button 
            class="toolbar-icon-btn"
            @click=${this.handleThemeToggle}
            title="${this.themeMode === "light" ? "Light mode" : this.themeMode === "dark" ? "Dark mode" : "System preference"}"
          >
            ${this.themeMode === "light" ? html`
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                <circle cx="12" cy="12" r="5"></circle>
                <line x1="12" y1="1" x2="12" y2="3"></line>
                <line x1="12" y1="21" x2="12" y2="23"></line>
                <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
                <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
                <line x1="1" y1="12" x2="3" y2="12"></line>
                <line x1="21" y1="12" x2="23" y2="12"></line>
                <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
                <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
              </svg>
            ` : this.themeMode === "dark" ? html`
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
              </svg>
            ` : html`
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                <rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect>
                <line x1="8" y1="21" x2="16" y2="21"></line>
                <line x1="12" y1="17" x2="12" y2="21"></line>
              </svg>
            `}
          </button>
          
          <!-- Settings button -->
          <button 
            id="settings-btn"
            class="toolbar-icon-btn"
            popovertarget="settings-popover"
            title="Preview Settings"
          >
            ${phosphorIcon(ICONS.gear, 16)}
          </button>
          
          <!-- Export button -->
          ${this.isExporting ? html`
            <button 
              id="export-btn"
              class="toolbar-btn active"
              style="min-width: 100px;"
              popovertarget="export-progress-popover"
            >
              <div style="width: 12px; height: 12px; border: 2px solid var(--ef-color-primary-subtle); border-top-color: var(--ef-color-primary); border-radius: 50%; animation: spin 1s linear infinite;"></div>
              Exporting...
            </button>
          ` : html`
            <button 
              id="export-btn"
              class="toolbar-btn primary"
              popovertarget="export-popover"
            >
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                <polygon points="23 7 16 12 23 17 23 7"></polygon>
                <rect x="1" y="5" width="15" height="14" rx="2" ry="2"></rect>
              </svg>
              Export
            </button>
          `}
        </div>
      </div>
      
      <!-- Popovers (rendered into top-layer) -->
      ${this.renderSettingsPopover()}
      ${this.renderExportPopover()}
      ${this.renderExportProgressPopover()}
    `;
	}
	update(changedProperties) {
		super.update(changedProperties);
		if (changedProperties.has("focusedElement")) this.drawOverlays();
	}
	updated(changedProperties) {
		super.updated(changedProperties);
		if (this.getTimegroup() && !changedProperties.has("panZoomTransform")) {
			if (this.panZoomTransform.x === 0 && this.panZoomTransform.y === 0 && this.panZoomTransform.scale === 1) requestAnimationFrame(() => {
				this.restorePreviewPanZoom();
			});
		}
		if (changedProperties.has("previewSettings") || changedProperties.has("presentationMode") || changedProperties.has("showStats")) this.applySettings();
		if (changedProperties.has("isExporting")) {
			const popover = this.shadowRoot?.getElementById("export-progress-popover");
			if (popover) if (this.isExporting) {
				popover.showPopover();
				requestAnimationFrame(() => {
					this.positionPopover(popover, "export-btn");
				});
			} else popover.hidePopover();
		}
	}
	renderPlaybackStats() {
		if (!this.showStats) return null;
		let stats = null;
		if (this.presentationMode === "canvas" && this.renderStats) {
			const timegroup = this.getTimegroup();
			if (!timegroup) return null;
			const compositionWidth = timegroup.offsetWidth || 1920;
			const compositionHeight = timegroup.offsetHeight || 1080;
			const resolutionScale = this.canvasPreviewResult ? this.canvasPreviewResult.getResolutionScale() : 1;
			const renderWidth = Math.floor(compositionWidth * resolutionScale);
			const renderHeight = Math.floor(compositionHeight * resolutionScale);
			stats = this.renderStats.getStats(renderWidth, renderHeight, resolutionScale);
		} else if (this.presentationMode === "dom" && this.domStatsStrategy) stats = this.domStatsStrategy.getStats();
		if (!stats) return null;
		const fpsClass = stats.fps >= 55 ? "good" : stats.fps >= 25 ? "warning" : "bad";
		const renderClass = stats.avgRenderTime !== null ? stats.avgRenderTime <= 20 ? "good" : stats.avgRenderTime <= 30 ? "warning" : "bad" : "";
		const headroomClass = stats.headroom !== null ? stats.headroom >= 10 ? "good" : stats.headroom >= 0 ? "warning" : "bad" : "";
		const pressureClass = stats.pressureState === "nominal" ? "good" : stats.pressureState === "fair" ? "good" : stats.pressureState === "serious" ? "warning" : "bad";
		const scaleClass = stats.resolutionScale !== null ? stats.resolutionScale >= .75 ? "good" : stats.resolutionScale >= .5 ? "warning" : "bad" : "";
		const isCanvasMode = this.presentationMode === "canvas";
		const showRenderTime = isCanvasMode;
		const showHeadroom = isCanvasMode;
		const showResolutionScale = isCanvasMode;
		const showAdaptiveResolution = isCanvasMode && this.previewResolutionScale === "auto";
		const motionState = this.isAtRest ? "At Rest" : this.isPlaying ? "Playing" : this.isScrubbing ? "Scrubbing" : "Idle";
		const renderPressureHistogram = () => {
			if (stats.pressureHistory.length === 0) return html`<div style="color: var(--ef-color-text-subtle); font-size: 9px;">No pressure data (API not available)</div>`;
			return html`
        <div class="pressure-histogram">
          ${stats.pressureHistory.map((state$1) => html`
            <div class="bar ${state$1}"></div>
          `)}
        </div>
        <div class="pressure-histogram-label">
          <span>30s ago</span>
          <span>now</span>
        </div>
      `;
		};
		const padNum = (n, decimals, width) => {
			return n.toFixed(decimals).padStart(width, " ");
		};
		return html`
      <div class="playback-stats">
        <div class="stat-row">
          <span class="stat-label">FPS</span>
          <span class="stat-value ${fpsClass}">${padNum(stats.fps, 1, 5)}</span>
        </div>
        ${showRenderTime && stats.avgRenderTime !== null ? html`
          <div class="stat-row">
            <span class="stat-label">Render</span>
            <span class="stat-value ${renderClass}">${padNum(stats.avgRenderTime, 1, 5)}ms</span>
          </div>
        ` : null}
        ${showHeadroom && stats.headroom !== null ? html`
          <div class="stat-row">
            <span class="stat-label">Headroom</span>
            <span class="stat-value ${headroomClass}">${stats.headroom >= 0 ? "+" : ""}${padNum(stats.headroom, 1, 4)}ms</span>
          </div>
        ` : null}
        <div class="stat-row">
          <span class="stat-label">Resolution</span>
          <span class="stat-value">${stats.renderWidth}×${stats.renderHeight}</span>
        </div>
        ${showResolutionScale && stats.resolutionScale !== null ? html`
          <div class="stat-row">
            <span class="stat-label">Scale</span>
            <span class="stat-value ${scaleClass}">${String(Math.round(stats.resolutionScale * 100)).padStart(3, " ")}%</span>
          </div>
        ` : null}
        <div class="stat-row">
          <span class="stat-label">CPU</span>
          <span class="stat-value ${pressureClass}">${stats.pressureState}</span>
        </div>
        <div class="stat-row">
          <span class="stat-label">State</span>
          <span class="stat-value">${motionState}</span>
        </div>
        ${showAdaptiveResolution && stats.samplesAtCurrentScale !== void 0 ? html`
          <div style="margin-top: 4px; padding-top: 4px; border-top: 1px solid var(--ef-color-border-subtle);">
            <div class="stat-row">
              <span class="stat-label">Mode</span>
              <span class="stat-value good">Auto</span>
            </div>
            <div class="stat-row">
              <span class="stat-label">Samples</span>
              <span class="stat-value">${String(stats.samplesAtCurrentScale).padStart(3, " ")}/60</span>
            </div>
            <div class="stat-row">
              <span class="stat-label">Scale Up</span>
              <span class="stat-value ${stats.canScaleUp ? "good" : ""}">${stats.canScaleUp ? "Ready" : "Waiting"}</span>
            </div>
            <div class="stat-row">
              <span class="stat-label">Scale Down</span>
              <span class="stat-value ${stats.canScaleDown ? "" : "warning"}">${stats.canScaleDown ? "Ready" : "Min"}</span>
            </div>
          </div>
        ` : null}
        
        <!-- CPU Pressure Histogram -->
        <div style="margin-top: 8px;">
          <div style="color: #94a3b8; font-size: 10px; margin-bottom: 4px;">CPU Pressure History</div>
          ${renderPressureHistogram()}
        </div>
      </div>
    `;
	}
	render() {
		if (this.rendering) return html`
        <slot class="fixed inset-0 h-full w-full" name="canvas"></slot>
      `;
		return html`
      <!-- Top: Full-width Toolbar -->
      <div style="grid-row: 1 / 2; grid-column: 1 / -1;">
        ${this.renderToolbar()}
      </div>
      
      <!-- Left: Hierarchy Panel -->
      <div
        style="grid-row: 2 / 3; grid-column: 1 / 2; background: var(--ef-color-bg-panel); border-right: 1px solid var(--ef-color-border); min-height: 0; overflow: hidden;"
      >
        <slot name="hierarchy"></slot>
      </div>

      <!-- Center: Canvas area -->
      <div
        class="canvas-container"
        part="canvas"
        style="grid-row: 2 / 3; grid-column: 2 / 3; min-height: 0; overflow: hidden;"
        @wheel=${this.handleStageWheel}
      >
        <!-- Original timegroup (hidden in clone/canvas mode, visible in dom mode) -->
        <slot
          name="canvas"
          @slotchange=${() => this.#syncTimegroupListener()}
        ></slot>
        
        <!-- Canvas preview (visible in canvas mode only) -->
        <div 
          class="canvas-overlay" 
          ${ref(this.canvasPreviewRef)}
          style="display: ${this.presentationMode === "canvas" ? "block" : "none"}"
        ></div>

        <!-- Preview loading overlay (shown when timegroup content is loading) -->
        ${this.previewIsLoading ? html`
          <div class="preview-loading-overlay">
            <div class="preview-loading-bar"></div>
          </div>
        ` : ""}
        
        <!-- Playback stats overlay (visible in canvas mode only) -->
        ${this.renderPlaybackStats()}
      </div>

      <!-- Bottom: Timeline -->
      <div
        class="overflow-hidden"
        style="grid-row: 3 / 4; grid-column: 1 / -1; height: 100%; border-top: 1px solid var(--ef-color-border);"
      >
        <slot name="timeline"></slot>
      </div>
    `;
	}
};
__decorate([property({ type: Boolean })], EFWorkbench.prototype, "rendering", void 0);
__decorate([state()], EFWorkbench.prototype, "panZoomTransform", void 0);
__decorate([state()], EFWorkbench.prototype, "isExporting", void 0);
__decorate([state()], EFWorkbench.prototype, "exportProgress", void 0);
__decorate([state()], EFWorkbench.prototype, "exportStatus", void 0);
__decorate([provide({ context: previewSettingsContext }), state()], EFWorkbench.prototype, "previewSettings", void 0);
__decorate([state()], EFWorkbench.prototype, "renderMode", void 0);
__decorate([state()], EFWorkbench.prototype, "presentationMode", void 0);
__decorate([state()], EFWorkbench.prototype, "previewResolutionScale", void 0);
__decorate([state()], EFWorkbench.prototype, "exportOptions", void 0);
__decorate([state()], EFWorkbench.prototype, "previewIsLoading", void 0);
__decorate([state()], EFWorkbench.prototype, "isPlaying", void 0);
__decorate([state()], EFWorkbench.prototype, "isScrubbing", void 0);
__decorate([state()], EFWorkbench.prototype, "isAtRest", void 0);
__decorate([state()], EFWorkbench.prototype, "currentAdaptiveScale", void 0);
__decorate([state()], EFWorkbench.prototype, "showStats", void 0);
__decorate([state()], EFWorkbench.prototype, "themeMode", void 0);
__decorate([eventOptions({
	passive: false,
	capture: true
})], EFWorkbench.prototype, "handleStageWheel", null);
EFWorkbench = __decorate([customElement("ef-workbench")], EFWorkbench);

//#endregion
export { EFWorkbench };
//# sourceMappingURL=EFWorkbench.js.map