diff --git a/tests/visualization/test_runtime.py b/tests/visualization/test_runtime.py index 512c2e923..d5451f656 100644 --- a/tests/visualization/test_runtime.py +++ b/tests/visualization/test_runtime.py @@ -1,20 +1,19 @@ """Tests for the installable browser workspace runtime.""" -from io import BytesIO import json -from pathlib import Path import tarfile import threading +from io import BytesIO +from pathlib import Path import pytest from fastapi.testclient import TestClient from PIL import Image from visualization import app as app_runtime -from visualization import modal_deployment -from visualization import runtime -from visualization.app import create_app +from visualization import modal_deployment, runtime from visualization import samples as sample_runtime +from visualization.app import create_app def _cuda_hardware() -> dict: @@ -83,6 +82,14 @@ def test_configuration_schema_defaults_to_vggt() -> None: assert argoverse_options["log_id"]["required"] is True +def test_yaml_catalog_ignores_cloud_duplicate_artifacts(tmp_path: Path) -> None: + (tmp_path / "vggt.yaml").write_text("model: canonical\n", encoding="utf-8") + (tmp_path / "vggt 2.yaml").write_text("model: duplicate\n", encoding="utf-8") + (tmp_path / "_base.yaml").write_text("model: base\n", encoding="utf-8") + + assert runtime._yaml_stem_options(tmp_path) == ["vggt"] + + def test_detect_hardware_always_reports_cpu() -> None: hardware = runtime.detect_hardware() @@ -237,6 +244,9 @@ def test_completed_job_exposes_splat_download(tmp_path: Path) -> None: jobs = client.get("/api/jobs").json()["items"] assert jobs[0]["has_final_splat"] is True + live = client.get("/api/jobs/finished-job/live") + assert live.status_code == 200 + assert live.json()["final_url"].endswith("/runs/finished/gaussian_splats.ply") response = client.get("/api/jobs/finished-job/splat", params={"format": "ply"}) assert response.status_code == 200 assert response.content.startswith(b"ply\n") @@ -273,6 +283,10 @@ def test_live_job_exposes_dask_worker_status(tmp_path: Path) -> None: live_root=str(live_root), spec={}, command=[], + log_tail=[ + "2026-08-13 17:00:00 [runner.py] INFO: 🌟 GTSFM: Starting SceneOptimizer...", + "2026-08-13 17:00:01 [scene_optimizer.py] INFO: 🔥 GTSFM: Partitioning the view graph...", + ], ) response = TestClient(app).get("/api/jobs/running-job/live") @@ -280,6 +294,7 @@ def test_live_job_exposes_dask_worker_status(tmp_path: Path) -> None: assert response.status_code == 200 assert response.json()["dask"]["workers"] == 2 assert response.json()["dask"]["running_tasks"] == 3 + assert response.json()["message"] == "🔥 GTSFM: Partitioning the view graph..." def test_workspace_rejects_invalid_splat_exports(tmp_path: Path) -> None: @@ -308,6 +323,23 @@ def test_sample_downloader_uses_certifi_ca_bundle() -> None: assert sample_runtime._SSL_CONTEXT.get_ca_certs() +def test_remote_workspace_requests_use_certifi_ca_bundle(monkeypatch: pytest.MonkeyPatch) -> None: + observed: dict[str, object] = {} + + def fake_urlopen(_request: object, **kwargs: object) -> BytesIO: + observed.update(kwargs) + return BytesIO(b'{"status": "ready"}') + + monkeypatch.setattr(runtime.urllib.request, "urlopen", fake_urlopen) + + result = runtime.JobManager._remote_json("https://workspace.example/api/hardware", "secret") + + assert result == {"status": "ready"} + assert observed["context"] is runtime._SSL_CONTEXT + assert observed["timeout"] == runtime._REMOTE_REQUEST_TIMEOUT_SECONDS + assert runtime._SSL_CONTEXT.get_ca_certs() + + def test_workspace_rejects_unknown_github_sample(tmp_path: Path) -> None: response = TestClient(create_app(tmp_path)).post("/api/samples/not-a-sample/prepare") @@ -559,6 +591,7 @@ def poll(self) -> None: def test_job_cancel_forwards_to_remote_vm(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setattr(threading.Thread, "start", lambda thread: thread.run()) manager = runtime.JobManager(tmp_path) job = runtime.ManagedJob( id="remote-job", @@ -585,6 +618,60 @@ def test_job_cancel_forwards_to_remote_vm(tmp_path: Path, monkeypatch: pytest.Mo assert cancelled["status"] == "cancelled" assert calls == [("https://gpu.example.test/api/jobs/upstream-job/cancel", "secret", {})] + assert job.remote == { + "endpoint": "https://gpu.example.test", + "job_id": "upstream-job", + "cancel_status": "confirmed", + } + assert job.log_tail[-1] == "Modal job cancellation confirmed." + + +def test_job_cancel_during_modal_start_forwards_after_remote_accepts( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + manager = runtime.JobManager(tmp_path) + job = runtime.ManagedJob( + id="starting-remote-job", + name="remote", + status="running", + created_at="now", + updated_at="now", + output_root=str(tmp_path / "output"), + live_root=str(tmp_path / "live"), + spec={"splat_implementation": "none"}, + command=[], + remote={"endpoint": "https://gpu.example.test"}, + remote_api_key="secret", + ) + manager._jobs[job.id] = job + calls: list[tuple[str, object]] = [] + + def fake_remote_json( + endpoint: str, _api_key: str, *, payload: dict[str, object] | None = None + ) -> dict[str, object]: + calls.append((endpoint, payload)) + if endpoint.endswith("/api/jobs"): + # Reproduce the user clicking Cancel while the POST is waiting for + # Modal's cold-started container to accept the job. + manager.cancel(job.id) + return {"id": "upstream-job", "status": "queued"} + return {"id": "upstream-job", "status": "cancelled"} + + monkeypatch.setattr(manager, "_remote_json", fake_remote_json) + + manager._run_remote(job) + + assert job.status == "cancelled" + assert calls == [ + ("https://gpu.example.test/api/jobs", {"splat_implementation": "none", "execution_target": "local"}), + ("https://gpu.example.test/api/jobs/upstream-job/cancel", {}), + ] + assert job.remote == { + "endpoint": "https://gpu.example.test", + "job_id": "upstream-job", + "workspace_url": "https://gpu.example.test/?view=results", + "cancel_status": "confirmed", + } def test_remote_job_keeps_modal_and_ssh_credentials_private(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: @@ -629,7 +716,7 @@ def test_remote_job_transfers_local_dataset_before_submit(tmp_path: Path, monkey def fake_upload(_endpoint: str, _api_key: str, directory: Path, _runtime_root: Path) -> dict[str, object]: assert directory == dataset - return {"path": "/workspace/results/.gtsfm/uploads/remote-dataset"} + return {"path": "/mnt/gtsfm-studio/results/.gtsfm/uploads/remote-dataset"} def fake_remote_json(url: str, _api_key: str, *, payload: dict[str, object] | None = None) -> dict[str, object]: if url.endswith("/api/jobs"): @@ -659,9 +746,10 @@ def fake_remote_json(url: str, _api_key: str, *, payload: dict[str, object] | No manager._run_remote(managed) - assert posted["dataset_dir"] == "/workspace/results/.gtsfm/uploads/remote-dataset" + assert posted["dataset_dir"] == "/mnt/gtsfm-studio/results/.gtsfm/uploads/remote-dataset" assert posted["execution_target"] == "local" assert managed.status == "completed" + assert json.loads((Path(managed.live_root) / "status.json").read_text(encoding="utf-8")) == {} def test_remote_sample_is_downloaded_by_remote_workspace(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: @@ -696,11 +784,11 @@ def test_remote_sample_is_downloaded_by_remote_workspace(tmp_path: Path, monkeyp assert response.json()["spec"]["sample_id"] == "lund-door" -def test_modal_remote_api_key_is_stable_and_scoped() -> None: - first = modal_deployment.modal_remote_api_key("ak-one", "as-secret") +def test_modal_workspace_api_key_is_stable_and_scoped() -> None: + first = modal_deployment.modal_workspace_api_key("ak-one", "as-secret") - assert first == modal_deployment.modal_remote_api_key("ak-one", "as-secret") - assert first != modal_deployment.modal_remote_api_key("ak-two", "as-secret") + assert first == modal_deployment.modal_workspace_api_key("ak-one", "as-secret") + assert first != modal_deployment.modal_workspace_api_key("ak-two", "as-secret") assert "as-secret" not in first @@ -762,3 +850,37 @@ def test_fastapi_exposes_openapi_and_job_websocket(tmp_path: Path) -> None: with client.websocket_connect("/api/events/jobs") as websocket: assert websocket.receive_json() == {"items": []} + + +def test_fastapi_uses_injected_hardware_provider_and_serves_favicon(tmp_path: Path) -> None: + hardware = { + "summary": "Remote GPU configured without allocation", + "devices": [{"id": "cuda:0", "supports_gaussian_splatting": True}], + "accelerator_count": 1, + "platform": {}, + } + client = TestClient(create_app(tmp_path, hardware_provider=lambda: hardware)) + + assert client.get("/api/hardware").json() == hardware + favicon = client.get("/favicon.ico") + assert favicon.status_code == 200 + assert favicon.headers["content-type"] == "image/png" + + +def test_job_manager_accepts_safe_caller_provided_job_id(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setattr(threading.Thread, "start", lambda _thread: None) + manager = runtime.JobManager(tmp_path) + spec = { + "name": "durable-id", + "dataset_dir": str(tmp_path), + "loader": "olsson", + "config_name": "vggt", + "splat_implementation": "none", + "hardware": "cpu", + } + + job = manager.start(spec, job_id="modal_job-123") + + assert job["id"] == "modal_job-123" + with pytest.raises(ValueError, match="unsupported characters"): + manager.start(spec, job_id="../../unsafe") diff --git a/visualization/app.py b/visualization/app.py index baffa74a7..1fc23487d 100644 --- a/visualization/app.py +++ b/visualization/app.py @@ -8,16 +8,19 @@ import hmac import json import os +import re import shutil import tarfile import urllib.error import uuid +from collections.abc import Callable from pathlib import Path, PurePosixPath from typing import Annotated, Any from urllib.parse import quote, urlparse import uvicorn -from fastapi import Depends, FastAPI, File, Form, Header, HTTPException, Request, UploadFile, WebSocket +from fastapi import (Depends, FastAPI, File, Form, Header, HTTPException, + Request, UploadFile, WebSocket) from fastapi.exceptions import RequestValidationError from fastapi.responses import FileResponse, HTMLResponse, JSONResponse from fastapi.staticfiles import StaticFiles @@ -25,22 +28,31 @@ from pydantic import BaseModel, ConfigDict from starlette.websockets import WebSocketDisconnect -from visualization.runtime import ( - JobManager, - configuration_schema, - detect_hardware, - install_optional_setup, - setup_status, -) -from visualization.modal_deployment import ModalDeploymentManager, modal_remote_api_key -from visualization.samples import SampleDownloadError, prepare_sample, sample_catalog - +from visualization.modal_deployment import (ModalDeploymentManager, + modal_workspace_api_key) +from visualization.runtime import (JobManager, configuration_schema, + detect_hardware, install_optional_setup, + setup_status) +from visualization.samples import (SampleDownloadError, prepare_sample, + sample_catalog) PACKAGE_ROOT = Path(__file__).resolve().parent STATIC_ROOT = PACKAGE_ROOT / "static" TEMPLATE_ROOT = PACKAGE_ROOT / "templates" SPLAT_EXPORT_FORMATS = {"ply"} IMAGE_SUFFIXES = {".avif", ".bmp", ".heic", ".heif", ".jpeg", ".jpg", ".png", ".tif", ".tiff", ".webp"} +_LOG_LEVEL_MESSAGE = re.compile(r"\b(?:DEBUG|INFO|WARNING|ERROR|CRITICAL):\s*(.+)$") +_PIPELINE_STATUS_MARKERS = ( + "gtsfm:", + "running vggt", + "gaussian", + "splat", + "partition", + "cluster optimization", + "bundle adjustment", + "image pair retrieval", + "sceneoptimizer", +) class RemoteInspectRequest(BaseModel): @@ -148,7 +160,9 @@ async def _discover_modal_endpoint(token_id: str, token_secret: str) -> dict[str """Find the deployed GTSFM web function in the token's default Modal environment.""" from modal.client import _Client - from modal.exception import AuthError, ConnectionError as ModalConnectionError, PermissionDeniedError + from modal.exception import AuthError + from modal.exception import ConnectionError as ModalConnectionError + from modal.exception import PermissionDeniedError from modal_proto import api_pb2 client = None @@ -185,7 +199,8 @@ async def _discover_modal_endpoint(token_id: str, token_secret: str) -> dict[str candidates.append((score, url, app_name or "gtsfm", function_name or "web")) if not candidates: raise ValueError( - "No deployed GTSFM web app was found in this Modal workspace. Deploy the GTSFM Modal app first, then try again." + "No deployed GTSFM web app was found in this Modal workspace. " + "Deploy the GTSFM Modal app first, then try again." ) _, endpoint, app_name, function_name = max(candidates, key=lambda item: item[0]) return {"endpoint": endpoint, "app_name": app_name, "function_name": function_name} @@ -293,6 +308,15 @@ def _live_state(manager: JobManager, resolved_base: Path, job_id: str) -> dict[s "stage": "pipeline", "progress": None, } + for raw_line in reversed(job.log_tail): + match = _LOG_LEVEL_MESSAGE.search(raw_line) + message = (match.group(1) if match else raw_line).strip() + lowered = message.lower() + if message and any(marker in lowered for marker in _PIPELINE_STATUS_MARKERS): + payload["message"] = message + break + if "message" not in payload: + payload["message"] = "Waiting for the reconstruction pipeline to report its first stage…" if status_path.exists(): try: loaded = json.loads(status_path.read_text(encoding="utf-8")) @@ -328,11 +352,16 @@ def _websocket_authorized(websocket: WebSocket) -> bool: return hmac.compare_digest(provided, expected) -def create_app(base_dir: Path | str = "results") -> FastAPI: +def create_app( + base_dir: Path | str = "results", + *, + job_manager: JobManager | None = None, + hardware_provider: Callable[[], dict[str, Any]] = detect_hardware, +) -> FastAPI: """Create an isolated FastAPI workspace for ``base_dir``.""" resolved_base = Path(base_dir).expanduser().resolve() - manager = JobManager(resolved_base) + manager = job_manager or JobManager(resolved_base) modal_deployments = ModalDeploymentManager( lambda token_id, token_secret: asyncio.run(_discover_modal_endpoint(token_id, token_secret)) ) @@ -368,6 +397,10 @@ def require_api_key(authorization: Annotated[str | None, Header()] = None) -> No def index() -> HTMLResponse: return HTMLResponse((TEMPLATE_ROOT / "index.html").read_text(encoding="utf-8")) + @app.get("/favicon.ico", include_in_schema=False) + def favicon() -> FileResponse: + return FileResponse(STATIC_ROOT / "brand" / "bee-favicon.png", media_type="image/png") + @app.get("/api/scenes") def list_scenes() -> dict[str, Any]: scenes = find_scenes(resolved_base) @@ -388,7 +421,7 @@ def get_configuration() -> dict[str, Any]: @app.get("/api/hardware") def get_hardware() -> dict[str, Any]: - return detect_hardware() + return hardware_provider() @app.get("/api/setup") def get_setup_status() -> dict[str, Any]: @@ -519,7 +552,7 @@ async def discover_modal_endpoint(payload: ModalDiscoverRequest) -> dict[str, st raise HTTPException(status_code=400, detail="Enter a valid Modal token ID and token secret") try: discovered = await _discover_modal_endpoint(payload.token_id, payload.token_secret) - discovered["api_key"] = modal_remote_api_key(payload.token_id, payload.token_secret) + discovered["api_key"] = modal_workspace_api_key(payload.token_id, payload.token_secret) return discovered except ValueError as exc: raise HTTPException(status_code=400, detail=str(exc)) from exc diff --git a/visualization/frontend/src/main.tsx b/visualization/frontend/src/main.tsx index f0bf5b4a6..8b70ffb3e 100644 --- a/visualization/frontend/src/main.tsx +++ b/visualization/frontend/src/main.tsx @@ -157,6 +157,7 @@ interface SetupStatus { interface RemoteWorkspace { configuration: ConfigurationSchema; hardware: HardwareCatalog; + verified?: boolean; } interface ModalDiscovery { @@ -230,7 +231,7 @@ function ModalDeploymentDialog({ deployment, onCancel, onClose }: { deployment:
MODAL SETUP & DEPLOYMENT{deployment.stage}
{deployment.gpu}{deployment.cpu ? ` · ${deployment.cpu} CPU` : ""}{deployment.memory_mb ? ` · ${formatBytes(deployment.memory_mb * 1024 * 1024)}` : ""} · {deployment.status} - {["queued", "running"].includes(deployment.status) && } + {["queued", "running"].includes(deployment.status) && deployment.phase !== "verifying" && }
@@ -242,21 +243,23 @@ function ModalDeploymentDialog({ deployment, onCancel, onClose }: { deployment: const MODAL_WORKSPACE_STEPS = [ { id: "building", label: "Prepare CUDA image", detail: "Install and cache the GTSFM environment" }, { id: "deploying", label: "Deploy workspace", detail: "Publish the FastAPI workspace on Modal" }, - { id: "verifying", label: "Verify connection", detail: "Find the endpoint and check availability" }, + { id: "verifying", label: "Start & verify workspace", detail: "Cold-start the GPU and confirm the workspace API is healthy" }, ] as const; function ModalDeploymentProgress({ deployment, onCancel, onExpand }: { deployment: ModalDeployment; onCancel: () => void; onExpand: () => void }) { - const currentPhase = deployment.phase === "ready" ? "verifying" : deployment.phase ?? "building"; + const ready = deployment.phase === "ready"; + const verifying = deployment.phase === "verifying"; + const currentPhase = ready ? "verifying" : deployment.phase ?? "building"; const currentIndex = Math.max(0, MODAL_WORKSPACE_STEPS.findIndex((step) => step.id === currentPhase)); const imageDetail = deployment.image_source === "prebuilt" ? "Pull the versioned GTSFM runtime; no package installation" : "Install and cache the GTSFM environment"; return
-
{deployment.status === "completed" ? : deployment.status === "failed" ? : deployment.status === "cancelled" ? : }{deployment.stage}{deployment.image_source === "prebuilt" ? "PREBUILT" : "SOURCE"} · {deployment.gpu}{["queued", "running"].includes(deployment.status) && }
+
{ready ? : deployment.status === "failed" ? : deployment.status === "cancelled" ? : }{deployment.stage}{deployment.image_source === "prebuilt" ? "PREBUILT" : "SOURCE"} · {deployment.gpu}{["queued", "running"].includes(deployment.status) && !verifying && }
    {MODAL_WORKSPACE_STEPS.map((step, index) => { - const complete = deployment.status === "completed" || index < currentIndex; - const active = deployment.status !== "completed" && index === currentIndex; + const complete = ready || index < currentIndex; + const active = !ready && index === currentIndex; const failed = active && deployment.status === "failed"; const cancelled = active && deployment.status === "cancelled"; return
  1. @@ -265,10 +268,27 @@ function ModalDeploymentProgress({ deployment, onCancel, onExpand }: { deploymen
  2. ; })}
- {deployment.log_tail.length > 0 &&
{deployment.log_tail.slice(-4).join("\n")}
} +
LIVE SETUP LOGS
+
{deployment.log_tail.slice(-6).join("\n") || "Waiting for Modal setup output…"}
; } +type ModalWorkspaceReadiness = "idle" | "found" | "working" | "ready" | "attention"; + +function ModalWorkspaceStatus({ state, detail }: { state: ModalWorkspaceReadiness; detail: string }) { + const title = { + idle: "Workspace setup required", + found: "Modal workspace found", + working: "Preparing Modal workspace", + ready: "Modal workspace ready", + attention: "Workspace needs attention", + }[state]; + return
+ +
{title}{detail}
+
; +} + interface JobEvent { job: Job; live: LiveState; @@ -295,6 +315,7 @@ interface JobsResponse { interface LiveState { progress?: number; stage?: string; + message?: string; step?: number; max_steps?: number; loss?: number; @@ -364,7 +385,7 @@ interface FolderFile { interface ViewerApi { isBusy(): boolean; - loadSplatsFile(input: { splatsUrl: string; label: string }): Promise; + loadSplatsFile(input: { splatsUrl: string; label: string }): Promise; } declare global { @@ -877,6 +898,7 @@ function RunForm({ schema, hardware, samples, samplesLoading, onStarted, onTabCh const [modalDiscovering, setModalDiscovering] = useState(false); const [remoteChecking, setRemoteChecking] = useState(false); const [modalDeploying, setModalDeploying] = useState(false); + const [modalWorkspaceIssue, setModalWorkspaceIssue] = useState(false); const [modalDeployment, setModalDeployment] = useState(null); const [modalLogExpanded, setModalLogExpanded] = useState(false); const [advanced, setAdvanced] = useState(false); @@ -951,12 +973,38 @@ function RunForm({ schema, hardware, samples, samplesLoading, onStarted, onTabCh { id: "aws", label: "AWS EC2 — Coming Soon!", status: "coming-soon" }, ]; + const useDeployedModalWorkspace = (gpu: string) => { + const gpuInfo = MODAL_GPU_PRICING.find((item) => item.id === gpu); + const workspace: RemoteWorkspace = { + configuration: schema, + verified: false, + hardware: { + summary: `Modal ${gpu} workspace`, + devices: [{ + id: "cuda:0", + kind: "cuda", + label: `Modal ${gpu}`, + details: "NVIDIA CUDA GPU · starts with the first reconstruction", + memory: gpuInfo ? `${gpuInfo.memoryGiB} GB` : undefined, + supports_gaussian_splatting: true, + }], + }, + }; + setRemote(workspace); + set("remote_hardware", "cuda:0"); + return workspace; + }; + useEffect(() => { if (!modalGpuRecommendation) return; - setForm((current) => current.modal_gpu === modalGpuRecommendation.gpu.id - ? current - : { ...current, modal_gpu: modalGpuRecommendation.gpu.id }); - }, [modalGpuRecommendation?.gpu.id, modalRecommendationKey]); + if (form.modal_gpu === modalGpuRecommendation.gpu.id) return; + set("modal_gpu", modalGpuRecommendation.gpu.id); + if (form.remote_endpoint) { + setRemote(null); + setModalWorkspaceIssue(true); + setRemoteMessage("The dataset changed the recommended VM. Update the Modal workspace to apply it, then verify readiness."); + } + }, [modalGpuRecommendation?.gpu.id, modalRecommendationKey, form.modal_gpu, form.remote_endpoint]); useEffect(() => { setForm((current) => ({ @@ -975,7 +1023,13 @@ function RunForm({ schema, hardware, samples, samplesLoading, onStarted, onTabCh }, [form.execution_target, selectedSample, preparedSample?.path]); const updateModalCredential = (field: "modal_token_id" | "modal_token_secret", value: string) => { + modalDiscoverySequence.current += 1; + setModalDiscovering(false); + setRemoteChecking(false); const parsed = parseModalTokenCommand(value); + setRemote(null); + setModalWorkspaceIssue(false); + setRemoteMessage(""); if (parsed) { setForm((current) => ({ ...current, modal_token_id: parsed.tokenId, modal_token_secret: parsed.tokenSecret, modal_api_key: "" })); setModalTokenMessage("Token command parsed. Both fields are filled."); @@ -985,6 +1039,13 @@ function RunForm({ schema, hardware, samples, samplesLoading, onStarted, onTabCh setModalTokenMessage(""); }; + const updateModalGpu = (value: string) => { + set("modal_gpu", value); + setRemote(null); + setModalWorkspaceIssue(Boolean(form.remote_endpoint)); + setRemoteMessage("VM selection changed. Update the Modal workspace to apply it, then verify readiness."); + }; + useEffect(() => { if (form.execution_target !== "remote" || form.remote_connection !== "api" || form.remote_provider !== "modal") return; if (!form.modal_token_id.startsWith("ak-") || !form.modal_token_secret.startsWith("as-")) return; @@ -1006,9 +1067,14 @@ function RunForm({ schema, hardware, samples, samplesLoading, onStarted, onTabCh return { ...current, remote_endpoint: discovered.endpoint, modal_api_key: discovered.api_key }; }); automaticModalEndpoint.current = discovered.endpoint; - setRemoteMessage(`Found ${discovered.app_name} · ${discovered.function_name}. Endpoint filled automatically.`); + useDeployedModalWorkspace(form.modal_gpu); + setModalWorkspaceIssue(false); + setRemoteMessage(`Found ${discovered.app_name} · ${discovered.function_name}. Update it to this GTSFM version, or verify the existing workspace.`); } catch (reason) { - if (sequence === modalDiscoverySequence.current) setRemoteMessage(errorMessage(reason)); + if (sequence === modalDiscoverySequence.current) { + setModalWorkspaceIssue(true); + setRemoteMessage(errorMessage(reason)); + } } finally { if (sequence === modalDiscoverySequence.current) setModalDiscovering(false); } @@ -1020,14 +1086,14 @@ function RunForm({ schema, hardware, samples, samplesLoading, onStarted, onTabCh if (form.splat_implementation === "gsplat" && model && !capabilities.iterative_splat) set("splat_implementation", "none"); }, [form.splat_implementation, model, capabilities.iterative_splat]); - const inspectRemote = async (endpoint: string, apiKey: string) => { + async function inspectRemote(endpoint: string, apiKey: string) { const payload = await getJson("/api/remote/inspect", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ endpoint, api_key: apiKey, remote_provider: form.remote_provider }) }); - setRemote(payload); + setRemote({ ...payload, verified: true }); const gsDevice = payload.hardware.devices.find((item) => item.supports_gaussian_splatting); set("remote_hardware", gsDevice?.id ?? payload.hardware.devices[0]?.id ?? ""); return payload; - }; + } const connectRemote = async () => { if (form.remote_connection !== "api") { @@ -1039,12 +1105,16 @@ function RunForm({ schema, hardware, samples, samplesLoading, onStarted, onTabCh return; } setRemoteChecking(true); - setRemoteMessage("Connecting…"); + setModalWorkspaceIssue(false); + setRemote((current) => current ? { ...current, verified: false } : null); + setRemoteMessage("Checking the lightweight Modal control service…"); try { const payload = await inspectRemote(form.remote_endpoint, modalBearerToken(form)); - setRemoteMessage(`${payload.hardware.summary}. Modal connection is healthy and workspace options are up to date.`); + setModalWorkspaceIssue(false); + setRemoteMessage(`${payload.hardware.summary}. The control service is ready; the GPU stays off until you run a reconstruction.`); } catch (reason) { - setRemoteMessage(errorMessage(reason)); + setModalWorkspaceIssue(true); + setRemoteMessage(`Workspace check failed. Update the Modal workspace before running. ${errorMessage(reason)}`); } finally { setRemoteChecking(false); } @@ -1057,6 +1127,7 @@ function RunForm({ schema, hardware, samples, samplesLoading, onStarted, onTabCh } modalDiscoverySequence.current += 1; setModalDeploying(true); + setModalWorkspaceIssue(false); setRemote(null); setRemoteMessage(""); try { @@ -1084,11 +1155,48 @@ function RunForm({ schema, hardware, samples, samplesLoading, onStarted, onTabCh if (deployment.status === "failed") throw new Error(deployment.error || "Modal deployment failed"); automaticModalEndpoint.current = deployment.endpoint; setForm((current) => ({ ...current, remote_endpoint: deployment.endpoint, modal_api_key: deployment.api_key })); - setRemoteMessage("Workspace deployed. Loading its GPU and pipeline catalog…"); - const payload = await inspectRemote(deployment.endpoint, deployment.api_key); - setRemoteMessage(`${payload.hardware.summary}. Modal workspace is ready.`); + useDeployedModalWorkspace(deployment.gpu); + setModalDeployment({ + ...deployment, + status: "running", + phase: "verifying", + stage: "Starting and verifying the Modal workspace", + log_tail: [...deployment.log_tail, `Registered endpoint ${deployment.endpoint}`, "Checking the CPU control service; the GPU remains off until a run starts…"], + }); + setRemoteChecking(true); + try { + await inspectRemote(deployment.endpoint, deployment.api_key); + } catch (reason) { + const message = `Deployment finished, but the workspace health check failed: ${errorMessage(reason)}`; + setRemote((current) => current ? { ...current, verified: false } : null); + setModalWorkspaceIssue(true); + setModalDeployment({ + ...deployment, + status: "failed", + phase: "verifying", + stage: "Modal workspace needs an update", + error: message, + log_tail: [...deployment.log_tail, `Registered endpoint ${deployment.endpoint}`, message], + }); + throw new Error(message); + } finally { + setRemoteChecking(false); + } + setModalDeployment({ + ...deployment, + phase: "ready", + stage: "Modal workspace ready", + log_tail: [ + ...deployment.log_tail, + `Registered endpoint ${deployment.endpoint}`, + "Workspace health check passed. The Modal GPU is ready.", + ], + }); + setModalWorkspaceIssue(false); + setRemoteMessage(`Modal ${deployment.gpu} workspace passed its health check and is ready to run.`); } catch (reason) { const message = errorMessage(reason); + setModalWorkspaceIssue(true); setRemoteMessage(/Request failed \(404\)/.test(message) ? "This GTSFM server was started before Modal deployment support was installed. Stop it with Ctrl-C, run `gtsfm run` again, then click Deploy." : message); @@ -1142,6 +1250,9 @@ function RunForm({ schema, hardware, samples, samplesLoading, onStarted, onTabCh if (form.execution_target === "remote" && form.remote_connection === "ssh") { throw new Error("SSH execution is not available yet. Choose API to run on Modal."); } + if (form.execution_target === "remote" && form.remote_provider === "modal" && !remote?.verified) { + throw new Error("The Modal workspace must pass its health check before a reconstruction can start."); + } const payload = { ...form, api_key: form.execution_target === "remote" ? modalBearerToken(form) : "", loader_options: loaderOptions, hardware: form.execution_target === "remote" ? form.remote_hardware : form.hardware, max_resolution: form.max_resolution ? Number(form.max_resolution) : null, @@ -1155,6 +1266,33 @@ function RunForm({ schema, hardware, samples, samplesLoading, onStarted, onTabCh } catch (reason) { setError(errorMessage(reason)); } finally { setBusy(false); } }; + const modalWorkspaceSelected = form.execution_target === "remote" && form.remote_connection === "api" && form.remote_provider === "modal"; + const modalWorkspaceState: ModalWorkspaceReadiness = remote?.verified + ? "ready" + : modalDeploying || modalDiscovering || remoteChecking + ? "working" + : modalWorkspaceIssue + ? "attention" + : form.remote_endpoint + ? "found" + : "idle"; + const modalWorkspaceDetail = remoteMessage || { + idle: "Enter Modal credentials, then deploy or discover a workspace.", + found: "Choose Update to apply this GTSFM version, or verify the existing deployment.", + working: "Preparing the lightweight control service. The GPU starts only when a reconstruction runs.", + ready: "Health checks passed. Reconstruction can start.", + attention: "Update or verify this workspace before starting a run.", + }[modalWorkspaceState]; + const modalActionLabel = modalDeploying + ? modalDeployment?.phase === "verifying" ? "Starting & verifying Modal workspace…" : "Setting up Modal workspace…" + : modalDiscovering + ? "Finding Modal workspace…" + : remoteChecking + ? "Starting & verifying Modal workspace…" + : modalWorkspaceSelected && !remote?.verified + ? "Prepare Modal workspace first" + : "Run reconstruction"; + return
NEW RECONSTRUCTION {schemaLoading ? Syncing workspace options… @@ -1219,9 +1357,9 @@ function RunForm({ schema, hardware, samples, samplesLoading, onStarted, onTabCh { set("remote_provider", value); setRemote(null); }} /> {form.remote_provider === "modal" &&
M
ModalConnect with your Modal account token
AVAILABLE
- set("modal_gpu", value)} /> + { - if (modalGpuRecommendation) set("modal_gpu", modalGpuRecommendation.gpu.id); + if (modalGpuRecommendation) updateModalGpu(modalGpuRecommendation.gpu.id); }}/>

Enter the two values separately, or paste the complete modal token set --token-id … --token-secret … command into either field.

@@ -1230,12 +1368,17 @@ function RunForm({ schema, hardware, samples, samplesLoading, onStarted, onTabCh updateModalCredential("modal_token_secret", value)} autoComplete="new-password" spellCheck={false} placeholder="as-…" />
{modalTokenMessage &&
{modalTokenMessage}
} - set("remote_endpoint", value)} placeholder={modalDiscovering ? "Discovering your Modal endpoint…" : "Filled after credentials are verified"} /> + { + set("remote_endpoint", value); + setRemote(null); + setModalWorkspaceIssue(false); + setRemoteMessage("Endpoint changed. Start and verify this workspace before running."); + }} placeholder={modalDiscovering ? "Discovering your Modal endpoint…" : "Filled after credentials are verified"} /> {modalDeployment && setModalLogExpanded(true)}/>} {modalDeployment && modalLogExpanded && setModalLogExpanded(false)}/>} - {form.remote_endpoint && form.modal_api_key && } -
{remoteMessage}
+ {form.remote_endpoint && form.modal_api_key && } + {remote && set("remote_hardware", value)} />}
} :
@@ -1291,7 +1434,7 @@ function RunForm({ schema, hardware, samples, samplesLoading, onStarted, onTabCh
{error}
- + ; } @@ -1319,7 +1462,7 @@ function ActivityPanel({ jobs, activeId, onSelect, onCancel, onRefresh }: Activi
{job.name}{statusLabel(job.status)}
{displayName(job.spec.config_name || "GTSFM")} · {displayName(job.spec.splat_implementation || "no_splats")} {job.error &&

{job.error}

} -
+
{["queued", "running"].includes(job.status) && } {job.status === "completed" && !job.remote && View results} {job.remote?.workspace_url && Remote results ↗} @@ -1344,13 +1487,93 @@ interface StatusBarProps { onClose: () => void; } +interface StatusBarPosition { + left: number; + top: number; + width: number; +} + function StatusBar({ job, live, logsOpen, setLogsOpen, visible, onCancel, onClose }: StatusBarProps) { + const barRef = useRef(null); + const dragStart = useRef<{ + pointerX: number; + pointerY: number; + left: number; + top: number; + width: number; + maxLeft: number; + maxTop: number; + } | null>(null); + const [position, setPosition] = useState(null); + const [dragging, setDragging] = useState(false); + + useEffect(() => { + const bar = barRef.current; + const container = bar?.parentElement; + if (!bar || !container || typeof ResizeObserver === "undefined") return; + const keepInBounds = () => setPosition((current) => { + if (!current) return null; + const containerRect = container.getBoundingClientRect(); + const width = Math.min(current.width, containerRect.width); + const height = bar.getBoundingClientRect().height; + return { + left: Math.max(0, Math.min(containerRect.width - width, current.left)), + top: Math.max(0, Math.min(containerRect.height - height, current.top)), + width, + }; + }); + const observer = new ResizeObserver(keepInBounds); + observer.observe(container); + return () => observer.disconnect(); + }, []); + + const beginDrag = (event: React.PointerEvent) => { + if ((event.target as HTMLElement).closest("button, a, input, select")) return; + const bar = barRef.current; + const container = bar?.parentElement; + if (!bar || !container || event.button !== 0) return; + event.preventDefault(); + event.currentTarget.setPointerCapture(event.pointerId); + const barRect = bar.getBoundingClientRect(); + const containerRect = container.getBoundingClientRect(); + const start = { + pointerX: event.clientX, + pointerY: event.clientY, + left: barRect.left - containerRect.left, + top: barRect.top - containerRect.top, + width: barRect.width, + maxLeft: Math.max(0, containerRect.width - barRect.width), + maxTop: Math.max(0, containerRect.height - barRect.height), + }; + dragStart.current = start; + setPosition({ left: start.left, top: start.top, width: start.width }); + setDragging(true); + }; + + const moveDrag = (event: React.PointerEvent) => { + const start = dragStart.current; + if (!start) return; + setPosition({ + left: Math.max(0, Math.min(start.maxLeft, start.left + event.clientX - start.pointerX)), + top: Math.max(0, Math.min(start.maxTop, start.top + event.clientY - start.pointerY)), + width: start.width, + }); + }; + + const finishDrag = (event: React.PointerEvent) => { + if (!dragStart.current) return; + dragStart.current = null; + setDragging(false); + if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId); + }; + if (!job || !visible) return null; const progress = typeof live?.progress === "number" && Number.isFinite(live.progress) ? live.progress : job.status === "completed" ? 1 : 0; const loss = typeof live?.loss === "number" && Number.isFinite(live.loss) ? `loss ${live.loss.toFixed(4)}` : ""; const splatCount = typeof live?.splat_count === "number" && Number.isFinite(live.splat_count) ? `${live.splat_count.toLocaleString()} splats` : ""; - return
-
{job.name} · {statusLabel(job.status)}{job.error || (live?.stage === "gaussian_splatting" ? "Optimizing Gaussian splats" : "Running reconstruction pipeline")}
+ const style = position ? { left: position.left, top: position.top, width: position.width, right: "auto", bottom: "auto" } : undefined; + return
+
setPosition(null)}>
{job.name} · {statusLabel(job.status)}{job.error || (live?.stage === "gaussian_splatting" ? "Optimizing Gaussian splats" : "Running reconstruction pipeline")}
{live?.max_steps ? `${Number(live.step).toLocaleString()} / ${Number(live.max_steps).toLocaleString()} steps` : ""}{loss}{splatCount}
{job.has_final_splat && }{["queued", "running"].includes(job.status) && }
@@ -1378,6 +1601,8 @@ interface LogPanelGeometry { height: number; } +type LogResizeCorner = "nw" | "ne" | "sw" | "se"; + function LogPanel({ open, lines, onClose }: { open: boolean; lines: string[]; onClose: () => void }) { const panelRef = useRef(null); const copyReset = useRef(null); @@ -1430,7 +1655,7 @@ function LogPanel({ open, lines, onClose }: { open: boolean; lines: string[]; on window.addEventListener("pointercancel", finish, { once: true }); }; - const beginResize = (event: React.PointerEvent) => { + const beginResize = (corner: LogResizeCorner) => (event: React.PointerEvent) => { const panel = panelRef.current; const container = panel?.parentElement; if (!panel || !container) return; @@ -1446,13 +1671,27 @@ function LogPanel({ open, lines, onClose }: { open: boolean; lines: string[]; on top: panelRect.top - containerRect.top, right: panelRect.right - containerRect.left, bottom: panelRect.bottom - containerRect.top, + containerWidth: containerRect.width, + containerHeight: containerRect.height, }; setGeometry({ left: start.left, top: start.top, width: panelRect.width, height: panelRect.height }); const move = (moveEvent: PointerEvent) => { - const left = Math.max(0, Math.min(start.right - 300, start.left + moveEvent.clientX - start.pointerX)); - const top = Math.max(0, Math.min(start.bottom - 150, start.top + moveEvent.clientY - start.pointerY)); - setGeometry({ left, top, width: start.right - left, height: start.bottom - top }); + const dx = moveEvent.clientX - start.pointerX; + const dy = moveEvent.clientY - start.pointerY; + const left = corner.includes("w") + ? Math.max(0, Math.min(start.right - 300, start.left + dx)) + : start.left; + const right = corner.includes("e") + ? Math.min(start.containerWidth, Math.max(start.left + 300, start.right + dx)) + : start.right; + const top = corner.includes("n") + ? Math.max(0, Math.min(start.bottom - 150, start.top + dy)) + : start.top; + const bottom = corner.includes("s") + ? Math.min(start.containerHeight, Math.max(start.top + 150, start.bottom + dy)) + : start.bottom; + setGeometry({ left, top, width: right - left, height: bottom - top }); }; const finish = () => { window.removeEventListener("pointermove", move); @@ -1465,9 +1704,20 @@ function LogPanel({ open, lines, onClose }: { open: boolean; lines: string[]; on }; if (!open) return null; - const style = geometry ? { left: geometry.left, top: geometry.top, width: geometry.width, height: geometry.height, right: "auto", bottom: "auto" } : undefined; + const logFontSize = geometry + ? Math.max(8, Math.min(16, 9 + (geometry.width - 420) / 140 + (geometry.height - 240) / 120)) + : 9; + const style = geometry ? ({ + left: geometry.left, + top: geometry.top, + width: geometry.width, + height: geometry.height, + right: "auto", + bottom: "auto", + "--log-font-size": `${logFontSize}px`, + } as React.CSSProperties) : undefined; return
-
{lines.join("\n")}
; @@ -1544,9 +1794,26 @@ function DaskStats({ job, live }: { job: Job; live: LiveState | null }) { ; } +function pipelineStatusMessage(job: Job, live: LiveState | null): string { + if (live?.stage === "gaussian_splatting") { + const step = Number(live.step || 0); + const maxSteps = Number(live.max_steps || 0); + return maxSteps > 0 + ? `GTSFM: Optimizing Gaussian splats · ${step.toLocaleString()} / ${maxSteps.toLocaleString()} steps` + : "GTSFM: Initializing Gaussian optimization…"; + } + if (live?.message) return live.message; + if (job.status === "queued") return job.remote ? "Waiting for the Modal GPU worker…" : "Waiting for the reconstruction worker…"; + const latestStatus = [...(job.log_tail || [])].reverse().find((line) => /GTSFM|partition|VGGT|Gaussian|splat/i.test(line)); + return latestStatus?.replace(/^.*?\b(?:DEBUG|INFO|WARNING|ERROR|CRITICAL):\s*/, "") || "GTSFM: Preparing the reconstruction pipeline…"; +} + function Viewer({ activeJob, live, logsOpen, setLogsOpen, statusBarOpen, setStatusBarOpen, onCancelJob, setup, setupRefreshing, onRefreshSetup, onSetupChange }: ViewerProps) { const closeStatus = () => { setStatusBarOpen(false); setLogsOpen(false); }; - const showDaskStats = Boolean(activeJob && !activeJob.remote && ["queued", "running"].includes(activeJob.status)); + const showDaskStats = Boolean(activeJob && ["queued", "running"].includes(activeJob.status)); + const expectsSplats = Boolean(activeJob && (activeJob.spec.splat_implementation || "none") !== "none"); + const visualizationAvailable = Boolean(live?.preview_url || live?.final_url || activeJob?.has_final_splat); + const showPipelineWait = Boolean(activeJob && expectsSplats && ["queued", "running"].includes(activeJob.status) && !visualizationAvailable); return
Cameras0
Points0
Image—
Splats0
{showDaskStats && activeJob && }
@@ -1554,6 +1821,7 @@ function Viewer({ activeJob, live, logsOpen, setLogsOpen, statusBarOpen, setStat
setLogsOpen(false)} /> + {showPipelineWait && activeJob &&
RECONSTRUCTION IN PROGRESS{pipelineStatusMessage(activeJob, live)}The first live Gaussian preview will appear here automatically.
}
Loading…
; } @@ -1604,8 +1872,29 @@ function HardwareWarning({ hardware, onClose, onUseRemote }: { hardware: Hardwar ; } +const SIDEBAR_WIDTH_KEY = "gtsfm-studio-sidebar-width"; +const SIDEBAR_MIN_WIDTH = 320; +const SIDEBAR_MAX_WIDTH = 760; + +function constrainSidebarWidth(width: number): number { + const viewerRoom = Math.max(SIDEBAR_MIN_WIDTH, window.innerWidth - 360); + return Math.round(Math.min(SIDEBAR_MAX_WIDTH, viewerRoom, Math.max(SIDEBAR_MIN_WIDTH, width))); +} + +function storedSidebarWidth(): number { + try { + const saved = Number(window.localStorage.getItem(SIDEBAR_WIDTH_KEY)); + return constrainSidebarWidth(Number.isFinite(saved) && saved > 0 ? saved : 420); + } catch { + return 420; + } +} + function App() { const [sidebarCollapsed, setSidebarCollapsed] = useState(false); + const [sidebarWidth, setSidebarWidth] = useState(storedSidebarWidth); + const [sidebarResizing, setSidebarResizing] = useState(false); + const sidebarResizeStart = useRef<{ pointerX: number; width: number } | null>(null); const [tab, setTab] = useState(new URLSearchParams(location.search).get("view") === "results" ? "results" : "run"); const [schema, setSchema] = useState(BOOTSTRAP_SCHEMA); const [schemaLoading, setSchemaLoading] = useState(true); @@ -1622,9 +1911,52 @@ function App() { const [statusBarOpen, setStatusBarOpen] = useState(true); const [hardwareWarningDismissed, setHardwareWarningDismissed] = useState(false); const [remotePromptKey, setRemotePromptKey] = useState(0); + const [viewerLoadRequest, setViewerLoadRequest] = useState(0); const previewVersion = useRef(null); const finalLoaded = useRef(null); + const finishSidebarResize = useCallback(() => { + sidebarResizeStart.current = null; + setSidebarResizing(false); + document.body.classList.remove("sidebar-is-resizing"); + }, []); + + const startSidebarResize = (event: React.PointerEvent) => { + if (sidebarCollapsed || event.button !== 0) return; + event.preventDefault(); + sidebarResizeStart.current = { pointerX: event.clientX, width: sidebarWidth }; + event.currentTarget.setPointerCapture(event.pointerId); + setSidebarResizing(true); + document.body.classList.add("sidebar-is-resizing"); + }; + + const moveSidebarResize = (event: React.PointerEvent) => { + const start = sidebarResizeStart.current; + if (!start) return; + setSidebarWidth(constrainSidebarWidth(start.width + event.clientX - start.pointerX)); + }; + + const resizeSidebarWithKeyboard = (event: React.KeyboardEvent) => { + if (event.key === "ArrowLeft" || event.key === "ArrowRight") { + event.preventDefault(); + const direction = event.key === "ArrowRight" ? 1 : -1; + setSidebarWidth((current) => constrainSidebarWidth(current + direction * (event.shiftKey ? 40 : 10))); + } else if (event.key === "Home") { + event.preventDefault(); + setSidebarWidth(420); + } + }; + + useEffect(() => () => document.body.classList.remove("sidebar-is-resizing"), []); + useEffect(() => { + try { window.localStorage.setItem(SIDEBAR_WIDTH_KEY, String(sidebarWidth)); } catch { /* storage is optional */ } + }, [sidebarWidth]); + useEffect(() => { + const keepSidebarOnScreen = () => setSidebarWidth((current) => constrainSidebarWidth(current)); + window.addEventListener("resize", keepSidebarOnScreen); + return () => window.removeEventListener("resize", keepSidebarOnScreen); + }, []); + const refreshJobs = useCallback(async () => { try { const payload = await getJson("/api/jobs"); setJobs(payload.items || []); setActiveId((current) => current || payload.items?.find((job) => ["queued", "running"].includes(job.status))?.id || null); } catch (reason) { console.warn("Unable to refresh jobs", reason); } }, []); @@ -1679,37 +2011,69 @@ function App() { }, []); useEffect(() => { - if (!activeJob || activeJob.remote) { setLive(null); return; } + if (!activeJob) { setLive(null); return; } + setLive(null); const socket = new WebSocket(websocketUrl(`/api/events/jobs/${encodeURIComponent(activeJob.id)}`)); - socket.onmessage = async (event) => { + socket.onmessage = (event) => { const payload = JSON.parse(event.data) as JobEvent; setJobs((current) => current.map((job) => job.id === payload.job.id ? payload.job : job)); setLive(payload.live); + }; + return () => socket.close(); + }, [activeJob?.id]); + + useEffect(() => { + if (!activeJob || !live) return; + const finalKey = activeJob.status === "completed" && live.final_url ? `${activeJob.id}:${live.final_url}` : null; + const previewKey = live.preview_url ? `${activeJob.id}:${String(live.preview_version ?? live.preview_url)}` : null; + const desired = finalKey + ? { kind: "final" as const, key: finalKey, url: live.final_url as string, label: `${activeJob.name} · final` } + : previewKey + ? { kind: "preview" as const, key: previewKey, url: live.preview_url as string, label: `${activeJob.name} · live` } + : null; + if (!desired) return; + if (desired.kind === "final" && finalLoaded.current === desired.key) return; + if (desired.kind === "preview" && previewVersion.current === desired.key) return; + + let cancelled = false; + let retry: number | null = null; + let loadFailures = 0; + const tryLoad = async () => { + if (cancelled) return; const viewer = window.gtsfmViewer; - if (payload.live.preview_url && payload.live.preview_version !== previewVersion.current && viewer && !viewer.isBusy()) { - previewVersion.current = payload.live.preview_version ?? null; - await viewer.loadSplatsFile({ splatsUrl: payload.live.preview_url, label: `${payload.job.name} · live` }); + if (!viewer || viewer.isBusy()) { + retry = window.setTimeout(() => { void tryLoad(); }, 250); + return; } - if (payload.job.status === "completed" && payload.live.final_url && finalLoaded.current !== payload.job.id && viewer && !viewer.isBusy()) { - finalLoaded.current = payload.job.id; - await viewer.loadSplatsFile({ splatsUrl: payload.live.final_url, label: `${payload.job.name} · final` }); + const loaded = await viewer.loadSplatsFile({ splatsUrl: desired.url, label: desired.label }); + if (cancelled) return; + if (loaded === false) { + loadFailures += 1; + if (loadFailures < 3) retry = window.setTimeout(() => { void tryLoad(); }, 1200); + return; } + if (desired.kind === "final") finalLoaded.current = desired.key; + else previewVersion.current = desired.key; }; - return () => socket.close(); - }, [activeJob?.id]); + void tryLoad(); + return () => { + cancelled = true; + if (retry !== null) window.clearTimeout(retry); + }; + }, [activeJob?.id, activeJob?.status, live?.final_url, live?.preview_url, live?.preview_version, viewerLoadRequest]); const cancelJob = async (id: string) => { await fetch(`/api/jobs/${encodeURIComponent(id)}/cancel`, { method: "POST" }); await refreshJobs(); }; const activeCount = jobs.filter((job) => ["queued", "running"].includes(job.status)).length; const hasNvidiaSplatSupport = hardware?.devices.some((device) => device.supports_gaussian_splatting && (!device.status || device.status === "available")) ?? false; const showHardwareWarning = Boolean(hardware && !hasNvidiaSplatSupport && !hardwareWarningDismissed); const useRemoteVm = () => { setHardwareWarningDismissed(true); setTab("run"); setRemotePromptKey((current) => current + 1); }; - return
{showHardwareWarning && hardware && setHardwareWarningDismissed(true)} onUseRemote={useRemoteVm}/>}
; } const root = document.getElementById("root"); diff --git a/visualization/frontend/src/styles.css b/visualization/frontend/src/styles.css index 3d6fc5534..1b47e28cb 100644 --- a/visualization/frontend/src/styles.css +++ b/visualization/frontend/src/styles.css @@ -66,8 +66,8 @@ button { position: relative; z-index: 10; display: flex; - flex: 0 0 420px; - min-width: 360px; + flex: 0 0 var(--sidebar-width, 420px); + min-width: 320px; flex-direction: column; overflow: hidden; background: var(--paper); @@ -75,6 +75,50 @@ button { transition: flex-basis 180ms ease, min-width 180ms ease; } +#sidebar.sidebar-resizing { + transition: none; +} + +.sidebar-resize-handle { + position: absolute; + z-index: 20; + top: 0; + right: 0; + bottom: 0; + width: 9px; + touch-action: none; + cursor: col-resize; + outline: 0; +} + +.sidebar-resize-handle::after { + position: absolute; + top: 0; + right: 0; + bottom: 0; + width: 2px; + background: var(--accent); + content: ""; + opacity: 0; + transition: opacity 120ms ease; +} + +.sidebar-resize-handle:hover::after, +.sidebar-resize-handle:focus-visible::after, +.sidebar-resizing .sidebar-resize-handle::after { + opacity: 1; +} + +.sidebar-collapsed .sidebar-resize-handle { + display: none; +} + +body.sidebar-is-resizing, +body.sidebar-is-resizing * { + cursor: col-resize !important; + user-select: none !important; +} + #sidebar.sidebar-collapsed { flex-basis: 0; min-width: 0; @@ -167,8 +211,7 @@ button { backdrop-filter: blur(8px); } -.sidebar-collapsed + #main-content #sceneStats, -.sidebar-collapsed + #main-content .run-status-bar { +.sidebar-collapsed + #main-content #sceneStats { left: 103px; } @@ -996,6 +1039,41 @@ input[type="checkbox"] { white-space: pre-wrap; } +.modal-deployment .modal-log-preview-heading { + display: flex; + margin-top: 1px; + padding: 0 1px; + align-items: center; + justify-content: space-between; +} + +.modal-log-preview-heading > span { + color: var(--ink-faint); + font-family: "SFMono-Regular", Consolas, monospace; + font-size: 6px; + font-weight: 700; + letter-spacing: 0.11em; +} + +.modal-log-preview-heading button { + display: inline-flex; + min-height: 22px; + padding: 0 5px; + align-items: center; + gap: 4px; + border: 0; + background: transparent; + color: var(--ink-soft); + font-size: 7px; + font-weight: 650; + cursor: pointer; +} + +.modal-log-preview-heading button:hover { + background: #deded7; + color: var(--ink); +} + .modal-log-backdrop { position: fixed; z-index: 80; @@ -1093,6 +1171,82 @@ input[type="checkbox"] { display: none; } +.modal-workspace-status { + display: grid; + min-height: 50px; + margin: 0 0 10px; + padding: 9px 10px; + grid-template-columns: 24px minmax(0, 1fr); + align-items: center; + gap: 8px; + border: 1px solid var(--line-dark); + background: #eeeeea; +} + +.modal-workspace-status > span { + display: grid; + width: 23px; + height: 23px; + place-items: center; + border: 1px solid currentColor; + border-radius: 50%; + color: var(--ink-soft); +} + +.modal-workspace-status > div { + display: grid; + gap: 2px; +} + +.modal-workspace-status strong { + color: var(--ink); + font-size: 9px; + font-weight: 700; +} + +.modal-workspace-status small { + color: var(--ink-soft); + font-size: 8px; + line-height: 1.45; +} + +.modal-workspace-status.working { + border-color: #d8bd85; + background: #f8f2e7; +} + +.modal-workspace-status.working > span { + color: #8d681e; +} + +.modal-workspace-status.found { + border-color: #aebbc2; + background: #eef2f3; +} + +.modal-workspace-status.found > span { + color: #536d79; +} + +.modal-workspace-status.ready { + border-color: #9ac5af; + background: #edf5f0; +} + +.modal-workspace-status.ready > span { + color: var(--success); +} + +.modal-workspace-status.attention { + border-color: #d4a3a3; + background: #faf0ef; +} + +.modal-workspace-status.attention > span, +.modal-workspace-status.attention strong { + color: var(--danger); +} + .field-help { margin: -5px 0 12px; color: var(--ink-soft); @@ -2151,9 +2305,10 @@ input[type="checkbox"] { .run-status-bar { position: absolute; z-index: 8; - top: 18px; right: 18px; - left: 18px; + bottom: 68px; + left: auto; + width: min(720px, calc(100% - 36px)); display: grid; min-height: 61px; grid-template-columns: 1.2fr 1fr auto; @@ -2164,6 +2319,7 @@ input[type="checkbox"] { border: 1px solid #373a3c; background: rgba(19, 21, 23, 0.94); color: #ecece7; + cursor: grab; } .status-copy { @@ -2172,6 +2328,27 @@ input[type="checkbox"] { gap: 10px; } +.status-drag-handle { + min-width: 0; + cursor: grab; + touch-action: none; + user-select: none; +} + +.status-metrics, +.run-progress-track { + touch-action: none; + user-select: none; +} + +.run-status-bar.is-dragging .status-drag-handle { + cursor: grabbing; +} + +.run-status-bar.is-dragging { + cursor: grabbing; +} + .status-copy > div { display: flex; flex-direction: column; @@ -2658,6 +2835,81 @@ input[type="checkbox"] { /* Logs and loading */ +.pipeline-wait-overlay { + position: absolute; + z-index: 4; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + padding: 96px 28px 76px; + background: rgba(5, 6, 7, 0.42); + color: #ecece7; + pointer-events: none; + animation: pipeline-viewport-dim 2.6s ease-in-out infinite; +} + +.pipeline-wait-content { + display: grid; + width: min(560px, calc(100% - 48px)); + justify-items: center; + gap: 11px; + text-align: center; +} + +.pipeline-wait-content > span { + color: #858a89; + font: 650 8px/1.2 "SFMono-Regular", Consolas, monospace; + letter-spacing: 0.14em; +} + +.pipeline-wait-content strong { + max-width: 100%; + color: #f0f0eb; + font-size: clamp(15px, 2vw, 22px); + font-weight: 500; + line-height: 1.35; + text-wrap: balance; +} + +.pipeline-wait-content small { + color: #858a89; + font-size: 10px; +} + +.pipeline-wait-dots { + display: flex; + height: 6px; + align-items: center; + gap: 5px; +} + +.pipeline-wait-dots i { + display: block; + width: 3px; + height: 3px; + border-radius: 50%; + background: var(--accent); + animation: pipeline-dot 1.35s ease-in-out infinite; +} + +.pipeline-wait-dots i:nth-child(2) { + animation-delay: 160ms; +} + +.pipeline-wait-dots i:nth-child(3) { + animation-delay: 320ms; +} + +@keyframes pipeline-viewport-dim { + 50% { background-color: rgba(5, 6, 7, 0.57); } +} + +@keyframes pipeline-dot { + 0%, 70%, 100% { opacity: 0.22; transform: translateY(0); } + 35% { opacity: 1; transform: translateY(-2px); } +} + .hardware-warning { position: fixed; z-index: 30; @@ -2797,40 +3049,79 @@ input[type="checkbox"] { .log-resize-handle { position: absolute; - z-index: 2; - top: -1px; - left: -1px; + z-index: 4; width: 18px; height: 18px; border: 0; padding: 0; background: transparent; - cursor: nwse-resize; touch-action: none; } -.log-resize-handle::before, -.log-resize-handle::after { +.log-resize-handle::before { position: absolute; - top: 3px; - left: 3px; - background: #737879; + width: 8px; + height: 8px; + border-color: #737879; + border-style: solid; + border-width: 0; content: ""; } -.log-resize-handle::before { - width: 9px; - height: 1px; +.log-resize-handle.nw { + top: -1px; + left: -1px; + cursor: nwse-resize; } -.log-resize-handle::after { - width: 1px; - height: 9px; +.log-resize-handle.nw::before { + top: 4px; + left: 4px; + border-top-width: 1px; + border-left-width: 1px; } -.log-resize-handle:hover::before, -.log-resize-handle:hover::after { - background: var(--accent); +.log-resize-handle.ne { + top: -1px; + right: -1px; + cursor: nesw-resize; +} + +.log-resize-handle.ne::before { + top: 4px; + right: 4px; + border-top-width: 1px; + border-right-width: 1px; +} + +.log-resize-handle.sw { + bottom: -1px; + left: -1px; + cursor: nesw-resize; +} + +.log-resize-handle.sw::before { + bottom: 4px; + left: 4px; + border-bottom-width: 1px; + border-left-width: 1px; +} + +.log-resize-handle.se { + right: -1px; + bottom: -1px; + cursor: nwse-resize; +} + +.log-resize-handle.se::before { + right: 4px; + bottom: 4px; + border-right-width: 1px; + border-bottom-width: 1px; +} + +.log-resize-handle:hover::before { + border-color: var(--accent); } .log-header { @@ -2895,7 +3186,9 @@ input[type="checkbox"] { margin: 0; padding: 11px; color: #adb1af; - font: 9px/1.6 "SFMono-Regular", Consolas, monospace; + font-family: "SFMono-Regular", Consolas, monospace; + font-size: var(--log-font-size, 9px); + line-height: 1.6; cursor: text; user-select: text; white-space: pre-wrap; @@ -2950,7 +3243,7 @@ input[type="checkbox"] { @media (max-width: 900px) { #sidebar { - flex-basis: 380px; + flex-basis: var(--sidebar-width, 380px); } .status-metrics { @@ -2987,6 +3280,10 @@ input[type="checkbox"] { background: transparent; } + .sidebar-resize-handle { + display: none; + } + .sidebar-collapsed .studio-header { top: 10px; left: 10px; diff --git a/visualization/modal_app.py b/visualization/modal_app.py index 892db596b..214c930ea 100644 --- a/visualization/modal_app.py +++ b/visualization/modal_app.py @@ -53,7 +53,20 @@ } if RUNTIME_IMAGE: - image = modal.Image.from_registry(RUNTIME_IMAGE).entrypoint([]).env(RUNTIME_ENV) + image = ( + modal.Image.from_registry( + RUNTIME_IMAGE, + setup_dockerfile_commands=[ + # uv-created virtual environments intentionally omit pip, but + # Modal's legacy registry-image builder requires ``python -m + # pip`` while installing its runtime dependencies. + "RUN uv pip install --python /opt/gtsfm-venv/bin/python pip", + ], + ) + .entrypoint([]) + .env(RUNTIME_ENV) + .workdir("/root") + ) else: image = ( modal.Image.from_registry("nvidia/cuda:12.8.1-devel-ubuntu22.04", add_python="3.12") diff --git a/visualization/modal_deployment.py b/visualization/modal_deployment.py index adde4decc..945524a47 100644 --- a/visualization/modal_deployment.py +++ b/visualization/modal_deployment.py @@ -2,19 +2,18 @@ from __future__ import annotations -from collections.abc import Callable -from dataclasses import dataclass, field import hashlib import hmac import os -from pathlib import Path import signal import subprocess import sys import threading -from typing import Any import uuid - +from collections.abc import Callable +from dataclasses import dataclass, field +from pathlib import Path +from typing import Any SUPPORTED_MODAL_GPUS = { "T4", @@ -31,7 +30,7 @@ DEFAULT_MODAL_RUNTIME_IMAGE = "docker.io/su071301/gtsfm-modal-runtime:firstclass" -def modal_remote_api_key(token_id: str, token_secret: str) -> str: +def modal_workspace_api_key(token_id: str, token_secret: str) -> str: """Derive a stable app-specific key without exposing the Modal credentials.""" digest = hmac.new( @@ -241,7 +240,7 @@ def _run(self, deployment: ModalDeployment, source_root: Path) -> None: "GTSFM_MODAL_GPU": deployment.gpu, "GTSFM_MODAL_CPU": str(deployment.cpu), "GTSFM_MODAL_MEMORY_MB": str(deployment.memory_mb), - "GTSFM_REMOTE_API_KEY": modal_remote_api_key(deployment.token_id, deployment.token_secret), + "GTSFM_API_KEY": modal_workspace_api_key(deployment.token_id, deployment.token_secret), "GTSFM_SOURCE_ROOT": str(source_root), } ) @@ -287,7 +286,7 @@ def run_command() -> int: self._update( deployment, phase="deploying", - stage="Deploying the Modal web workspace", + stage="Deploying the Modal CPU control service", ) self._update(deployment, line=line) return process.wait() @@ -350,7 +349,7 @@ def run_command() -> int: self._mark_cancelled(deployment) return deployment.endpoint = discovered["endpoint"] - deployment.api_key = modal_remote_api_key(deployment.token_id, deployment.token_secret) + deployment.api_key = modal_workspace_api_key(deployment.token_id, deployment.token_secret) deployment.status = "completed" deployment.phase = "ready" deployment.stage = "Ready" diff --git a/visualization/runtime.py b/visualization/runtime.py index d1e8b6a15..891b79e80 100644 --- a/visualization/runtime.py +++ b/visualization/runtime.py @@ -2,36 +2,40 @@ from __future__ import annotations -import importlib.util import http.client +import importlib.util import json import os import platform import re import shutil import signal +import ssl import subprocess import sys import tarfile import tempfile import threading import time -import uuid import urllib.error import urllib.request -from functools import lru_cache -from urllib.parse import urljoin, urlparse +import uuid from dataclasses import dataclass, field from datetime import datetime, timezone +from functools import lru_cache from pathlib import Path from typing import Any, Mapping +from urllib.parse import urljoin, urlparse -import gtsfm +import certifi import yaml +import gtsfm PACKAGE_ROOT = Path(gtsfm.__file__).resolve().parent CONFIG_ROOT = PACKAGE_ROOT / "configs" +_SSL_CONTEXT = ssl.create_default_context(cafile=certifi.where()) +_REMOTE_REQUEST_TIMEOUT_SECONDS = 10 * 60 _RUN_NAME_PATTERN = re.compile(r"[^A-Za-z0-9._-]+") _OPTIONAL_SUBMODULES = { "submodule-anysplat": { @@ -463,10 +467,30 @@ def install_optional_setup(check_id: str, results_root: Path) -> dict[str, Any]: return {"item": item, "setup": status} +_CATALOG_YAML_NAME_PATTERN = re.compile(r"^[A-Za-z0-9_.-]+\.yaml$") + + +def _yaml_catalog_paths(folder: Path) -> list[Path]: + """Return canonical catalog YAMLs, excluding cloud/conflict copies. + + macOS cloud storage can create numbered copies such as ``vggt 2.yaml``. + Those files are not GTSFM configurations and may be dataless placeholders, + so attempting to read them can block the configuration endpoint indefinitely. + """ + + if not folder.exists(): + return [] + return sorted( + path + for path in folder.glob("*.yaml") + if not path.name.startswith("_") and _CATALOG_YAML_NAME_PATTERN.fullmatch(path.name) + ) + + def _yaml_stem_options(folder: Path) -> list[str]: if not folder.exists(): return [] - return sorted(path.stem for path in folder.glob("*.yaml") if not path.name.startswith("_")) + return [path.stem for path in _yaml_catalog_paths(folder)] def _display_name(value: str) -> str: @@ -508,7 +532,7 @@ def configuration_schema() -> dict[str, Any]: ) loader_options: dict[str, list[dict[str, Any]]] = {} standard_loader_fields = {"_target_", "dataset_dir", "images_dir", "max_resolution", "input_worker"} - for loader_path in sorted((CONFIG_ROOT / "loader").glob("*.yaml")): + for loader_path in _yaml_catalog_paths(CONFIG_ROOT / "loader"): data = yaml.safe_load(loader_path.read_text(encoding="utf-8")) or {} options: list[dict[str, Any]] = [] for name, value in data.items(): @@ -766,6 +790,8 @@ class ManagedJob: pid: int | None = None remote: dict[str, Any] | None = None remote_api_key: str | None = field(default=None, repr=False, compare=False) + remote_cancel_requested: bool = field(default=False, repr=False, compare=False) + remote_cancel_dispatched: bool = field(default=False, repr=False, compare=False) process: subprocess.Popen[str] | None = field(default=None, repr=False, compare=False) def public(self) -> dict[str, Any]: @@ -808,8 +834,12 @@ def get(self, job_id: str) -> ManagedJob | None: with self._lock: return self._jobs.get(job_id) - def start(self, spec: Mapping[str, Any]) -> dict[str, Any]: - job_id = uuid.uuid4().hex[:12] + def start(self, spec: Mapping[str, Any], *, job_id: str | None = None) -> dict[str, Any]: + """Start a pipeline, optionally using a caller-provided durable job ID.""" + + job_id = job_id or uuid.uuid4().hex[:12] + if not re.fullmatch(r"[A-Za-z0-9_-]{1,64}", job_id): + raise ValueError("Job ID contains unsupported characters") name = _normalise_run_name(spec.get("name")) run_root = self.results_root / "runs" / f"{name}-{job_id}" # Keep transient previews outside the results tree discovered by the viewer. @@ -881,7 +911,10 @@ def _remote_json(url: str, api_key: str, *, payload: dict[str, Any] | None = Non method="POST" if payload is not None else "GET", headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}, ) - with urllib.request.urlopen(request, timeout=120) as response: + # Allocating a Modal GPU and loading the CUDA runtime can take more than + # two minutes on the first request. Keep the socket open through that + # cold start instead of launching a second competing verification. + with urllib.request.urlopen(request, timeout=_REMOTE_REQUEST_TIMEOUT_SECONDS, context=_SSL_CONTEXT) as response: result = json.loads(response.read().decode("utf-8")) if not isinstance(result, dict): raise ValueError("Remote workspace returned an invalid response") @@ -893,7 +926,10 @@ def _remote_download(url: str, api_key: str, destination: Path) -> None: destination.parent.mkdir(parents=True, exist_ok=True) temporary = destination.with_suffix(f"{destination.suffix}.part") try: - with urllib.request.urlopen(request, timeout=300) as response, temporary.open("wb") as output: + with ( + urllib.request.urlopen(request, timeout=300, context=_SSL_CONTEXT) as response, + temporary.open("wb") as output, + ): shutil.copyfileobj(response, output) temporary.replace(destination) finally: @@ -930,7 +966,7 @@ def _remote_upload_directory(endpoint: str, api_key: str, directory: Path, runti parsed = urlparse(endpoint) if parsed.scheme == "https": connection: http.client.HTTPConnection = http.client.HTTPSConnection( - parsed.hostname, parsed.port or 443, timeout=3600 + parsed.hostname, parsed.port or 443, timeout=3600, context=_SSL_CONTEXT ) elif parsed.scheme == "http": connection = http.client.HTTPConnection(parsed.hostname, parsed.port or 80, timeout=3600) @@ -1003,6 +1039,9 @@ def _run_remote(self, job: ManagedJob) -> None: with self._lock: if job.status == "cancelled": return + job.status = "running" + job.updated_at = _utc_now() + job.log_tail.append("Starting the remote GPU workspace; the first run may take several minutes…") remote_spec["execution_target"] = "local" created = self._remote_json(f"{endpoint}/api/jobs", job.remote_api_key, payload=remote_spec) remote_id = str(created["id"]) @@ -1014,11 +1053,13 @@ def _run_remote(self, job: ManagedJob) -> None: "workspace_url": f"{endpoint}/?view=results", } ) + if cancelled: + job.log_tail.append("Modal accepted the job. Sending the pending cancellation request…") if not cancelled: job.status = str(created.get("status", "queued")) job.updated_at = _utc_now() if cancelled: - self._remote_json(f"{endpoint}/api/jobs/{remote_id}/cancel", job.remote_api_key, payload={}) + self._dispatch_remote_cancel(job, background=False) return preview_version: object = None remote_status = str(created.get("status", "queued")) @@ -1028,6 +1069,11 @@ def _run_remote(self, job: ManagedJob) -> None: remote_status = str(state.get("status", "running")) try: live = self._remote_json(f"{endpoint}/api/jobs/{remote_id}/live", job.remote_api_key) + live_path = Path(job.live_root) / "status.json" + live_path.parent.mkdir(parents=True, exist_ok=True) + live_temporary = live_path.with_suffix(".json.tmp") + live_temporary.write_text(json.dumps(live), encoding="utf-8") + live_temporary.replace(live_path) next_version = live.get("preview_version") preview_url = str(live.get("preview_url") or "") if preview_url and next_version != preview_version: @@ -1150,27 +1196,82 @@ def force_kill() -> None: threading.Thread(target=force_kill, daemon=True, name="gtsfm-job-cancel").start() + def _dispatch_remote_cancel(self, job: ManagedJob, *, background: bool) -> bool: + """Send one cancellation request to the remote workspace once its job ID exists.""" + + with self._lock: + remote = job.remote + remote_id = str(remote.get("job_id") or "") if remote else "" + if ( + not job.remote_cancel_requested + or job.remote_cancel_dispatched + or not remote + or not remote_id + or not job.remote_api_key + ): + return False + job.remote_cancel_dispatched = True + remote["cancel_status"] = "requested" + endpoint = str(remote["endpoint"]) + api_key = job.remote_api_key + + def send_cancel() -> None: + try: + self._remote_json(f"{endpoint}/api/jobs/{remote_id}/cancel", api_key, payload={}) + except (urllib.error.URLError, ValueError, TimeoutError) as exc: + with self._lock: + if job.remote is not None: + job.remote["cancel_status"] = "failed" + job.log_tail.append(f"Unable to confirm Modal cancellation: {exc}") + del job.log_tail[:-250] + job.updated_at = _utc_now() + else: + with self._lock: + if job.remote is not None: + job.remote["cancel_status"] = "confirmed" + job.log_tail.append("Modal job cancellation confirmed.") + del job.log_tail[:-250] + job.updated_at = _utc_now() + + if background: + threading.Thread( + target=send_cancel, + daemon=True, + name=f"gtsfm-remote-cancel-{job.id}", + ).start() + else: + send_cancel() + return True + def cancel(self, job_id: str) -> dict[str, Any]: with self._lock: job = self._jobs.get(job_id) if job is None: raise KeyError(job_id) - if job.status not in {"queued", "running"}: + if job.status not in {"queued", "running", "cancelled"}: return job.public() - job.status = "cancelled" - job.updated_at = _utc_now() + if job.status != "cancelled": + job.status = "cancelled" + job.updated_at = _utc_now() + job.log_tail.append("Cancellation requested.") process = job.process + if job.remote is not None: + job.remote_cancel_requested = True + if job.remote.get("job_id"): + job.remote["cancel_status"] = "requested" + else: + job.remote["cancel_status"] = "waiting_for_remote_job" + job.log_tail.append( + "Waiting for Modal to accept the starting job; it will be cancelled immediately afterward." + ) + del job.log_tail[:-250] if process is not None and process.poll() is None: self._terminate_process(process) - elif job.remote and job.remote.get("job_id") and job.remote_api_key: - try: - self._remote_json( - f"{job.remote['endpoint']}/api/jobs/{job.remote['job_id']}/cancel", - job.remote_api_key, - payload={}, - ) - except (urllib.error.URLError, ValueError): - pass + elif job.remote is not None: + # Do not make the browser wait on a network round-trip. If Modal is + # still cold-starting, _run_remote dispatches this as soon as the + # upstream job ID becomes available. + self._dispatch_remote_cancel(job, background=True) return job.public() def live_root(self, job_id: str) -> Path: diff --git a/visualization/samples.py b/visualization/samples.py index 43a30f23c..419d923c8 100644 --- a/visualization/samples.py +++ b/visualization/samples.py @@ -124,7 +124,9 @@ def _github_json(source_path: str) -> list[dict[str, Any]]: def _download_file(url: str, destination: Path) -> None: request = urllib.request.Request(url, headers={"User-Agent": "gtsfm-studio"}) destination.parent.mkdir(parents=True, exist_ok=True) - with urllib.request.urlopen(request, timeout=120, context=_SSL_CONTEXT) as response, destination.open("wb") as output: + with urllib.request.urlopen(request, timeout=120, context=_SSL_CONTEXT) as response, destination.open( + "wb" + ) as output: shutil.copyfileobj(response, output) diff --git a/visualization/static/studio.css b/visualization/static/studio.css index ab7c98ef9..5e122b870 100644 --- a/visualization/static/studio.css +++ b/visualization/static/studio.css @@ -1 +1 @@ -:root{--ink: #20211f;--ink-soft: #666761;--ink-faint: #96978f;--paper: #f4f4f0;--paper-raised: #fafaf7;--line: #d8d8d1;--line-dark: #c7c7bf;--viewport: #0e1012;--viewport-line: #2a2e31;--accent: #e45d37;--accent-dark: #c94825;--success: #3a8060;--danger: #b94b40;--control-height: 40px}*{box-sizing:border-box}html,body{height:100%}body{margin:0;overflow:hidden;background:var(--viewport);color:var(--ink);font-family:Inter,ui-sans-serif,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;font-size:13px;line-height:1.45;-webkit-font-smoothing:antialiased}#root,.app-shell{width:100%;height:100%}.app-shell{display:flex}button,input,select,textarea{font:inherit}button{color:inherit}.hidden{display:none!important}#sidebar{position:relative;z-index:10;display:flex;flex:0 0 420px;min-width:360px;flex-direction:column;overflow:hidden;background:var(--paper);border-right:1px solid #292b2d;transition:flex-basis .18s ease,min-width .18s ease}#sidebar.sidebar-collapsed{flex-basis:0;min-width:0;overflow:visible;border-right:0;background:transparent}.studio-header{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:79px;padding:12px 22px;border-bottom:1px solid var(--line)}.brand-logo{display:block;width:194px;max-width:100%;height:auto}.brand-primary{display:flex;min-width:0;align-items:center;gap:9px}.brand-mark{display:none;width:31px;height:31px;object-fit:contain}.sidebar-toggle{display:grid;width:31px;height:31px;flex:0 0 31px;place-items:center;border:1px solid var(--line-dark);border-radius:2px;padding:0;background:var(--paper-raised);color:var(--ink-soft);cursor:pointer}.sidebar-toggle:hover{border-color:var(--ink);color:var(--ink)}.sidebar-toggle:focus-visible{outline:1px solid var(--accent);outline-offset:2px}.sidebar-collapsed .studio-header{position:absolute;top:18px;left:18px;width:auto;min-height:0;gap:5px;justify-content:flex-start;padding:0;border:0;background:transparent}.sidebar-collapsed .brand-primary,.sidebar-collapsed .workspace-tabs{display:none}.sidebar-collapsed .brand-mark{display:block}.sidebar-collapsed .sidebar-toggle{border-color:#45494b;background:#131517e0;color:#d8d9d5;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}.sidebar-collapsed+#main-content #sceneStats,.sidebar-collapsed+#main-content .run-status-bar{left:103px}.studio-tabs{display:flex;min-height:43px;padding:0 22px;gap:24px;border-bottom:1px solid var(--line)}.studio-tab{position:relative;border:0;padding:0;background:transparent;color:var(--ink-soft);font-size:11px;font-weight:650;cursor:pointer}.studio-tab:after{position:absolute;right:0;bottom:-1px;left:0;height:2px;background:var(--ink);content:"";opacity:0}.studio-tab:hover,.studio-tab[data-state=active]{color:var(--ink)}.studio-tab:focus-visible,.target-choice:focus-visible,.primary-action:focus-visible,.secondary-action:focus-visible,.icon-button:focus-visible,.text-button:focus-visible,#hud button:focus-visible,.setup-panel button:focus-visible,.setup-reopen:focus-visible{outline:1px solid var(--accent);outline-offset:2px}.studio-tab[data-state=active]:after{opacity:1}#activeJobCount:not(:empty){display:inline-grid;min-width:17px;height:17px;margin-left:4px;place-items:center;border-radius:50%;background:var(--accent);color:#fff;font-size:9px}.studio-panel{display:none;min-height:0;flex:1;overflow-y:auto;padding:0 22px 30px;scrollbar-color:var(--line-dark) transparent;scrollbar-width:thin}.studio-panel[data-state=active]{display:block}.workspace-tabs{display:flex;min-height:0;flex:1;flex-direction:column}.studio-tab{display:flex;align-items:center;gap:5px}.panel-intro{position:relative;padding:22px 0 14px}.catalog-sync{position:absolute;top:21px;right:0;display:inline-flex;align-items:center;gap:5px;border:0;background:transparent;color:var(--ink-faint);font-family:SFMono-Regular,Consolas,monospace;font-size:8px;letter-spacing:.03em}.catalog-sync.failed{color:var(--danger);cursor:pointer}.panel-intro span,.mini-heading{color:var(--accent-dark);font-family:SFMono-Regular,Consolas,monospace;font-size:9px;font-weight:700;letter-spacing:.1em}.panel-intro p{margin:5px 0 0;color:var(--ink-soft);font-size:12px}.form-section{padding:20px 0 8px;border-top:1px solid var(--line)}.section-heading{display:grid;grid-template-columns:27px 1fr;align-items:start;margin-bottom:17px}.section-heading>div{display:flex;flex-direction:column}.section-heading strong{font-size:13px;font-weight:680}.section-heading small{margin-top:1px;color:var(--ink-faint);font-size:10px;font-weight:450}.step-number{padding-top:2px;color:var(--accent);font-family:SFMono-Regular,Consolas,monospace;font-size:9px;font-weight:700}#runForm label,.advanced-options label{display:block;margin:0 0 12px;color:#4f504c;font-size:10px;font-weight:680;letter-spacing:.01em}#runForm input:not([type=checkbox]),#runForm select,#runForm textarea,#filter{display:block;width:100%;min-height:var(--control-height);margin-top:5px;border:1px solid var(--line-dark);border-radius:2px;outline:none;background:var(--paper-raised);color:var(--ink);font-size:12px;font-weight:500;transition:border-color .12s ease,background .12s ease}#runForm input:not([type=checkbox]),#runForm select,#filter{padding:9px 10px}#runForm textarea{min-height:88px;padding:9px 10px;resize:vertical;font-family:SFMono-Regular,Consolas,monospace;font-size:10px}#runForm input:hover,#runForm select:hover,#runForm textarea:hover,#filter:hover{border-color:#a6a79f}#runForm input:focus,#runForm select:focus,#runForm textarea:focus,#filter:focus{border-color:var(--ink);background:#fff}#runForm input::placeholder,#runForm textarea::placeholder,#filter::placeholder{color:#aaa9a2}#runForm input:disabled,#runForm select:disabled,#filter:disabled{cursor:not-allowed;opacity:.55}select{appearance:none;padding-right:32px!important;background-image:linear-gradient(45deg,transparent 50%,#60615c 50%),linear-gradient(135deg,#60615c 50%,transparent 50%)!important;background-position:calc(100% - 14px) 17px,calc(100% - 10px) 17px!important;background-repeat:no-repeat!important;background-size:4px 4px,4px 4px!important;cursor:pointer}input[type=checkbox]{width:14px;height:14px;margin:0;accent-color:var(--accent)}.optional{float:right;color:var(--ink-faint);font-weight:450}.folder-field{position:relative;margin-bottom:13px}.folder-label{margin-bottom:5px;color:#4f504c;font-size:10px;font-weight:680;letter-spacing:.01em}.folder-drop{display:flex;width:100%;min-height:86px;align-items:center;gap:12px;padding:14px;border:1px dashed #b7b7ae;border-radius:3px;background:#f8f8f4;text-align:left;cursor:pointer;transition:border-color .12s ease,background .12s ease,box-shadow .12s ease}.folder-drop:hover,.folder-drop.dragging{border-color:var(--accent);background:#fff7f2;box-shadow:inset 3px 0 0 var(--accent)}.folder-drop.has-folder{border-style:solid;border-color:#b6c8bb;background:#f4f8f4}.folder-drop:disabled{cursor:wait;opacity:.7}.folder-icon{display:grid;width:34px;height:34px;flex:0 0 34px;place-items:center;border:1px solid var(--line-dark);border-radius:2px;background:var(--paper-raised);color:var(--accent)}.folder-drop.has-folder .folder-icon{border-color:#9eb6a5;color:var(--success)}.folder-copy{display:flex;min-width:0;flex-direction:column}.folder-copy strong{overflow:hidden;color:var(--ink);font-size:12px;font-weight:680;text-overflow:ellipsis;white-space:nowrap}.folder-copy small{margin-top:2px;color:var(--ink-faint);font-size:10px;font-weight:450}.folder-input{display:none!important}.folder-remove{display:block;margin:3px 0 0 auto;padding:1px 0;border:0;background:transparent;color:var(--ink-faint);font-size:9px;cursor:pointer}.folder-remove:hover{color:var(--danger)}.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:0 10px}.nested-options{margin:3px 0 12px;padding:13px 13px 1px;background:#ecece7;border-left:2px solid var(--accent)}.remote-vm-options{padding-bottom:12px}.provider-panel{margin:2px 0 0;padding:12px;border:1px solid #d2d2cb;background:var(--paper-raised)}.provider-heading{display:grid;grid-template-columns:30px minmax(0,1fr) auto;align-items:center;gap:9px;margin-bottom:14px}.provider-heading strong,.provider-heading small{display:block}.provider-heading strong{color:var(--ink);font-size:11px}.provider-heading small{margin-top:2px;color:var(--ink-soft);font-size:9px}.provider-mark{display:grid;width:30px;height:30px;place-items:center;border-radius:4px;background:#111;color:#7cf7c5;font-size:14px;font-weight:800}.provider-mark.ssh{background:#e7e7e1;color:var(--ink)}.provider-status{color:#287a5b;font-family:SFMono-Regular,Consolas,monospace;font-size:8px;font-weight:700;letter-spacing:.08em}.provider-status.soon{color:var(--ink-faint)}.modal-gpu-recommendation{display:grid;gap:6px;margin:-3px 0 10px;padding:11px 12px;border:1px solid #a9c4b4;border-left:2px solid var(--success);background:#f2f7f3}.modal-gpu-recommendation>div{display:flex;align-items:baseline;justify-content:space-between;gap:10px}.modal-gpu-recommendation span{color:#47715d;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;font-weight:700;letter-spacing:.11em}.modal-gpu-recommendation strong{color:#254d3a;font-size:11px;white-space:nowrap}.modal-gpu-recommendation p{margin:0;color:#5f6862;font-size:9px;line-height:1.45}.modal-gpu-recommendation small{display:flex;align-items:center;gap:5px;color:var(--success);font-size:8px;font-weight:650}.modal-gpu-recommendation button{width:max-content;border:0;padding:0;background:transparent;color:var(--accent-dark);font-size:8px;font-weight:700;text-decoration:underline;text-underline-offset:3px;cursor:pointer}.modal-gpu-recommendation.overridden{border-color:#d5b59d;border-left-color:var(--accent);background:#faf4ef}.modal-gpu-recommendation.empty{border-color:var(--line);border-left-color:var(--line-dark);background:#f2f2ed}.modal-gpu-recommendation.empty strong{color:var(--ink);font-size:10px}.modal-estimate{display:grid;margin:2px 0 14px;padding:13px;gap:7px;border:1px solid #323633;background:#171918;color:#eceee9}.modal-estimate-heading{display:flex;align-items:flex-end;justify-content:space-between;gap:12px}.modal-estimate-heading>div{display:grid;gap:3px}.modal-estimate-heading span{color:#6f7772;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;letter-spacing:.13em}.modal-estimate-heading strong{font-family:SFMono-Regular,Consolas,monospace;font-size:20px;font-weight:500;letter-spacing:-.04em}.modal-estimate-heading em{color:#9ea5a0;font-family:SFMono-Regular,Consolas,monospace;font-size:8px;font-style:normal;white-space:nowrap}.modal-estimate-bar{height:2px;overflow:hidden;background:#303431}.modal-estimate-bar span{display:block;height:100%;background:#68d8ab}.modal-estimate p,.modal-estimate small{margin:0}.modal-estimate p{color:#c2c6c2;font-size:9px}.modal-estimate small{color:#777e79;font-size:8px;line-height:1.45}.modal-estimate a{width:max-content;color:#8e9791;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;text-decoration:none}.modal-estimate a:hover{color:#68d8ab}.modal-estimate.empty{background:#f2f2ed;color:var(--ink);border-color:var(--line)}.modal-estimate.empty strong{font-size:10px}.modal-estimate.empty p{color:var(--ink-soft);line-height:1.45}.modal-command-help{margin-top:0}.credential-success{display:flex;align-items:center;gap:5px;margin:-4px 0 12px;color:#287a5b;font-size:9px;font-weight:650}.modal-deploy-action{display:inline-flex;min-height:36px;align-items:center;justify-content:center;gap:7px;margin-bottom:8px;border:1px solid #1f2924;background:#17241e;color:#dcebe3;font-size:9px;font-weight:650;cursor:pointer}.modal-deploy-action:hover:not(:disabled){border-color:#287a5b;background:#1b2c24}.modal-deploy-action:disabled{cursor:not-allowed;opacity:.45}.modal-deployment{display:grid;margin:0 0 8px;gap:7px;padding:9px;border:1px solid var(--line);background:#eeeee9}.modal-deployment>div,.modal-deployment>div>span{display:flex;align-items:center;gap:6px}.modal-deployment>div{justify-content:space-between}.modal-deployment-actions{flex:0 0 auto}.modal-deployment-actions button{display:grid;width:24px;height:24px;padding:0;place-items:center;border:0;background:transparent;color:var(--ink-soft);cursor:pointer}.modal-deployment-actions button:hover{background:#deded7;color:var(--ink)}.modal-deployment-actions .modal-stop-action{display:inline-flex;width:auto;padding:0 7px;align-items:center;gap:4px;color:var(--danger);font-size:7px;font-weight:700}.modal-deployment-steps{display:grid;margin:2px 0 1px;padding:0;gap:3px;list-style:none}.modal-deployment-steps li{display:grid;min-height:34px;padding:5px 7px;grid-template-columns:19px minmax(0,1fr);align-items:center;gap:7px;border:1px solid transparent;color:var(--ink-faint)}.modal-deployment-steps li>div{display:grid;gap:1px}.modal-deployment-steps li strong{color:inherit;font-size:8px;font-weight:680}.modal-deployment-steps li small{color:inherit;font-size:7px;line-height:1.35}.modal-step-mark{display:grid;width:18px;height:18px;place-items:center;border:1px solid var(--line-dark);border-radius:50%;font-family:SFMono-Regular,Consolas,monospace;font-size:7px}.modal-deployment-steps li[data-state=active]{border-color:#d8bd85;background:#f8f2e7;color:#725a28}.modal-deployment-steps li[data-state=active] .modal-step-mark{border-color:#b68b32;color:#8d681e}.modal-deployment-steps li[data-state=complete]{color:var(--success)}.modal-deployment-steps li[data-state=complete] .modal-step-mark{border-color:#8aaf98}.modal-deployment-steps li[data-state=failed]{border-color:#d4a3a3;background:#faf0ef;color:var(--danger)}.modal-deployment-steps li[data-state=failed] .modal-step-mark{border-color:var(--danger)}.modal-deployment-steps li[data-state=cancelled]{border-color:#b9b9b1;background:#e7e7e1;color:var(--ink-soft)}.modal-deployment strong,.modal-deployment small{font-size:8px}.modal-deployment.completed{border-color:#9ac5af}.modal-deployment.failed{border-color:#d4a3a3;color:var(--danger)}.modal-deployment.cancelling,.modal-deployment.cancelled{border-color:#b9b9b1;color:var(--ink-soft)}.modal-deployment pre{overflow:auto;max-height:74px;margin:0;padding:7px;background:#171918;color:#aeb5b0;font:7px/1.5 SFMono-Regular,Consolas,monospace;white-space:pre-wrap}.modal-log-backdrop{position:fixed;z-index:80;inset:0;display:grid;padding:32px;place-items:center;background:#090a0aad;-webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}.modal-log-dialog{display:flex;width:min(820px,calc(100vw - 64px));height:min(590px,calc(100vh - 64px));flex-direction:column;overflow:hidden;border:1px solid #4b504d;border-radius:3px;background:#111311;box-shadow:0 28px 80px #00000080;color:#e6e9e5}.modal-log-dialog header{display:flex;min-height:54px;padding:0 12px 0 16px;align-items:center;gap:12px;border-bottom:1px solid #343835}.modal-log-dialog header>div{display:grid;flex:1;gap:2px}.modal-log-dialog header span,.modal-log-dialog header small{color:#7c847e;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;letter-spacing:.1em;text-transform:uppercase}.modal-log-dialog header strong{font-size:11px;font-weight:600}.modal-log-dialog header button{display:inline-flex;min-height:29px;padding:0 8px;align-items:center;justify-content:center;gap:5px;border:0;background:transparent;color:#9fa5a1;font-size:8px;cursor:pointer}.modal-log-dialog header button:hover{background:#262a27;color:#f0f2ef}.modal-log-dialog header .modal-dialog-stop{color:#e28378}.modal-log-dialog pre{flex:1;overflow:auto;margin:0;padding:18px;color:#bbc2bc;font:10px/1.65 SFMono-Regular,Consolas,monospace;-webkit-user-select:text;user-select:text;white-space:pre-wrap}@media(max-width:640px){.modal-log-backdrop{padding:12px}.modal-log-dialog{width:calc(100vw - 24px);height:calc(100vh - 24px)}.modal-log-dialog header small{display:none}}.remote-message:empty{display:none}.field-help{margin:-5px 0 12px;color:var(--ink-soft);font-size:10px;line-height:1.5}.field-help code{font-family:SFMono-Regular,Consolas,monospace}.mini-heading{margin:1px 0 10px;color:var(--ink-soft)}.loader-options{margin:-3px 0 12px;padding:12px 12px 1px;background:#ecece7;border:1px solid var(--line)}.check-label{display:flex!important;align-items:center;gap:8px;min-height:26px;cursor:pointer}.segmented{display:grid;grid-template-columns:1fr 1fr;margin-bottom:13px;border:1px solid var(--line-dark);background:var(--paper-raised)}.input-source{margin-top:2px}.sample-picker{margin-bottom:13px}.sample-card{display:grid;grid-template-columns:32px minmax(0,1fr);gap:10px;margin:-4px 0 10px;padding:11px;border:1px solid var(--line);background:#ecece7}.sample-card.ready{border-color:#b6c8bb;background:#f4f8f4}.sample-state{display:grid;width:30px;height:30px;place-items:center;border:1px solid var(--line-dark);color:var(--accent)}.sample-card.ready .sample-state{border-color:#9eb6a5;color:var(--success)}.sample-card>div{display:flex;min-width:0;flex-direction:column}.sample-card strong{font-size:11px}.sample-card small{margin-top:1px;color:var(--ink-soft);font-size:9px;line-height:1.45}.sample-card div>span{margin-top:5px;color:var(--ink-faint);font-family:SFMono-Regular,Consolas,monospace;font-size:8px}.sample-card a{color:var(--ink-soft);text-underline-offset:2px}.sample-help{margin-top:0}.target-choice{display:flex;min-height:36px;align-items:center;justify-content:center;gap:6px;border:0;background:transparent;color:var(--ink-soft);font-size:10px;font-weight:680;cursor:pointer}.target-choice+.target-choice{border-left:1px solid var(--line-dark)}.target-choice.active{background:var(--ink);color:#fff}.hardware-card{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:2px 10px;margin:-4px 0 11px;padding:10px;border:1px solid var(--line);background:#ecece7}.hardware-card strong{overflow:hidden;font-size:11px;text-overflow:ellipsis;white-space:nowrap}.hardware-card small{grid-row:2;overflow:hidden;color:var(--ink-soft);font-size:9px;text-overflow:ellipsis;white-space:nowrap}.capability{grid-column:2;grid-row:1 / span 2;align-self:center;padding:3px 6px;border:1px solid var(--line-dark);color:var(--ink-soft);font-family:SFMono-Regular,Consolas,monospace;font-size:8px;font-weight:700;letter-spacing:.04em;text-transform:uppercase}.capability.yes{border-color:#8aaf98;color:var(--success)}.advanced-options{margin:13px 0 16px;padding-top:14px;border-top:1px solid var(--line)}.advanced-trigger{display:flex;width:100%;align-items:center;justify-content:space-between;border:0;padding:0 0 13px;background:transparent;color:var(--ink-soft);font-size:10px;font-weight:680;cursor:pointer}.advanced-trigger>span,.secondary-action{display:flex;align-items:center;justify-content:center;gap:6px}.advanced-trigger-copy{display:grid;gap:1px;text-align:left}.advanced-trigger-copy small{color:var(--ink-faint);font-family:SFMono-Regular,Consolas,monospace;font-size:7px;font-weight:500}.advanced-trigger[data-state=open]>svg{transform:rotate(180deg)}.advanced-content{overflow:hidden}.machine-profile-summary{display:grid;gap:7px;margin:0 0 14px;padding:11px 12px;border:1px solid var(--line);border-left:2px solid var(--accent);background:#eeeeea}.machine-profile-summary>div:first-child{display:flex;align-items:baseline;justify-content:space-between;gap:10px}.machine-profile-summary>div:first-child span{color:var(--ink-faint);font-family:SFMono-Regular,Consolas,monospace;font-size:7px;letter-spacing:.1em}.machine-profile-summary strong{overflow:hidden;font-size:10px;text-overflow:ellipsis;white-space:nowrap}.machine-profile-summary p,.advanced-machine-note{margin:0;color:var(--ink-soft);font-size:9px;line-height:1.45}.machine-profile-specs{display:flex;flex-wrap:wrap;gap:5px}.machine-profile-specs span{padding:3px 6px;border:1px solid var(--line-dark);background:var(--paper-raised);color:#555752;font-family:SFMono-Regular,Consolas,monospace;font-size:7px}.advanced-machine-note{margin:-5px 0 13px}.toggle-row{display:flex;min-height:31px;align-items:center;gap:9px;margin:0 0 10px}.toggle-row.disabled{opacity:.48}.toggle-row label{margin:0!important;cursor:pointer}.switch-root{position:relative;width:28px;height:16px;flex:0 0 28px;border:0;border-radius:999px;padding:0;background:#b9b9b2;cursor:pointer}.switch-root[data-state=checked]{background:var(--accent)}.switch-thumb{display:block;width:12px;height:12px;border-radius:50%;background:#fff;transform:translate(2px);transition:transform .12s ease}.switch-thumb[data-state=checked]{transform:translate(14px)}.primary-action{display:flex;width:100%;min-height:43px;align-items:center;justify-content:space-between;border:1px solid var(--ink);border-radius:0;padding:0 14px;background:var(--ink);color:#fff;font-size:11px;font-weight:680;cursor:pointer;transition:background .12s ease,border-color .12s ease}.primary-action:hover{border-color:var(--accent-dark);background:var(--accent-dark)}.spin{animation:spin .9s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.panel-loading{display:flex;align-items:center;gap:8px;padding:36px 0;color:var(--ink-soft);font-size:11px}.panel-loading.failed{align-items:flex-start;color:var(--danger)}.panel-loading.failed>div{display:grid;flex:1;gap:3px}.panel-loading.failed strong,.panel-loading.failed small{display:block}.panel-loading.failed small{color:var(--ink-soft);line-height:1.4}.hardware-card.detecting{display:flex;min-height:54px;align-items:center;gap:10px}.hardware-card.detecting>div{display:grid;gap:3px}.primary-action:disabled{cursor:wait;opacity:.55}.form-error{min-height:18px;margin:4px 0 8px;color:var(--danger);font-size:10px}.secondary-action,.icon-button{border:1px solid var(--line-dark);border-radius:2px;background:var(--paper-raised);color:var(--ink);font-size:10px;font-weight:650;cursor:pointer}.secondary-action{padding:7px 10px}.secondary-action:hover,.icon-button:hover{border-color:var(--ink)}.secondary-action.full-width{width:100%;margin:2px 0 10px}.panel-title{display:flex;align-items:center;justify-content:space-between;margin:22px 0 17px}.panel-title h3{margin:0;font-size:18px;font-weight:680;letter-spacing:-.035em}.panel-title p{margin:2px 0 0;color:var(--ink-soft);font-size:10px}.icon-button{width:31px;height:31px}.job-list{display:flex;flex-direction:column;gap:8px}.job-card{padding:12px;border:1px solid var(--line);background:var(--paper-raised)}.job-card.selected{border-left:2px solid var(--accent)}.job-card-top{display:flex;justify-content:space-between;gap:8px}.job-card strong{font-size:12px}.job-card>small{color:var(--ink-soft);font-size:9px}.job-status{color:var(--ink-soft);font-family:SFMono-Regular,Consolas,monospace;font-size:8px;font-weight:700;letter-spacing:.04em;text-transform:uppercase}.job-status.running,.job-status.queued{color:#a85523}.job-status.completed{color:var(--success)}.job-status.failed,.job-status.cancelled,.job-error{color:var(--danger)}.job-actions{display:flex;gap:12px;margin-top:9px}.job-card>.splat-download{margin-top:10px}.text-button{display:inline-flex;align-items:center;gap:4px;border:0;padding:0;background:none;color:var(--ink);font-size:9px;font-weight:700;text-decoration:underline;text-decoration-color:var(--line-dark);text-underline-offset:3px;cursor:pointer}.text-button.danger{color:var(--danger)}.job-error{margin:6px 0;font-size:9px}.empty-state{display:flex;align-items:center;justify-content:center;flex-direction:column;gap:5px;padding:42px 16px;border:1px dashed var(--line-dark);color:var(--ink-faint);font-size:11px;text-align:center}.empty-state strong{color:var(--ink);font-size:11px}.empty-state span{font-size:10px}#resultsPanel #info{margin-bottom:12px}#resultsPanel #filter{margin:0 0 12px}#resultsPanel #sceneList{min-height:200px}#info{display:flex;align-items:center;gap:12px;padding:11px;border:1px solid var(--line);background:var(--paper-raised)}#info .info-pill{display:grid;width:39px;height:39px;flex:0 0 39px;place-items:center;background:var(--ink);color:#fff;font-family:SFMono-Regular,Consolas,monospace;font-size:12px;font-weight:700}#info .info-details{min-width:0}#info .info-title{font-size:11px;font-weight:680}#info .info-path{overflow:hidden;margin-top:2px;color:var(--ink-soft);font-family:SFMono-Regular,Consolas,monospace;font-size:8px;text-overflow:ellipsis;white-space:nowrap}#info.info-error{border-color:#d5a29d}#info.info-error .info-pill{background:var(--danger)}#sceneList{margin:0 -6px;overflow-y:auto}#sceneList.is-disabled{pointer-events:none;opacity:.45}#sceneList ul{margin:3px 0;padding-left:15px;list-style:none}.directory-node{display:flex;width:100%;min-height:30px;align-items:center;gap:7px;border:0;padding:6px;background:transparent;color:var(--ink);font-size:11px;font-weight:680;text-align:left;cursor:pointer}.directory-node:hover{background:#eeeee9}.directory-node:focus-visible{outline:1px solid var(--accent);outline-offset:-1px}.directory-chevron{width:6px;height:6px;flex:0 0 6px;border-right:1px solid var(--ink-faint);border-bottom:1px solid var(--ink-faint);transform:rotate(45deg) translate(-1px,-1px);transition:transform .12s ease}.directory-branch.is-collapsed>.directory-node .directory-chevron{transform:rotate(-45deg)}.directory-branch.is-collapsed>ul{display:none}.item{margin-bottom:1px;padding:7px 8px;border-left:2px solid transparent;cursor:pointer}.item:hover{background:#e9e9e4}.item.active{border-left-color:var(--accent);background:#e6e5df}.item div{overflow:hidden;color:var(--ink);font-size:11px;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.item small{display:block;overflow:hidden;color:var(--ink-soft);font-size:9px;text-overflow:ellipsis;white-space:nowrap}.item .result-splat-download{display:flex;margin-top:7px}.result-splat-download .splat-format-label{display:grid;width:61px;min-height:27px;place-items:center;border:1px solid var(--line-dark);border-right:0;border-radius:2px 0 0 2px;padding:4px 7px;background-color:var(--paper-raised);color:var(--ink);font:8px SFMono-Regular,Consolas,monospace}.result-splat-download a{display:grid;min-width:65px;place-items:center;border:1px solid var(--line-dark);border-radius:0 2px 2px 0;padding:0 7px;color:var(--ink);font-size:8px;font-weight:650;text-decoration:none}.result-splat-download a:hover{border-color:var(--ink)}#main-content{position:relative;min-width:0;flex:1;overflow:hidden;background:var(--viewport)}#renderCanvas{display:block;width:100%;height:100%;outline:none}.setup-panel,.setup-reopen{position:absolute;z-index:9;top:18px;right:18px}.setup-panel.with-active-job,.setup-reopen.with-active-job{top:91px}.setup-panel{width:318px;overflow:hidden;border:1px solid #404346;border-radius:2px;background:#131517f5;box-shadow:0 12px 32px #0000003d;color:#e8e8e3;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px)}.setup-panel.collapsed{width:238px}.setup-panel-header{display:grid;min-height:52px;grid-template-columns:20px 1fr auto;align-items:center;gap:9px;padding:9px 8px 9px 12px}.setup-overall-icon{display:grid;width:20px;height:20px;place-items:center;color:#d69a52}.setup-overall-icon.ready{color:#6fa484}.setup-overall-icon.error{color:#d16b61}.setup-panel-copy{display:flex;min-width:0;flex-direction:column}.setup-panel-copy>span{color:#767b7d;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;font-weight:700;letter-spacing:.13em}.setup-panel-copy strong{overflow:hidden;margin-top:1px;font-size:11px;font-weight:650;text-overflow:ellipsis;white-space:nowrap}.setup-panel-actions{display:flex;align-items:center}.setup-panel-actions button,.setup-reopen{display:grid;width:27px;height:27px;place-items:center;border:0;padding:0;background:transparent;color:#8d9192;cursor:pointer}.setup-panel-actions button:hover,.setup-reopen:hover{background:#2b2e30;color:#f0f0eb}.setup-panel-actions button:disabled{cursor:wait;opacity:.5}.setup-panel-body{max-height:min(560px,calc(100vh - 92px));overflow-y:auto;border-top:1px solid #34373a;scrollbar-color:#44484a transparent;scrollbar-width:thin}.setup-summary-line{display:flex;justify-content:space-between;gap:10px;padding:8px 12px;border-bottom:1px solid #2f3234;color:#777c7d;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;letter-spacing:.04em;text-transform:uppercase}.setup-panel ul{margin:0;padding:4px 0;list-style:none}.setup-panel li{display:grid;grid-template-columns:18px 1fr;gap:7px;padding:7px 12px}.setup-check-content{min-width:0}.setup-check-mark{display:grid;width:16px;height:16px;margin-top:1px;place-items:center;border:1px solid #44484a;border-radius:50%;color:#6fa484}.setup-panel li[data-state=error] .setup-check-mark{border-color:#804f4a;color:#d16b61}.setup-panel li[data-state=optional] .setup-check-mark,.setup-panel li[data-state=warning] .setup-check-mark{border-color:#484c4e;color:transparent}.setup-panel li[data-state=optional] .setup-check-mark>span,.setup-panel li[data-state=warning] .setup-check-mark>span{width:4px;height:4px;border-radius:50%;background:#686d6f}.setup-check-title{display:flex;align-items:center;justify-content:space-between;gap:8px}.setup-check-tools{display:flex;flex:0 0 auto;align-items:center;gap:6px}.setup-check-title strong{color:#dadbd6;font-size:10px;font-weight:620}.setup-check-title em{color:#686d6f;font-family:SFMono-Regular,Consolas,monospace;font-size:6px;font-style:normal;letter-spacing:.08em;text-transform:uppercase}.setup-check-title .setup-install{display:flex;min-height:21px;align-items:center;justify-content:center;gap:4px;border:1px solid #505456;border-radius:2px;padding:2px 6px;background:#25282a;color:#d7d8d3;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;font-weight:650;cursor:pointer;white-space:nowrap}.setup-check-title .setup-install:hover:not(:disabled){border-color:#777b7d;background:#303335;color:#fff}.setup-check-title .setup-install:disabled{cursor:not-allowed;opacity:.45}.setup-panel li small{display:block;margin-top:1px;color:#777c7d;font-size:8px;line-height:1.35}.setup-panel li[data-state=error] small{color:#b87a74}.setup-panel li small.setup-action-error{color:#d9877f}.setup-loading{display:flex;align-items:center;gap:8px;padding:15px 12px;color:#8c9092;font-size:9px}.setup-reopen{width:34px;height:34px;border:1px solid #404346;border-radius:2px;background:#131517f0;box-shadow:0 8px 22px #0003}.run-status-bar{position:absolute;z-index:8;top:18px;right:18px;left:18px;display:grid;min-height:61px;grid-template-columns:1.2fr 1fr auto;grid-template-rows:auto 2px;align-items:center;gap:8px 16px;padding:11px 12px 9px;border:1px solid #373a3c;background:#131517f0;color:#ecece7}.status-copy{display:flex;align-items:center;gap:10px}.status-copy>div{display:flex;flex-direction:column}.status-copy strong{font-size:11px}.status-copy small{color:#8c9092;font-size:9px}.status-dot{width:7px;height:7px;background:var(--accent);animation:statusPulse 1.5s ease-in-out infinite}.run-status-bar[data-status=completed] .status-dot{background:#6da17f;animation:none}.run-status-bar[data-status=failed] .status-dot,.run-status-bar[data-status=cancelled] .status-dot{background:#cb6258;animation:none}@keyframes statusPulse{50%{opacity:.35}}.status-metrics{display:flex;justify-content:flex-end;gap:13px;color:#a3a6a5;font-family:SFMono-Regular,Consolas,monospace;font-size:8px;font-variant-numeric:tabular-nums}.run-progress-track{grid-column:1 / 4;height:2px;overflow:hidden;background:#343739}.run-progress-fill{width:100%;height:100%;background:var(--accent);transition:transform .4s ease}.run-status-bar .secondary-action{border-color:#484c4e;background:transparent;color:#d1d2cd}.run-status-bar .secondary-action.stop-process{border-color:#744843;color:#e79289}.run-status-bar .secondary-action.stop-process:hover{border-color:#a95a52;background:#b94b4021;color:#ffb0a8}.status-actions{display:flex;align-items:center;gap:4px}.splat-download{display:flex;align-items:stretch;min-height:31px}.splat-download .splat-format-label{display:grid;width:62px;min-height:31px;place-items:center;border:1px solid #484c4e;border-right:0;border-radius:2px 0 0 2px;padding:5px 7px;background-color:transparent;color:#d1d2cd;font-family:SFMono-Regular,Consolas,monospace;font-size:8px}.splat-download a{display:flex;min-width:76px;align-items:center;justify-content:center;gap:5px;border:1px solid #484c4e;border-radius:0 2px 2px 0;padding:0 8px;color:#d1d2cd;font-size:9px;font-weight:650;text-decoration:none}.splat-download a:hover{border-color:#707476;color:#fff}.splat-download.compact{width:fit-content;min-height:27px}.splat-download.compact .splat-format-label{min-height:27px;border-color:var(--line-dark);background-color:var(--paper-raised);color:var(--ink)}.splat-download.compact a{min-width:31px;border-color:var(--line-dark);color:var(--ink)}.status-close{display:grid;width:31px;height:31px;place-items:center;border:1px solid #484c4e;border-radius:2px;padding:0;background:transparent;color:#8e9293;cursor:pointer}.status-close:hover{border-color:#707476;color:#f0f0eb}.status-close:focus-visible{outline:1px solid var(--accent);outline-offset:2px}#hud{position:absolute;z-index:5;right:58px;bottom:18px;display:flex;align-items:center;gap:1px;padding:4px;border:1px solid #383b3e;background:#131517eb;color:#b9bcba;font-size:9px}.viewport-github{position:absolute;z-index:6;right:18px;bottom:18px;display:grid;width:31px;height:31px;place-items:center;border:1px solid #414547;border-radius:2px;background:#131517eb;color:#d3d4d0;text-decoration:none;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}.viewport-github:hover{border-color:#767a7c;color:#fff}.viewport-github:focus-visible{outline:1px solid var(--accent);outline-offset:2px}#hud button{display:flex;height:30px;align-items:center;justify-content:center;gap:5px;min-width:0;border:0;padding:0 10px;background:transparent;color:#d3d4d0;font-size:9px;font-weight:620;cursor:pointer;white-space:nowrap}#hud button:hover,#hud button.is-active{background:#303335;color:#fff}#hud label{display:flex;align-items:center;gap:6px;min-height:30px;padding:0 8px;border-left:1px solid #343739;white-space:nowrap}#hud .background-control{gap:7px;border-left:0}#hud .background-control select{width:82px;min-height:24px;border:1px solid #3f4345;border-radius:1px;padding:3px 22px 3px 7px!important;outline:none;background-color:#232628;background-position:calc(100% - 11px) 10px,calc(100% - 7px) 10px!important;color:#e2e3de;font-size:9px}#hud .background-control select:hover,#hud .background-control select:focus{border-color:#676b6d}#hud input[type=range]{width:90px;accent-color:var(--accent)}#hud .plane-height-control{min-width:190px}#hud .plane-height-control input[type=range]{width:112px}#groundYValue{min-width:25px;color:#e4e5df;font-family:SFMono-Regular,Consolas,monospace;font-size:8px;text-align:right}#hud input[type=checkbox]{accent-color:var(--accent)}#hud.hud-splat-mode .hud-scene-only,.hud-hidden{display:none!important}#sceneStats{position:absolute;z-index:6;top:18px;left:18px;display:grid;min-width:178px;gap:8px;padding:12px;border:1px solid #383b3e;background:#131517eb;color:#e5e5df}#sceneStats .stat-group[data-mode=scene]{display:grid;grid-template-columns:1fr 1fr;gap:9px 15px}#sceneStats .stat-group[data-mode=splat]{display:none}#sceneStats .stat-wide{grid-column:1 / 3}#sceneStats .stat-pair,#sceneStats .stat-wide{display:flex;flex-direction:column}#sceneStats .label{color:#747879;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;letter-spacing:.12em;text-transform:uppercase}#sceneStats .value{overflow:hidden;color:#e6e6e1;font-family:SFMono-Regular,Consolas,monospace;font-size:12px;font-weight:600;text-overflow:ellipsis;white-space:nowrap}#sceneStats .stat-wide .value{max-width:240px}#sceneStats.dask-active{width:226px}.dask-stats{display:grid;padding-top:11px;gap:11px;border-top:1px solid #34383a;animation:dask-stats-expand .18s ease-out;transform-origin:top}@keyframes dask-stats-expand{0%{opacity:0;transform:scaleY(.75) translateY(-5px)}to{opacity:1;transform:scaleY(1) translateY(0)}}.dask-stats-heading,.dask-memory>div:first-child{display:flex;align-items:flex-end;justify-content:space-between;gap:10px}.dask-stats-heading>div{display:grid;gap:3px}.dask-stats-heading span,.dask-memory span,.dask-stat-grid span{color:#747879;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;letter-spacing:.12em;text-transform:uppercase}.dask-stats-heading strong{font-size:11px;font-weight:600}.dask-stats-heading a{color:#9ba09f;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;text-decoration:none}.dask-stats-heading a:hover{color:var(--accent)}.dask-stat-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px 14px}.dask-stat-grid>div{display:grid;gap:1px}.dask-stat-grid strong{color:#eeeee9;font-family:SFMono-Regular,Consolas,monospace;font-size:15px;font-weight:500}.dask-stat-grid small{color:#656a6b;font-family:SFMono-Regular,Consolas,monospace;font-size:7px}.dask-memory{display:grid;gap:5px}.dask-memory strong{color:#9da2a1;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;font-weight:500}.dask-memory-track{height:2px;overflow:hidden;background:#2e3234}.dask-memory-track span{display:block;height:100%;background:var(--accent);transition:width .3s ease}.dask-stats-waiting{display:flex;align-items:center;gap:7px;color:#858a89;font-family:SFMono-Regular,Consolas,monospace;font-size:8px}.dask-pulse{width:5px;height:5px;border-radius:50%;background:var(--accent);animation:dask-pulse 1.2s ease-in-out infinite}@keyframes dask-pulse{50%{opacity:.25}}.hardware-warning{position:fixed;z-index:30;top:50%;left:50%;display:grid;width:min(430px,calc(100vw - 48px));padding:16px 42px 16px 16px;grid-template-columns:24px 1fr;gap:11px;border:1px solid #665936;border-radius:3px;background:#181712f7;color:#ece9de;box-shadow:0 16px 42px #00000061;transform:translate(-50%,-50%);animation:hardware-warning-in .18s ease-out}@keyframes hardware-warning-in{0%{opacity:0;transform:translate(-50%,calc(-50% - 8px))}to{opacity:1;transform:translate(-50%,-50%)}}.hardware-warning-icon{display:grid;width:24px;height:24px;place-items:center;border:1px solid #6e6038;border-radius:50%;color:#e0b74c}.hardware-warning-copy{display:grid;gap:5px}.hardware-warning-copy>span{color:#a89052;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;letter-spacing:.14em}.hardware-warning-copy>strong{font-size:13px;font-weight:600}.hardware-warning-copy p{margin:1px 0 7px;color:#a7a69f;font-size:10px;line-height:1.5}.hardware-warning-actions{display:flex;flex-wrap:wrap;gap:7px}.hardware-warning-actions button{display:inline-flex;min-height:29px;padding:0 10px;align-items:center;justify-content:center;gap:6px;border:1px solid #4a4a44;background:transparent;color:#b7b7b0;font-family:SFMono-Regular,Consolas,monospace;font-size:8px;cursor:pointer}.hardware-warning-actions .warning-primary{border-color:#d1aa40;background:#d1aa40;color:#15140f;font-weight:700}.hardware-warning-actions button:hover{border-color:#e2bd55;color:#f2f0e8}.hardware-warning-actions .warning-primary:hover{background:#e2bd55;color:#15140f}.hardware-warning-close{position:absolute;top:9px;right:9px;display:grid;width:25px;height:25px;padding:0;place-items:center;border:0;background:transparent;color:#7d7d76;cursor:pointer}.hardware-warning-close:hover{color:#ece9de}@media(max-width:840px){.hardware-warning{width:calc(100vw - 24px)}}.log-drawer{position:absolute;z-index:12;right:18px;bottom:58px;display:flex;width:min(420px,calc(100% - 36px));height:min(240px,32%);flex-direction:column;overflow:hidden;border:1px solid #44484a;border-radius:2px;background:#0e1012fa;box-shadow:0 12px 34px #0000004d}.log-resize-handle{position:absolute;z-index:2;top:-1px;left:-1px;width:18px;height:18px;border:0;padding:0;background:transparent;cursor:nwse-resize;touch-action:none}.log-resize-handle:before,.log-resize-handle:after{position:absolute;top:3px;left:3px;background:#737879;content:""}.log-resize-handle:before{width:9px;height:1px}.log-resize-handle:after{width:1px;height:9px}.log-resize-handle:hover:before,.log-resize-handle:hover:after{background:var(--accent)}.log-header{display:flex;align-items:center;justify-content:space-between;padding:8px 11px;border-bottom:1px solid #333739;color:#d7d8d3;font-size:9px;cursor:move;touch-action:none;-webkit-user-select:none;user-select:none}.log-header strong{display:flex;align-items:center;gap:6px}.log-header-actions{display:flex;align-items:center;gap:1px}.log-header button{display:grid;width:27px;height:25px;place-items:center;border:0;padding:0;background:none;color:#8b8f90;cursor:pointer}.log-header button.log-copy{width:auto;min-width:54px;grid-auto-flow:column;gap:5px;padding:0 7px;font-size:8px}.log-header button:hover{background:#292c2e;color:#f0f0eb}.log-header button:focus-visible{outline:1px solid var(--accent);outline-offset:-2px}#runLogs{flex:1;overflow:auto;margin:0;padding:11px;color:#adb1af;font:9px/1.6 SFMono-Regular,Consolas,monospace;cursor:text;-webkit-user-select:text;user-select:text;white-space:pre-wrap}.loading-overlay{position:absolute;z-index:20;inset:0;display:flex;align-items:center;justify-content:center;background:#060708b8;opacity:0;pointer-events:none;transition:opacity .18s ease}.loading-overlay.active{opacity:1;pointer-events:auto}.loading-box{display:grid;min-width:270px;gap:13px;padding:16px;border:1px solid #3b3f41;background:#151719;color:#dddeda}#loadingMessage{font-size:10px;font-weight:650}.loading-progress-track{width:100%;height:2px;overflow:hidden;background:#363a3c}.loading-progress-fill{width:0;height:100%;background:var(--accent);transition:width .12s ease}@media(max-width:900px){#sidebar{flex-basis:380px}.status-metrics{display:none}}@media(max-width:720px){body{display:block;overflow:auto;background:var(--paper)}.app-shell{display:block;height:auto}#sidebar{width:100%;min-width:0;height:auto;min-height:100vh;border-right:0}#sidebar.sidebar-collapsed{width:0;min-width:0;min-height:0;height:0;overflow:visible;background:transparent}.sidebar-collapsed .studio-header{top:10px;left:10px;min-height:0;justify-content:flex-start;padding:0}#main-content{height:72vh;min-height:520px}.run-status-bar{grid-template-columns:1fr auto}.run-progress-track{grid-column:1 / 3}.setup-panel,.setup-reopen{top:10px;right:10px}.setup-panel.with-active-job,.setup-reopen.with-active-job{top:90px}.setup-panel{width:min(318px,calc(100vw - 20px))}.setup-panel-body{max-height:390px}.log-drawer{right:10px;bottom:56px;width:min(420px,calc(100% - 20px));height:min(220px,34%)}#hud{right:50px;bottom:10px;left:10px;overflow-x:auto}.viewport-github{right:10px;bottom:10px}}@media(max-width:430px){.form-grid{grid-template-columns:1fr}.studio-header,.studio-tabs,.studio-panel{padding-right:17px;padding-left:17px}}@media(prefers-reduced-motion:reduce){*,*:before,*:after{scroll-behavior:auto!important;animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}} +:root{--ink: #20211f;--ink-soft: #666761;--ink-faint: #96978f;--paper: #f4f4f0;--paper-raised: #fafaf7;--line: #d8d8d1;--line-dark: #c7c7bf;--viewport: #0e1012;--viewport-line: #2a2e31;--accent: #e45d37;--accent-dark: #c94825;--success: #3a8060;--danger: #b94b40;--control-height: 40px}*{box-sizing:border-box}html,body{height:100%}body{margin:0;overflow:hidden;background:var(--viewport);color:var(--ink);font-family:Inter,ui-sans-serif,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;font-size:13px;line-height:1.45;-webkit-font-smoothing:antialiased}#root,.app-shell{width:100%;height:100%}.app-shell{display:flex}button,input,select,textarea{font:inherit}button{color:inherit}.hidden{display:none!important}#sidebar{position:relative;z-index:10;display:flex;flex:0 0 var(--sidebar-width, 420px);min-width:320px;flex-direction:column;overflow:hidden;background:var(--paper);border-right:1px solid #292b2d;transition:flex-basis .18s ease,min-width .18s ease}#sidebar.sidebar-resizing{transition:none}.sidebar-resize-handle{position:absolute;z-index:20;top:0;right:0;bottom:0;width:9px;touch-action:none;cursor:col-resize;outline:0}.sidebar-resize-handle:after{position:absolute;top:0;right:0;bottom:0;width:2px;background:var(--accent);content:"";opacity:0;transition:opacity .12s ease}.sidebar-resize-handle:hover:after,.sidebar-resize-handle:focus-visible:after,.sidebar-resizing .sidebar-resize-handle:after{opacity:1}.sidebar-collapsed .sidebar-resize-handle{display:none}body.sidebar-is-resizing,body.sidebar-is-resizing *{cursor:col-resize!important;-webkit-user-select:none!important;user-select:none!important}#sidebar.sidebar-collapsed{flex-basis:0;min-width:0;overflow:visible;border-right:0;background:transparent}.studio-header{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:79px;padding:12px 22px;border-bottom:1px solid var(--line)}.brand-logo{display:block;width:194px;max-width:100%;height:auto}.brand-primary{display:flex;min-width:0;align-items:center;gap:9px}.brand-mark{display:none;width:31px;height:31px;object-fit:contain}.sidebar-toggle{display:grid;width:31px;height:31px;flex:0 0 31px;place-items:center;border:1px solid var(--line-dark);border-radius:2px;padding:0;background:var(--paper-raised);color:var(--ink-soft);cursor:pointer}.sidebar-toggle:hover{border-color:var(--ink);color:var(--ink)}.sidebar-toggle:focus-visible{outline:1px solid var(--accent);outline-offset:2px}.sidebar-collapsed .studio-header{position:absolute;top:18px;left:18px;width:auto;min-height:0;gap:5px;justify-content:flex-start;padding:0;border:0;background:transparent}.sidebar-collapsed .brand-primary,.sidebar-collapsed .workspace-tabs{display:none}.sidebar-collapsed .brand-mark{display:block}.sidebar-collapsed .sidebar-toggle{border-color:#45494b;background:#131517e0;color:#d8d9d5;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}.sidebar-collapsed+#main-content #sceneStats{left:103px}.studio-tabs{display:flex;min-height:43px;padding:0 22px;gap:24px;border-bottom:1px solid var(--line)}.studio-tab{position:relative;border:0;padding:0;background:transparent;color:var(--ink-soft);font-size:11px;font-weight:650;cursor:pointer}.studio-tab:after{position:absolute;right:0;bottom:-1px;left:0;height:2px;background:var(--ink);content:"";opacity:0}.studio-tab:hover,.studio-tab[data-state=active]{color:var(--ink)}.studio-tab:focus-visible,.target-choice:focus-visible,.primary-action:focus-visible,.secondary-action:focus-visible,.icon-button:focus-visible,.text-button:focus-visible,#hud button:focus-visible,.setup-panel button:focus-visible,.setup-reopen:focus-visible{outline:1px solid var(--accent);outline-offset:2px}.studio-tab[data-state=active]:after{opacity:1}#activeJobCount:not(:empty){display:inline-grid;min-width:17px;height:17px;margin-left:4px;place-items:center;border-radius:50%;background:var(--accent);color:#fff;font-size:9px}.studio-panel{display:none;min-height:0;flex:1;overflow-y:auto;padding:0 22px 30px;scrollbar-color:var(--line-dark) transparent;scrollbar-width:thin}.studio-panel[data-state=active]{display:block}.workspace-tabs{display:flex;min-height:0;flex:1;flex-direction:column}.studio-tab{display:flex;align-items:center;gap:5px}.panel-intro{position:relative;padding:22px 0 14px}.catalog-sync{position:absolute;top:21px;right:0;display:inline-flex;align-items:center;gap:5px;border:0;background:transparent;color:var(--ink-faint);font-family:SFMono-Regular,Consolas,monospace;font-size:8px;letter-spacing:.03em}.catalog-sync.failed{color:var(--danger);cursor:pointer}.panel-intro span,.mini-heading{color:var(--accent-dark);font-family:SFMono-Regular,Consolas,monospace;font-size:9px;font-weight:700;letter-spacing:.1em}.panel-intro p{margin:5px 0 0;color:var(--ink-soft);font-size:12px}.form-section{padding:20px 0 8px;border-top:1px solid var(--line)}.section-heading{display:grid;grid-template-columns:27px 1fr;align-items:start;margin-bottom:17px}.section-heading>div{display:flex;flex-direction:column}.section-heading strong{font-size:13px;font-weight:680}.section-heading small{margin-top:1px;color:var(--ink-faint);font-size:10px;font-weight:450}.step-number{padding-top:2px;color:var(--accent);font-family:SFMono-Regular,Consolas,monospace;font-size:9px;font-weight:700}#runForm label,.advanced-options label{display:block;margin:0 0 12px;color:#4f504c;font-size:10px;font-weight:680;letter-spacing:.01em}#runForm input:not([type=checkbox]),#runForm select,#runForm textarea,#filter{display:block;width:100%;min-height:var(--control-height);margin-top:5px;border:1px solid var(--line-dark);border-radius:2px;outline:none;background:var(--paper-raised);color:var(--ink);font-size:12px;font-weight:500;transition:border-color .12s ease,background .12s ease}#runForm input:not([type=checkbox]),#runForm select,#filter{padding:9px 10px}#runForm textarea{min-height:88px;padding:9px 10px;resize:vertical;font-family:SFMono-Regular,Consolas,monospace;font-size:10px}#runForm input:hover,#runForm select:hover,#runForm textarea:hover,#filter:hover{border-color:#a6a79f}#runForm input:focus,#runForm select:focus,#runForm textarea:focus,#filter:focus{border-color:var(--ink);background:#fff}#runForm input::placeholder,#runForm textarea::placeholder,#filter::placeholder{color:#aaa9a2}#runForm input:disabled,#runForm select:disabled,#filter:disabled{cursor:not-allowed;opacity:.55}select{appearance:none;padding-right:32px!important;background-image:linear-gradient(45deg,transparent 50%,#60615c 50%),linear-gradient(135deg,#60615c 50%,transparent 50%)!important;background-position:calc(100% - 14px) 17px,calc(100% - 10px) 17px!important;background-repeat:no-repeat!important;background-size:4px 4px,4px 4px!important;cursor:pointer}input[type=checkbox]{width:14px;height:14px;margin:0;accent-color:var(--accent)}.optional{float:right;color:var(--ink-faint);font-weight:450}.folder-field{position:relative;margin-bottom:13px}.folder-label{margin-bottom:5px;color:#4f504c;font-size:10px;font-weight:680;letter-spacing:.01em}.folder-drop{display:flex;width:100%;min-height:86px;align-items:center;gap:12px;padding:14px;border:1px dashed #b7b7ae;border-radius:3px;background:#f8f8f4;text-align:left;cursor:pointer;transition:border-color .12s ease,background .12s ease,box-shadow .12s ease}.folder-drop:hover,.folder-drop.dragging{border-color:var(--accent);background:#fff7f2;box-shadow:inset 3px 0 0 var(--accent)}.folder-drop.has-folder{border-style:solid;border-color:#b6c8bb;background:#f4f8f4}.folder-drop:disabled{cursor:wait;opacity:.7}.folder-icon{display:grid;width:34px;height:34px;flex:0 0 34px;place-items:center;border:1px solid var(--line-dark);border-radius:2px;background:var(--paper-raised);color:var(--accent)}.folder-drop.has-folder .folder-icon{border-color:#9eb6a5;color:var(--success)}.folder-copy{display:flex;min-width:0;flex-direction:column}.folder-copy strong{overflow:hidden;color:var(--ink);font-size:12px;font-weight:680;text-overflow:ellipsis;white-space:nowrap}.folder-copy small{margin-top:2px;color:var(--ink-faint);font-size:10px;font-weight:450}.folder-input{display:none!important}.folder-remove{display:block;margin:3px 0 0 auto;padding:1px 0;border:0;background:transparent;color:var(--ink-faint);font-size:9px;cursor:pointer}.folder-remove:hover{color:var(--danger)}.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:0 10px}.nested-options{margin:3px 0 12px;padding:13px 13px 1px;background:#ecece7;border-left:2px solid var(--accent)}.remote-vm-options{padding-bottom:12px}.provider-panel{margin:2px 0 0;padding:12px;border:1px solid #d2d2cb;background:var(--paper-raised)}.provider-heading{display:grid;grid-template-columns:30px minmax(0,1fr) auto;align-items:center;gap:9px;margin-bottom:14px}.provider-heading strong,.provider-heading small{display:block}.provider-heading strong{color:var(--ink);font-size:11px}.provider-heading small{margin-top:2px;color:var(--ink-soft);font-size:9px}.provider-mark{display:grid;width:30px;height:30px;place-items:center;border-radius:4px;background:#111;color:#7cf7c5;font-size:14px;font-weight:800}.provider-mark.ssh{background:#e7e7e1;color:var(--ink)}.provider-status{color:#287a5b;font-family:SFMono-Regular,Consolas,monospace;font-size:8px;font-weight:700;letter-spacing:.08em}.provider-status.soon{color:var(--ink-faint)}.modal-gpu-recommendation{display:grid;gap:6px;margin:-3px 0 10px;padding:11px 12px;border:1px solid #a9c4b4;border-left:2px solid var(--success);background:#f2f7f3}.modal-gpu-recommendation>div{display:flex;align-items:baseline;justify-content:space-between;gap:10px}.modal-gpu-recommendation span{color:#47715d;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;font-weight:700;letter-spacing:.11em}.modal-gpu-recommendation strong{color:#254d3a;font-size:11px;white-space:nowrap}.modal-gpu-recommendation p{margin:0;color:#5f6862;font-size:9px;line-height:1.45}.modal-gpu-recommendation small{display:flex;align-items:center;gap:5px;color:var(--success);font-size:8px;font-weight:650}.modal-gpu-recommendation button{width:max-content;border:0;padding:0;background:transparent;color:var(--accent-dark);font-size:8px;font-weight:700;text-decoration:underline;text-underline-offset:3px;cursor:pointer}.modal-gpu-recommendation.overridden{border-color:#d5b59d;border-left-color:var(--accent);background:#faf4ef}.modal-gpu-recommendation.empty{border-color:var(--line);border-left-color:var(--line-dark);background:#f2f2ed}.modal-gpu-recommendation.empty strong{color:var(--ink);font-size:10px}.modal-estimate{display:grid;margin:2px 0 14px;padding:13px;gap:7px;border:1px solid #323633;background:#171918;color:#eceee9}.modal-estimate-heading{display:flex;align-items:flex-end;justify-content:space-between;gap:12px}.modal-estimate-heading>div{display:grid;gap:3px}.modal-estimate-heading span{color:#6f7772;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;letter-spacing:.13em}.modal-estimate-heading strong{font-family:SFMono-Regular,Consolas,monospace;font-size:20px;font-weight:500;letter-spacing:-.04em}.modal-estimate-heading em{color:#9ea5a0;font-family:SFMono-Regular,Consolas,monospace;font-size:8px;font-style:normal;white-space:nowrap}.modal-estimate-bar{height:2px;overflow:hidden;background:#303431}.modal-estimate-bar span{display:block;height:100%;background:#68d8ab}.modal-estimate p,.modal-estimate small{margin:0}.modal-estimate p{color:#c2c6c2;font-size:9px}.modal-estimate small{color:#777e79;font-size:8px;line-height:1.45}.modal-estimate a{width:max-content;color:#8e9791;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;text-decoration:none}.modal-estimate a:hover{color:#68d8ab}.modal-estimate.empty{background:#f2f2ed;color:var(--ink);border-color:var(--line)}.modal-estimate.empty strong{font-size:10px}.modal-estimate.empty p{color:var(--ink-soft);line-height:1.45}.modal-command-help{margin-top:0}.credential-success{display:flex;align-items:center;gap:5px;margin:-4px 0 12px;color:#287a5b;font-size:9px;font-weight:650}.modal-deploy-action{display:inline-flex;min-height:36px;align-items:center;justify-content:center;gap:7px;margin-bottom:8px;border:1px solid #1f2924;background:#17241e;color:#dcebe3;font-size:9px;font-weight:650;cursor:pointer}.modal-deploy-action:hover:not(:disabled){border-color:#287a5b;background:#1b2c24}.modal-deploy-action:disabled{cursor:not-allowed;opacity:.45}.modal-deployment{display:grid;margin:0 0 8px;gap:7px;padding:9px;border:1px solid var(--line);background:#eeeee9}.modal-deployment>div,.modal-deployment>div>span{display:flex;align-items:center;gap:6px}.modal-deployment>div{justify-content:space-between}.modal-deployment-actions{flex:0 0 auto}.modal-deployment-actions button{display:grid;width:24px;height:24px;padding:0;place-items:center;border:0;background:transparent;color:var(--ink-soft);cursor:pointer}.modal-deployment-actions button:hover{background:#deded7;color:var(--ink)}.modal-deployment-actions .modal-stop-action{display:inline-flex;width:auto;padding:0 7px;align-items:center;gap:4px;color:var(--danger);font-size:7px;font-weight:700}.modal-deployment-steps{display:grid;margin:2px 0 1px;padding:0;gap:3px;list-style:none}.modal-deployment-steps li{display:grid;min-height:34px;padding:5px 7px;grid-template-columns:19px minmax(0,1fr);align-items:center;gap:7px;border:1px solid transparent;color:var(--ink-faint)}.modal-deployment-steps li>div{display:grid;gap:1px}.modal-deployment-steps li strong{color:inherit;font-size:8px;font-weight:680}.modal-deployment-steps li small{color:inherit;font-size:7px;line-height:1.35}.modal-step-mark{display:grid;width:18px;height:18px;place-items:center;border:1px solid var(--line-dark);border-radius:50%;font-family:SFMono-Regular,Consolas,monospace;font-size:7px}.modal-deployment-steps li[data-state=active]{border-color:#d8bd85;background:#f8f2e7;color:#725a28}.modal-deployment-steps li[data-state=active] .modal-step-mark{border-color:#b68b32;color:#8d681e}.modal-deployment-steps li[data-state=complete]{color:var(--success)}.modal-deployment-steps li[data-state=complete] .modal-step-mark{border-color:#8aaf98}.modal-deployment-steps li[data-state=failed]{border-color:#d4a3a3;background:#faf0ef;color:var(--danger)}.modal-deployment-steps li[data-state=failed] .modal-step-mark{border-color:var(--danger)}.modal-deployment-steps li[data-state=cancelled]{border-color:#b9b9b1;background:#e7e7e1;color:var(--ink-soft)}.modal-deployment strong,.modal-deployment small{font-size:8px}.modal-deployment.completed{border-color:#9ac5af}.modal-deployment.failed{border-color:#d4a3a3;color:var(--danger)}.modal-deployment.cancelling,.modal-deployment.cancelled{border-color:#b9b9b1;color:var(--ink-soft)}.modal-deployment pre{overflow:auto;max-height:74px;margin:0;padding:7px;background:#171918;color:#aeb5b0;font:7px/1.5 SFMono-Regular,Consolas,monospace;white-space:pre-wrap}.modal-deployment .modal-log-preview-heading{display:flex;margin-top:1px;padding:0 1px;align-items:center;justify-content:space-between}.modal-log-preview-heading>span{color:var(--ink-faint);font-family:SFMono-Regular,Consolas,monospace;font-size:6px;font-weight:700;letter-spacing:.11em}.modal-log-preview-heading button{display:inline-flex;min-height:22px;padding:0 5px;align-items:center;gap:4px;border:0;background:transparent;color:var(--ink-soft);font-size:7px;font-weight:650;cursor:pointer}.modal-log-preview-heading button:hover{background:#deded7;color:var(--ink)}.modal-log-backdrop{position:fixed;z-index:80;inset:0;display:grid;padding:32px;place-items:center;background:#090a0aad;-webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}.modal-log-dialog{display:flex;width:min(820px,calc(100vw - 64px));height:min(590px,calc(100vh - 64px));flex-direction:column;overflow:hidden;border:1px solid #4b504d;border-radius:3px;background:#111311;box-shadow:0 28px 80px #00000080;color:#e6e9e5}.modal-log-dialog header{display:flex;min-height:54px;padding:0 12px 0 16px;align-items:center;gap:12px;border-bottom:1px solid #343835}.modal-log-dialog header>div{display:grid;flex:1;gap:2px}.modal-log-dialog header span,.modal-log-dialog header small{color:#7c847e;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;letter-spacing:.1em;text-transform:uppercase}.modal-log-dialog header strong{font-size:11px;font-weight:600}.modal-log-dialog header button{display:inline-flex;min-height:29px;padding:0 8px;align-items:center;justify-content:center;gap:5px;border:0;background:transparent;color:#9fa5a1;font-size:8px;cursor:pointer}.modal-log-dialog header button:hover{background:#262a27;color:#f0f2ef}.modal-log-dialog header .modal-dialog-stop{color:#e28378}.modal-log-dialog pre{flex:1;overflow:auto;margin:0;padding:18px;color:#bbc2bc;font:10px/1.65 SFMono-Regular,Consolas,monospace;-webkit-user-select:text;user-select:text;white-space:pre-wrap}@media(max-width:640px){.modal-log-backdrop{padding:12px}.modal-log-dialog{width:calc(100vw - 24px);height:calc(100vh - 24px)}.modal-log-dialog header small{display:none}}.remote-message:empty{display:none}.modal-workspace-status{display:grid;min-height:50px;margin:0 0 10px;padding:9px 10px;grid-template-columns:24px minmax(0,1fr);align-items:center;gap:8px;border:1px solid var(--line-dark);background:#eeeeea}.modal-workspace-status>span{display:grid;width:23px;height:23px;place-items:center;border:1px solid currentColor;border-radius:50%;color:var(--ink-soft)}.modal-workspace-status>div{display:grid;gap:2px}.modal-workspace-status strong{color:var(--ink);font-size:9px;font-weight:700}.modal-workspace-status small{color:var(--ink-soft);font-size:8px;line-height:1.45}.modal-workspace-status.working{border-color:#d8bd85;background:#f8f2e7}.modal-workspace-status.working>span{color:#8d681e}.modal-workspace-status.found{border-color:#aebbc2;background:#eef2f3}.modal-workspace-status.found>span{color:#536d79}.modal-workspace-status.ready{border-color:#9ac5af;background:#edf5f0}.modal-workspace-status.ready>span{color:var(--success)}.modal-workspace-status.attention{border-color:#d4a3a3;background:#faf0ef}.modal-workspace-status.attention>span,.modal-workspace-status.attention strong{color:var(--danger)}.field-help{margin:-5px 0 12px;color:var(--ink-soft);font-size:10px;line-height:1.5}.field-help code{font-family:SFMono-Regular,Consolas,monospace}.mini-heading{margin:1px 0 10px;color:var(--ink-soft)}.loader-options{margin:-3px 0 12px;padding:12px 12px 1px;background:#ecece7;border:1px solid var(--line)}.check-label{display:flex!important;align-items:center;gap:8px;min-height:26px;cursor:pointer}.segmented{display:grid;grid-template-columns:1fr 1fr;margin-bottom:13px;border:1px solid var(--line-dark);background:var(--paper-raised)}.input-source{margin-top:2px}.sample-picker{margin-bottom:13px}.sample-card{display:grid;grid-template-columns:32px minmax(0,1fr);gap:10px;margin:-4px 0 10px;padding:11px;border:1px solid var(--line);background:#ecece7}.sample-card.ready{border-color:#b6c8bb;background:#f4f8f4}.sample-state{display:grid;width:30px;height:30px;place-items:center;border:1px solid var(--line-dark);color:var(--accent)}.sample-card.ready .sample-state{border-color:#9eb6a5;color:var(--success)}.sample-card>div{display:flex;min-width:0;flex-direction:column}.sample-card strong{font-size:11px}.sample-card small{margin-top:1px;color:var(--ink-soft);font-size:9px;line-height:1.45}.sample-card div>span{margin-top:5px;color:var(--ink-faint);font-family:SFMono-Regular,Consolas,monospace;font-size:8px}.sample-card a{color:var(--ink-soft);text-underline-offset:2px}.sample-help{margin-top:0}.target-choice{display:flex;min-height:36px;align-items:center;justify-content:center;gap:6px;border:0;background:transparent;color:var(--ink-soft);font-size:10px;font-weight:680;cursor:pointer}.target-choice+.target-choice{border-left:1px solid var(--line-dark)}.target-choice.active{background:var(--ink);color:#fff}.hardware-card{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:2px 10px;margin:-4px 0 11px;padding:10px;border:1px solid var(--line);background:#ecece7}.hardware-card strong{overflow:hidden;font-size:11px;text-overflow:ellipsis;white-space:nowrap}.hardware-card small{grid-row:2;overflow:hidden;color:var(--ink-soft);font-size:9px;text-overflow:ellipsis;white-space:nowrap}.capability{grid-column:2;grid-row:1 / span 2;align-self:center;padding:3px 6px;border:1px solid var(--line-dark);color:var(--ink-soft);font-family:SFMono-Regular,Consolas,monospace;font-size:8px;font-weight:700;letter-spacing:.04em;text-transform:uppercase}.capability.yes{border-color:#8aaf98;color:var(--success)}.advanced-options{margin:13px 0 16px;padding-top:14px;border-top:1px solid var(--line)}.advanced-trigger{display:flex;width:100%;align-items:center;justify-content:space-between;border:0;padding:0 0 13px;background:transparent;color:var(--ink-soft);font-size:10px;font-weight:680;cursor:pointer}.advanced-trigger>span,.secondary-action{display:flex;align-items:center;justify-content:center;gap:6px}.advanced-trigger-copy{display:grid;gap:1px;text-align:left}.advanced-trigger-copy small{color:var(--ink-faint);font-family:SFMono-Regular,Consolas,monospace;font-size:7px;font-weight:500}.advanced-trigger[data-state=open]>svg{transform:rotate(180deg)}.advanced-content{overflow:hidden}.machine-profile-summary{display:grid;gap:7px;margin:0 0 14px;padding:11px 12px;border:1px solid var(--line);border-left:2px solid var(--accent);background:#eeeeea}.machine-profile-summary>div:first-child{display:flex;align-items:baseline;justify-content:space-between;gap:10px}.machine-profile-summary>div:first-child span{color:var(--ink-faint);font-family:SFMono-Regular,Consolas,monospace;font-size:7px;letter-spacing:.1em}.machine-profile-summary strong{overflow:hidden;font-size:10px;text-overflow:ellipsis;white-space:nowrap}.machine-profile-summary p,.advanced-machine-note{margin:0;color:var(--ink-soft);font-size:9px;line-height:1.45}.machine-profile-specs{display:flex;flex-wrap:wrap;gap:5px}.machine-profile-specs span{padding:3px 6px;border:1px solid var(--line-dark);background:var(--paper-raised);color:#555752;font-family:SFMono-Regular,Consolas,monospace;font-size:7px}.advanced-machine-note{margin:-5px 0 13px}.toggle-row{display:flex;min-height:31px;align-items:center;gap:9px;margin:0 0 10px}.toggle-row.disabled{opacity:.48}.toggle-row label{margin:0!important;cursor:pointer}.switch-root{position:relative;width:28px;height:16px;flex:0 0 28px;border:0;border-radius:999px;padding:0;background:#b9b9b2;cursor:pointer}.switch-root[data-state=checked]{background:var(--accent)}.switch-thumb{display:block;width:12px;height:12px;border-radius:50%;background:#fff;transform:translate(2px);transition:transform .12s ease}.switch-thumb[data-state=checked]{transform:translate(14px)}.primary-action{display:flex;width:100%;min-height:43px;align-items:center;justify-content:space-between;border:1px solid var(--ink);border-radius:0;padding:0 14px;background:var(--ink);color:#fff;font-size:11px;font-weight:680;cursor:pointer;transition:background .12s ease,border-color .12s ease}.primary-action:hover{border-color:var(--accent-dark);background:var(--accent-dark)}.spin{animation:spin .9s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.panel-loading{display:flex;align-items:center;gap:8px;padding:36px 0;color:var(--ink-soft);font-size:11px}.panel-loading.failed{align-items:flex-start;color:var(--danger)}.panel-loading.failed>div{display:grid;flex:1;gap:3px}.panel-loading.failed strong,.panel-loading.failed small{display:block}.panel-loading.failed small{color:var(--ink-soft);line-height:1.4}.hardware-card.detecting{display:flex;min-height:54px;align-items:center;gap:10px}.hardware-card.detecting>div{display:grid;gap:3px}.primary-action:disabled{cursor:wait;opacity:.55}.form-error{min-height:18px;margin:4px 0 8px;color:var(--danger);font-size:10px}.secondary-action,.icon-button{border:1px solid var(--line-dark);border-radius:2px;background:var(--paper-raised);color:var(--ink);font-size:10px;font-weight:650;cursor:pointer}.secondary-action{padding:7px 10px}.secondary-action:hover,.icon-button:hover{border-color:var(--ink)}.secondary-action.full-width{width:100%;margin:2px 0 10px}.panel-title{display:flex;align-items:center;justify-content:space-between;margin:22px 0 17px}.panel-title h3{margin:0;font-size:18px;font-weight:680;letter-spacing:-.035em}.panel-title p{margin:2px 0 0;color:var(--ink-soft);font-size:10px}.icon-button{width:31px;height:31px}.job-list{display:flex;flex-direction:column;gap:8px}.job-card{padding:12px;border:1px solid var(--line);background:var(--paper-raised)}.job-card.selected{border-left:2px solid var(--accent)}.job-card-top{display:flex;justify-content:space-between;gap:8px}.job-card strong{font-size:12px}.job-card>small{color:var(--ink-soft);font-size:9px}.job-status{color:var(--ink-soft);font-family:SFMono-Regular,Consolas,monospace;font-size:8px;font-weight:700;letter-spacing:.04em;text-transform:uppercase}.job-status.running,.job-status.queued{color:#a85523}.job-status.completed{color:var(--success)}.job-status.failed,.job-status.cancelled,.job-error{color:var(--danger)}.job-actions{display:flex;gap:12px;margin-top:9px}.job-card>.splat-download{margin-top:10px}.text-button{display:inline-flex;align-items:center;gap:4px;border:0;padding:0;background:none;color:var(--ink);font-size:9px;font-weight:700;text-decoration:underline;text-decoration-color:var(--line-dark);text-underline-offset:3px;cursor:pointer}.text-button.danger{color:var(--danger)}.job-error{margin:6px 0;font-size:9px}.empty-state{display:flex;align-items:center;justify-content:center;flex-direction:column;gap:5px;padding:42px 16px;border:1px dashed var(--line-dark);color:var(--ink-faint);font-size:11px;text-align:center}.empty-state strong{color:var(--ink);font-size:11px}.empty-state span{font-size:10px}#resultsPanel #info{margin-bottom:12px}#resultsPanel #filter{margin:0 0 12px}#resultsPanel #sceneList{min-height:200px}#info{display:flex;align-items:center;gap:12px;padding:11px;border:1px solid var(--line);background:var(--paper-raised)}#info .info-pill{display:grid;width:39px;height:39px;flex:0 0 39px;place-items:center;background:var(--ink);color:#fff;font-family:SFMono-Regular,Consolas,monospace;font-size:12px;font-weight:700}#info .info-details{min-width:0}#info .info-title{font-size:11px;font-weight:680}#info .info-path{overflow:hidden;margin-top:2px;color:var(--ink-soft);font-family:SFMono-Regular,Consolas,monospace;font-size:8px;text-overflow:ellipsis;white-space:nowrap}#info.info-error{border-color:#d5a29d}#info.info-error .info-pill{background:var(--danger)}#sceneList{margin:0 -6px;overflow-y:auto}#sceneList.is-disabled{pointer-events:none;opacity:.45}#sceneList ul{margin:3px 0;padding-left:15px;list-style:none}.directory-node{display:flex;width:100%;min-height:30px;align-items:center;gap:7px;border:0;padding:6px;background:transparent;color:var(--ink);font-size:11px;font-weight:680;text-align:left;cursor:pointer}.directory-node:hover{background:#eeeee9}.directory-node:focus-visible{outline:1px solid var(--accent);outline-offset:-1px}.directory-chevron{width:6px;height:6px;flex:0 0 6px;border-right:1px solid var(--ink-faint);border-bottom:1px solid var(--ink-faint);transform:rotate(45deg) translate(-1px,-1px);transition:transform .12s ease}.directory-branch.is-collapsed>.directory-node .directory-chevron{transform:rotate(-45deg)}.directory-branch.is-collapsed>ul{display:none}.item{margin-bottom:1px;padding:7px 8px;border-left:2px solid transparent;cursor:pointer}.item:hover{background:#e9e9e4}.item.active{border-left-color:var(--accent);background:#e6e5df}.item div{overflow:hidden;color:var(--ink);font-size:11px;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.item small{display:block;overflow:hidden;color:var(--ink-soft);font-size:9px;text-overflow:ellipsis;white-space:nowrap}.item .result-splat-download{display:flex;margin-top:7px}.result-splat-download .splat-format-label{display:grid;width:61px;min-height:27px;place-items:center;border:1px solid var(--line-dark);border-right:0;border-radius:2px 0 0 2px;padding:4px 7px;background-color:var(--paper-raised);color:var(--ink);font:8px SFMono-Regular,Consolas,monospace}.result-splat-download a{display:grid;min-width:65px;place-items:center;border:1px solid var(--line-dark);border-radius:0 2px 2px 0;padding:0 7px;color:var(--ink);font-size:8px;font-weight:650;text-decoration:none}.result-splat-download a:hover{border-color:var(--ink)}#main-content{position:relative;min-width:0;flex:1;overflow:hidden;background:var(--viewport)}#renderCanvas{display:block;width:100%;height:100%;outline:none}.setup-panel,.setup-reopen{position:absolute;z-index:9;top:18px;right:18px}.setup-panel.with-active-job,.setup-reopen.with-active-job{top:91px}.setup-panel{width:318px;overflow:hidden;border:1px solid #404346;border-radius:2px;background:#131517f5;box-shadow:0 12px 32px #0000003d;color:#e8e8e3;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px)}.setup-panel.collapsed{width:238px}.setup-panel-header{display:grid;min-height:52px;grid-template-columns:20px 1fr auto;align-items:center;gap:9px;padding:9px 8px 9px 12px}.setup-overall-icon{display:grid;width:20px;height:20px;place-items:center;color:#d69a52}.setup-overall-icon.ready{color:#6fa484}.setup-overall-icon.error{color:#d16b61}.setup-panel-copy{display:flex;min-width:0;flex-direction:column}.setup-panel-copy>span{color:#767b7d;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;font-weight:700;letter-spacing:.13em}.setup-panel-copy strong{overflow:hidden;margin-top:1px;font-size:11px;font-weight:650;text-overflow:ellipsis;white-space:nowrap}.setup-panel-actions{display:flex;align-items:center}.setup-panel-actions button,.setup-reopen{display:grid;width:27px;height:27px;place-items:center;border:0;padding:0;background:transparent;color:#8d9192;cursor:pointer}.setup-panel-actions button:hover,.setup-reopen:hover{background:#2b2e30;color:#f0f0eb}.setup-panel-actions button:disabled{cursor:wait;opacity:.5}.setup-panel-body{max-height:min(560px,calc(100vh - 92px));overflow-y:auto;border-top:1px solid #34373a;scrollbar-color:#44484a transparent;scrollbar-width:thin}.setup-summary-line{display:flex;justify-content:space-between;gap:10px;padding:8px 12px;border-bottom:1px solid #2f3234;color:#777c7d;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;letter-spacing:.04em;text-transform:uppercase}.setup-panel ul{margin:0;padding:4px 0;list-style:none}.setup-panel li{display:grid;grid-template-columns:18px 1fr;gap:7px;padding:7px 12px}.setup-check-content{min-width:0}.setup-check-mark{display:grid;width:16px;height:16px;margin-top:1px;place-items:center;border:1px solid #44484a;border-radius:50%;color:#6fa484}.setup-panel li[data-state=error] .setup-check-mark{border-color:#804f4a;color:#d16b61}.setup-panel li[data-state=optional] .setup-check-mark,.setup-panel li[data-state=warning] .setup-check-mark{border-color:#484c4e;color:transparent}.setup-panel li[data-state=optional] .setup-check-mark>span,.setup-panel li[data-state=warning] .setup-check-mark>span{width:4px;height:4px;border-radius:50%;background:#686d6f}.setup-check-title{display:flex;align-items:center;justify-content:space-between;gap:8px}.setup-check-tools{display:flex;flex:0 0 auto;align-items:center;gap:6px}.setup-check-title strong{color:#dadbd6;font-size:10px;font-weight:620}.setup-check-title em{color:#686d6f;font-family:SFMono-Regular,Consolas,monospace;font-size:6px;font-style:normal;letter-spacing:.08em;text-transform:uppercase}.setup-check-title .setup-install{display:flex;min-height:21px;align-items:center;justify-content:center;gap:4px;border:1px solid #505456;border-radius:2px;padding:2px 6px;background:#25282a;color:#d7d8d3;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;font-weight:650;cursor:pointer;white-space:nowrap}.setup-check-title .setup-install:hover:not(:disabled){border-color:#777b7d;background:#303335;color:#fff}.setup-check-title .setup-install:disabled{cursor:not-allowed;opacity:.45}.setup-panel li small{display:block;margin-top:1px;color:#777c7d;font-size:8px;line-height:1.35}.setup-panel li[data-state=error] small{color:#b87a74}.setup-panel li small.setup-action-error{color:#d9877f}.setup-loading{display:flex;align-items:center;gap:8px;padding:15px 12px;color:#8c9092;font-size:9px}.setup-reopen{width:34px;height:34px;border:1px solid #404346;border-radius:2px;background:#131517f0;box-shadow:0 8px 22px #0003}.run-status-bar{position:absolute;z-index:8;right:18px;bottom:68px;left:auto;width:min(720px,calc(100% - 36px));display:grid;min-height:61px;grid-template-columns:1.2fr 1fr auto;grid-template-rows:auto 2px;align-items:center;gap:8px 16px;padding:11px 12px 9px;border:1px solid #373a3c;background:#131517f0;color:#ecece7;cursor:grab}.status-copy{display:flex;align-items:center;gap:10px}.status-drag-handle{min-width:0;cursor:grab;touch-action:none;-webkit-user-select:none;user-select:none}.status-metrics,.run-progress-track{touch-action:none;-webkit-user-select:none;user-select:none}.run-status-bar.is-dragging .status-drag-handle,.run-status-bar.is-dragging{cursor:grabbing}.status-copy>div{display:flex;flex-direction:column}.status-copy strong{font-size:11px}.status-copy small{color:#8c9092;font-size:9px}.status-dot{width:7px;height:7px;background:var(--accent);animation:statusPulse 1.5s ease-in-out infinite}.run-status-bar[data-status=completed] .status-dot{background:#6da17f;animation:none}.run-status-bar[data-status=failed] .status-dot,.run-status-bar[data-status=cancelled] .status-dot{background:#cb6258;animation:none}@keyframes statusPulse{50%{opacity:.35}}.status-metrics{display:flex;justify-content:flex-end;gap:13px;color:#a3a6a5;font-family:SFMono-Regular,Consolas,monospace;font-size:8px;font-variant-numeric:tabular-nums}.run-progress-track{grid-column:1 / 4;height:2px;overflow:hidden;background:#343739}.run-progress-fill{width:100%;height:100%;background:var(--accent);transition:transform .4s ease}.run-status-bar .secondary-action{border-color:#484c4e;background:transparent;color:#d1d2cd}.run-status-bar .secondary-action.stop-process{border-color:#744843;color:#e79289}.run-status-bar .secondary-action.stop-process:hover{border-color:#a95a52;background:#b94b4021;color:#ffb0a8}.status-actions{display:flex;align-items:center;gap:4px}.splat-download{display:flex;align-items:stretch;min-height:31px}.splat-download .splat-format-label{display:grid;width:62px;min-height:31px;place-items:center;border:1px solid #484c4e;border-right:0;border-radius:2px 0 0 2px;padding:5px 7px;background-color:transparent;color:#d1d2cd;font-family:SFMono-Regular,Consolas,monospace;font-size:8px}.splat-download a{display:flex;min-width:76px;align-items:center;justify-content:center;gap:5px;border:1px solid #484c4e;border-radius:0 2px 2px 0;padding:0 8px;color:#d1d2cd;font-size:9px;font-weight:650;text-decoration:none}.splat-download a:hover{border-color:#707476;color:#fff}.splat-download.compact{width:fit-content;min-height:27px}.splat-download.compact .splat-format-label{min-height:27px;border-color:var(--line-dark);background-color:var(--paper-raised);color:var(--ink)}.splat-download.compact a{min-width:31px;border-color:var(--line-dark);color:var(--ink)}.status-close{display:grid;width:31px;height:31px;place-items:center;border:1px solid #484c4e;border-radius:2px;padding:0;background:transparent;color:#8e9293;cursor:pointer}.status-close:hover{border-color:#707476;color:#f0f0eb}.status-close:focus-visible{outline:1px solid var(--accent);outline-offset:2px}#hud{position:absolute;z-index:5;right:58px;bottom:18px;display:flex;align-items:center;gap:1px;padding:4px;border:1px solid #383b3e;background:#131517eb;color:#b9bcba;font-size:9px}.viewport-github{position:absolute;z-index:6;right:18px;bottom:18px;display:grid;width:31px;height:31px;place-items:center;border:1px solid #414547;border-radius:2px;background:#131517eb;color:#d3d4d0;text-decoration:none;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}.viewport-github:hover{border-color:#767a7c;color:#fff}.viewport-github:focus-visible{outline:1px solid var(--accent);outline-offset:2px}#hud button{display:flex;height:30px;align-items:center;justify-content:center;gap:5px;min-width:0;border:0;padding:0 10px;background:transparent;color:#d3d4d0;font-size:9px;font-weight:620;cursor:pointer;white-space:nowrap}#hud button:hover,#hud button.is-active{background:#303335;color:#fff}#hud label{display:flex;align-items:center;gap:6px;min-height:30px;padding:0 8px;border-left:1px solid #343739;white-space:nowrap}#hud .background-control{gap:7px;border-left:0}#hud .background-control select{width:82px;min-height:24px;border:1px solid #3f4345;border-radius:1px;padding:3px 22px 3px 7px!important;outline:none;background-color:#232628;background-position:calc(100% - 11px) 10px,calc(100% - 7px) 10px!important;color:#e2e3de;font-size:9px}#hud .background-control select:hover,#hud .background-control select:focus{border-color:#676b6d}#hud input[type=range]{width:90px;accent-color:var(--accent)}#hud .plane-height-control{min-width:190px}#hud .plane-height-control input[type=range]{width:112px}#groundYValue{min-width:25px;color:#e4e5df;font-family:SFMono-Regular,Consolas,monospace;font-size:8px;text-align:right}#hud input[type=checkbox]{accent-color:var(--accent)}#hud.hud-splat-mode .hud-scene-only,.hud-hidden{display:none!important}#sceneStats{position:absolute;z-index:6;top:18px;left:18px;display:grid;min-width:178px;gap:8px;padding:12px;border:1px solid #383b3e;background:#131517eb;color:#e5e5df}#sceneStats .stat-group[data-mode=scene]{display:grid;grid-template-columns:1fr 1fr;gap:9px 15px}#sceneStats .stat-group[data-mode=splat]{display:none}#sceneStats .stat-wide{grid-column:1 / 3}#sceneStats .stat-pair,#sceneStats .stat-wide{display:flex;flex-direction:column}#sceneStats .label{color:#747879;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;letter-spacing:.12em;text-transform:uppercase}#sceneStats .value{overflow:hidden;color:#e6e6e1;font-family:SFMono-Regular,Consolas,monospace;font-size:12px;font-weight:600;text-overflow:ellipsis;white-space:nowrap}#sceneStats .stat-wide .value{max-width:240px}#sceneStats.dask-active{width:226px}.dask-stats{display:grid;padding-top:11px;gap:11px;border-top:1px solid #34383a;animation:dask-stats-expand .18s ease-out;transform-origin:top}@keyframes dask-stats-expand{0%{opacity:0;transform:scaleY(.75) translateY(-5px)}to{opacity:1;transform:scaleY(1) translateY(0)}}.dask-stats-heading,.dask-memory>div:first-child{display:flex;align-items:flex-end;justify-content:space-between;gap:10px}.dask-stats-heading>div{display:grid;gap:3px}.dask-stats-heading span,.dask-memory span,.dask-stat-grid span{color:#747879;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;letter-spacing:.12em;text-transform:uppercase}.dask-stats-heading strong{font-size:11px;font-weight:600}.dask-stats-heading a{color:#9ba09f;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;text-decoration:none}.dask-stats-heading a:hover{color:var(--accent)}.dask-stat-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px 14px}.dask-stat-grid>div{display:grid;gap:1px}.dask-stat-grid strong{color:#eeeee9;font-family:SFMono-Regular,Consolas,monospace;font-size:15px;font-weight:500}.dask-stat-grid small{color:#656a6b;font-family:SFMono-Regular,Consolas,monospace;font-size:7px}.dask-memory{display:grid;gap:5px}.dask-memory strong{color:#9da2a1;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;font-weight:500}.dask-memory-track{height:2px;overflow:hidden;background:#2e3234}.dask-memory-track span{display:block;height:100%;background:var(--accent);transition:width .3s ease}.dask-stats-waiting{display:flex;align-items:center;gap:7px;color:#858a89;font-family:SFMono-Regular,Consolas,monospace;font-size:8px}.dask-pulse{width:5px;height:5px;border-radius:50%;background:var(--accent);animation:dask-pulse 1.2s ease-in-out infinite}@keyframes dask-pulse{50%{opacity:.25}}.pipeline-wait-overlay{position:absolute;z-index:4;inset:0;display:flex;align-items:center;justify-content:center;padding:96px 28px 76px;background:#0506076b;color:#ecece7;pointer-events:none;animation:pipeline-viewport-dim 2.6s ease-in-out infinite}.pipeline-wait-content{display:grid;width:min(560px,calc(100% - 48px));justify-items:center;gap:11px;text-align:center}.pipeline-wait-content>span{color:#858a89;font:650 8px/1.2 SFMono-Regular,Consolas,monospace;letter-spacing:.14em}.pipeline-wait-content strong{max-width:100%;color:#f0f0eb;font-size:clamp(15px,2vw,22px);font-weight:500;line-height:1.35;text-wrap:balance}.pipeline-wait-content small{color:#858a89;font-size:10px}.pipeline-wait-dots{display:flex;height:6px;align-items:center;gap:5px}.pipeline-wait-dots i{display:block;width:3px;height:3px;border-radius:50%;background:var(--accent);animation:pipeline-dot 1.35s ease-in-out infinite}.pipeline-wait-dots i:nth-child(2){animation-delay:.16s}.pipeline-wait-dots i:nth-child(3){animation-delay:.32s}@keyframes pipeline-viewport-dim{50%{background-color:#05060791}}@keyframes pipeline-dot{0%,70%,to{opacity:.22;transform:translateY(0)}35%{opacity:1;transform:translateY(-2px)}}.hardware-warning{position:fixed;z-index:30;top:50%;left:50%;display:grid;width:min(430px,calc(100vw - 48px));padding:16px 42px 16px 16px;grid-template-columns:24px 1fr;gap:11px;border:1px solid #665936;border-radius:3px;background:#181712f7;color:#ece9de;box-shadow:0 16px 42px #00000061;transform:translate(-50%,-50%);animation:hardware-warning-in .18s ease-out}@keyframes hardware-warning-in{0%{opacity:0;transform:translate(-50%,calc(-50% - 8px))}to{opacity:1;transform:translate(-50%,-50%)}}.hardware-warning-icon{display:grid;width:24px;height:24px;place-items:center;border:1px solid #6e6038;border-radius:50%;color:#e0b74c}.hardware-warning-copy{display:grid;gap:5px}.hardware-warning-copy>span{color:#a89052;font-family:SFMono-Regular,Consolas,monospace;font-size:7px;letter-spacing:.14em}.hardware-warning-copy>strong{font-size:13px;font-weight:600}.hardware-warning-copy p{margin:1px 0 7px;color:#a7a69f;font-size:10px;line-height:1.5}.hardware-warning-actions{display:flex;flex-wrap:wrap;gap:7px}.hardware-warning-actions button{display:inline-flex;min-height:29px;padding:0 10px;align-items:center;justify-content:center;gap:6px;border:1px solid #4a4a44;background:transparent;color:#b7b7b0;font-family:SFMono-Regular,Consolas,monospace;font-size:8px;cursor:pointer}.hardware-warning-actions .warning-primary{border-color:#d1aa40;background:#d1aa40;color:#15140f;font-weight:700}.hardware-warning-actions button:hover{border-color:#e2bd55;color:#f2f0e8}.hardware-warning-actions .warning-primary:hover{background:#e2bd55;color:#15140f}.hardware-warning-close{position:absolute;top:9px;right:9px;display:grid;width:25px;height:25px;padding:0;place-items:center;border:0;background:transparent;color:#7d7d76;cursor:pointer}.hardware-warning-close:hover{color:#ece9de}@media(max-width:840px){.hardware-warning{width:calc(100vw - 24px)}}.log-drawer{position:absolute;z-index:12;right:18px;bottom:58px;display:flex;width:min(420px,calc(100% - 36px));height:min(240px,32%);flex-direction:column;overflow:hidden;border:1px solid #44484a;border-radius:2px;background:#0e1012fa;box-shadow:0 12px 34px #0000004d}.log-resize-handle{position:absolute;z-index:4;width:18px;height:18px;border:0;padding:0;background:transparent;touch-action:none}.log-resize-handle:before{position:absolute;width:8px;height:8px;border-color:#737879;border-style:solid;border-width:0;content:""}.log-resize-handle.nw{top:-1px;left:-1px;cursor:nwse-resize}.log-resize-handle.nw:before{top:4px;left:4px;border-top-width:1px;border-left-width:1px}.log-resize-handle.ne{top:-1px;right:-1px;cursor:nesw-resize}.log-resize-handle.ne:before{top:4px;right:4px;border-top-width:1px;border-right-width:1px}.log-resize-handle.sw{bottom:-1px;left:-1px;cursor:nesw-resize}.log-resize-handle.sw:before{bottom:4px;left:4px;border-bottom-width:1px;border-left-width:1px}.log-resize-handle.se{right:-1px;bottom:-1px;cursor:nwse-resize}.log-resize-handle.se:before{right:4px;bottom:4px;border-right-width:1px;border-bottom-width:1px}.log-resize-handle:hover:before{border-color:var(--accent)}.log-header{display:flex;align-items:center;justify-content:space-between;padding:8px 11px;border-bottom:1px solid #333739;color:#d7d8d3;font-size:9px;cursor:move;touch-action:none;-webkit-user-select:none;user-select:none}.log-header strong{display:flex;align-items:center;gap:6px}.log-header-actions{display:flex;align-items:center;gap:1px}.log-header button{display:grid;width:27px;height:25px;place-items:center;border:0;padding:0;background:none;color:#8b8f90;cursor:pointer}.log-header button.log-copy{width:auto;min-width:54px;grid-auto-flow:column;gap:5px;padding:0 7px;font-size:8px}.log-header button:hover{background:#292c2e;color:#f0f0eb}.log-header button:focus-visible{outline:1px solid var(--accent);outline-offset:-2px}#runLogs{flex:1;overflow:auto;margin:0;padding:11px;color:#adb1af;font-family:SFMono-Regular,Consolas,monospace;font-size:var(--log-font-size, 9px);line-height:1.6;cursor:text;-webkit-user-select:text;user-select:text;white-space:pre-wrap}.loading-overlay{position:absolute;z-index:20;inset:0;display:flex;align-items:center;justify-content:center;background:#060708b8;opacity:0;pointer-events:none;transition:opacity .18s ease}.loading-overlay.active{opacity:1;pointer-events:auto}.loading-box{display:grid;min-width:270px;gap:13px;padding:16px;border:1px solid #3b3f41;background:#151719;color:#dddeda}#loadingMessage{font-size:10px;font-weight:650}.loading-progress-track{width:100%;height:2px;overflow:hidden;background:#363a3c}.loading-progress-fill{width:0;height:100%;background:var(--accent);transition:width .12s ease}@media(max-width:900px){#sidebar{flex-basis:var(--sidebar-width, 380px)}.status-metrics{display:none}}@media(max-width:720px){body{display:block;overflow:auto;background:var(--paper)}.app-shell{display:block;height:auto}#sidebar{width:100%;min-width:0;height:auto;min-height:100vh;border-right:0}#sidebar.sidebar-collapsed{width:0;min-width:0;min-height:0;height:0;overflow:visible;background:transparent}.sidebar-resize-handle{display:none}.sidebar-collapsed .studio-header{top:10px;left:10px;min-height:0;justify-content:flex-start;padding:0}#main-content{height:72vh;min-height:520px}.run-status-bar{grid-template-columns:1fr auto}.run-progress-track{grid-column:1 / 3}.setup-panel,.setup-reopen{top:10px;right:10px}.setup-panel.with-active-job,.setup-reopen.with-active-job{top:90px}.setup-panel{width:min(318px,calc(100vw - 20px))}.setup-panel-body{max-height:390px}.log-drawer{right:10px;bottom:56px;width:min(420px,calc(100% - 20px));height:min(220px,34%)}#hud{right:50px;bottom:10px;left:10px;overflow-x:auto}.viewport-github{right:10px;bottom:10px}}@media(max-width:430px){.form-grid{grid-template-columns:1fr}.studio-header,.studio-tabs,.studio-panel{padding-right:17px;padding-left:17px}}@media(prefers-reduced-motion:reduce){*,*:before,*:after{scroll-behavior:auto!important;animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}} diff --git a/visualization/static/studio.js b/visualization/static/studio.js index 18cce404f..dd2f7dc8f 100644 --- a/visualization/static/studio.js +++ b/visualization/static/studio.js @@ -1,18 +1,18 @@ -var Fm=u=>{throw TypeError(u)};var Wm=(u,r,f)=>r.has(u)||Fm("Cannot "+f);var mt=(u,r,f)=>(Wm(u,r,"read from private field"),f?f.call(u):r.get(u)),Im=(u,r,f)=>r.has(u)?Fm("Cannot add the same private member more than once"):r instanceof WeakSet?r.add(u):r.set(u,f),co=(u,r,f,o)=>(Wm(u,r,"write to private field"),o?o.call(u,f):r.set(u,f),f);function Gy(u,r){for(var f=0;fo[m]})}}}return Object.freeze(Object.defineProperty(u,Symbol.toStringTag,{value:"Module"}))}function Hy(u){return u&&u.__esModule&&Object.prototype.hasOwnProperty.call(u,"default")?u.default:u}var so={exports:{}},fi={};var Pm;function qy(){if(Pm)return fi;Pm=1;var u=Symbol.for("react.transitional.element"),r=Symbol.for("react.fragment");function f(o,m,h){var S=null;if(h!==void 0&&(S=""+h),m.key!==void 0&&(S=""+m.key),"key"in m){h={};for(var M in m)M!=="key"&&(h[M]=m[M])}else h=m;return m=h.ref,{$$typeof:u,type:o,key:S,ref:m!==void 0?m:null,props:h}}return fi.Fragment=r,fi.jsx=f,fi.jsxs=f,fi}var eh;function ky(){return eh||(eh=1,so.exports=qy()),so.exports}var c=ky(),oo={exports:{}},se={};var th;function Ly(){if(th)return se;th=1;var u=Symbol.for("react.transitional.element"),r=Symbol.for("react.portal"),f=Symbol.for("react.fragment"),o=Symbol.for("react.strict_mode"),m=Symbol.for("react.profiler"),h=Symbol.for("react.consumer"),S=Symbol.for("react.context"),M=Symbol.for("react.forward_ref"),j=Symbol.for("react.suspense"),y=Symbol.for("react.memo"),p=Symbol.for("react.lazy"),x=Symbol.for("react.activity"),D=Symbol.iterator;function H(g){return g===null||typeof g!="object"?null:(g=D&&g[D]||g["@@iterator"],typeof g=="function"?g:null)}var L={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},Q=Object.assign,V={};function k(g,w,X){this.props=g,this.context=w,this.refs=V,this.updater=X||L}k.prototype.isReactComponent={},k.prototype.setState=function(g,w){if(typeof g!="object"&&typeof g!="function"&&g!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,g,w,"setState")},k.prototype.forceUpdate=function(g){this.updater.enqueueForceUpdate(this,g,"forceUpdate")};function Y(){}Y.prototype=k.prototype;function G(g,w,X){this.props=g,this.context=w,this.refs=V,this.updater=X||L}var Z=G.prototype=new Y;Z.constructor=G,Q(Z,k.prototype),Z.isPureReactComponent=!0;var le=Array.isArray;function P(){}var J={H:null,A:null,T:null,S:null},me=Object.prototype.hasOwnProperty;function ue(g,w,X){var K=X.ref;return{$$typeof:u,type:g,key:w,ref:K!==void 0?K:null,props:X}}function He(g,w){return ue(g.type,w,g.props)}function Ue(g){return typeof g=="object"&&g!==null&&g.$$typeof===u}function _e(g){var w={"=":"=0",":":"=2"};return"$"+g.replace(/[=:]/g,function(X){return w[X]})}var ze=/\/+/g;function Ze(g,w){return typeof g=="object"&&g!==null&&g.key!=null?_e(""+g.key):w.toString(36)}function Ke(g){switch(g.status){case"fulfilled":return g.value;case"rejected":throw g.reason;default:switch(typeof g.status=="string"?g.then(P,P):(g.status="pending",g.then(function(w){g.status==="pending"&&(g.status="fulfilled",g.value=w)},function(w){g.status==="pending"&&(g.status="rejected",g.reason=w)})),g.status){case"fulfilled":return g.value;case"rejected":throw g.reason}}throw g}function R(g,w,X,K,ae){var ne=typeof g;(ne==="undefined"||ne==="boolean")&&(g=null);var he=!1;if(g===null)he=!0;else switch(ne){case"bigint":case"string":case"number":he=!0;break;case"object":switch(g.$$typeof){case u:case r:he=!0;break;case p:return he=g._init,R(he(g._payload),w,X,K,ae)}}if(he)return ae=ae(g),he=K===""?"."+Ze(g,0):K,le(ae)?(X="",he!=null&&(X=he.replace(ze,"$&/")+"/"),R(ae,w,X,"",function(nl){return nl})):ae!=null&&(Ue(ae)&&(ae=He(ae,X+(ae.key==null||g&&g.key===ae.key?"":(""+ae.key).replace(ze,"$&/")+"/")+he)),w.push(ae)),1;he=0;var Le=K===""?".":K+":";if(le(g))for(var qe=0;qe"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(u)}catch(r){console.error(r)}}return u(),ro.exports=Vy(),ro.exports}var Do=Sh(),fo={exports:{}},di={},mo={exports:{}},ho={};var ih;function Xy(){return ih||(ih=1,(function(u){function r(R,q){var I=R.length;R.push(q);e:for(;0>>1,ge=R[ye];if(0>>1;yem(X,I))Km(ae,X)?(R[ye]=ae,R[K]=I,ye=K):(R[ye]=X,R[w]=I,ye=w);else if(Km(ae,I))R[ye]=ae,R[K]=I,ye=K;else break e}}return q}function m(R,q){var I=R.sortIndex-q.sortIndex;return I!==0?I:R.id-q.id}if(u.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var h=performance;u.unstable_now=function(){return h.now()}}else{var S=Date,M=S.now();u.unstable_now=function(){return S.now()-M}}var j=[],y=[],p=1,x=null,D=3,H=!1,L=!1,Q=!1,V=!1,k=typeof setTimeout=="function"?setTimeout:null,Y=typeof clearTimeout=="function"?clearTimeout:null,G=typeof setImmediate<"u"?setImmediate:null;function Z(R){for(var q=f(y);q!==null;){if(q.callback===null)o(y);else if(q.startTime<=R)o(y),q.sortIndex=q.expirationTime,r(j,q);else break;q=f(y)}}function le(R){if(Q=!1,Z(R),!L)if(f(j)!==null)L=!0,P||(P=!0,_e());else{var q=f(y);q!==null&&Ke(le,q.startTime-R)}}var P=!1,J=-1,me=5,ue=-1;function He(){return V?!0:!(u.unstable_now()-ueR&&He());){var ye=x.callback;if(typeof ye=="function"){x.callback=null,D=x.priorityLevel;var ge=ye(x.expirationTime<=R);if(R=u.unstable_now(),typeof ge=="function"){x.callback=ge,Z(R),q=!0;break t}x===f(j)&&o(j),Z(R)}else o(j);x=f(j)}if(x!==null)q=!0;else{var g=f(y);g!==null&&Ke(le,g.startTime-R),q=!1}}break e}finally{x=null,D=I,H=!1}q=void 0}}finally{q?_e():P=!1}}}var _e;if(typeof G=="function")_e=function(){G(Ue)};else if(typeof MessageChannel<"u"){var ze=new MessageChannel,Ze=ze.port2;ze.port1.onmessage=Ue,_e=function(){Ze.postMessage(null)}}else _e=function(){k(Ue,0)};function Ke(R,q){J=k(function(){R(u.unstable_now())},q)}u.unstable_IdlePriority=5,u.unstable_ImmediatePriority=1,u.unstable_LowPriority=4,u.unstable_NormalPriority=3,u.unstable_Profiling=null,u.unstable_UserBlockingPriority=2,u.unstable_cancelCallback=function(R){R.callback=null},u.unstable_forceFrameRate=function(R){0>R||125ye?(R.sortIndex=I,r(y,R),f(j)===null&&R===f(y)&&(Q?(Y(J),J=-1):Q=!0,Ke(le,I-ye))):(R.sortIndex=ge,r(j,R),L||H||(L=!0,P||(P=!0,_e()))),R},u.unstable_shouldYield=He,u.unstable_wrapCallback=function(R){var q=D;return function(){var I=D;D=q;try{return R.apply(this,arguments)}finally{D=I}}}})(ho)),ho}var uh;function Qy(){return uh||(uh=1,mo.exports=Xy()),mo.exports}var ch;function Zy(){if(ch)return di;ch=1;var u=Qy(),r=Oo(),f=Sh();function o(e){var t="https://react.dev/errors/"+e;if(1ge||(e.current=ye[ge],ye[ge]=null,ge--)}function X(e,t){ge++,ye[ge]=e.current,e.current=t}var K=g(null),ae=g(null),ne=g(null),he=g(null);function Le(e,t){switch(X(ne,t),X(ae,e),X(K,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?bm(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=bm(t),e=_m(t,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}w(K),X(K,e)}function qe(){w(K),w(ae),w(ne)}function nl(e){e.memoizedState!==null&&X(he,e);var t=K.current,l=_m(t,e.type);t!==l&&(X(ae,e),X(K,l))}function ie(e){ae.current===e&&(w(K),w(ae)),he.current===e&&(w(he),ci._currentValue=I)}var ct,Oe;function F(e){if(ct===void 0)try{throw Error()}catch(l){var t=l.stack.trim().match(/\n( *(at )?)/);ct=t&&t[1]||"",Oe=-1{throw TypeError(u)};var eh=(u,r,f)=>r.has(u)||Pm("Cannot "+f);var pt=(u,r,f)=>(eh(u,r,"read from private field"),f?f.call(u):r.get(u)),th=(u,r,f)=>r.has(u)?Pm("Cannot add the same private member more than once"):r instanceof WeakSet?r.add(u):r.set(u,f),fo=(u,r,f,o)=>(eh(u,r,"write to private field"),o?o.call(u,f):r.set(u,f),f);function Yg(u,r){for(var f=0;fo[m]})}}}return Object.freeze(Object.defineProperty(u,Symbol.toStringTag,{value:"Module"}))}function Vg(u){return u&&u.__esModule&&Object.prototype.hasOwnProperty.call(u,"default")?u.default:u}var mo={exports:{}},bi={};var lh;function Xg(){if(lh)return bi;lh=1;var u=Symbol.for("react.transitional.element"),r=Symbol.for("react.fragment");function f(o,m,h){var S=null;if(h!==void 0&&(S=""+h),m.key!==void 0&&(S=""+m.key),"key"in m){h={};for(var E in m)E!=="key"&&(h[E]=m[E])}else h=m;return m=h.ref,{$$typeof:u,type:o,key:S,ref:m!==void 0?m:null,props:h}}return bi.Fragment=r,bi.jsx=f,bi.jsxs=f,bi}var ah;function Qg(){return ah||(ah=1,mo.exports=Xg()),mo.exports}var c=Qg(),ho={exports:{}},re={};var nh;function Zg(){if(nh)return re;nh=1;var u=Symbol.for("react.transitional.element"),r=Symbol.for("react.portal"),f=Symbol.for("react.fragment"),o=Symbol.for("react.strict_mode"),m=Symbol.for("react.profiler"),h=Symbol.for("react.consumer"),S=Symbol.for("react.context"),E=Symbol.for("react.forward_ref"),j=Symbol.for("react.suspense"),y=Symbol.for("react.memo"),p=Symbol.for("react.lazy"),M=Symbol.for("react.activity"),O=Symbol.iterator;function Y(_){return _===null||typeof _!="object"?null:(_=O&&_[O]||_["@@iterator"],typeof _=="function"?_:null)}var H={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},V=Object.assign,X={};function k(_,G,Q){this.props=_,this.context=G,this.refs=X,this.updater=Q||H}k.prototype.isReactComponent={},k.prototype.setState=function(_,G){if(typeof _!="object"&&typeof _!="function"&&_!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,_,G,"setState")},k.prototype.forceUpdate=function(_){this.updater.enqueueForceUpdate(this,_,"forceUpdate")};function Z(){}Z.prototype=k.prototype;function w(_,G,Q){this.props=_,this.context=G,this.refs=X,this.updater=Q||H}var q=w.prototype=new Z;q.constructor=w,V(q,k.prototype),q.isPureReactComponent=!0;var $=Array.isArray;function W(){}var K={H:null,A:null,T:null,S:null},ne=Object.prototype.hasOwnProperty;function ee(_,G,Q){var J=Q.ref;return{$$typeof:u,type:_,key:G,ref:J!==void 0?J:null,props:Q}}function Me(_,G){return ee(_.type,G,_.props)}function Ce(_){return typeof _=="object"&&_!==null&&_.$$typeof===u}function xe(_){var G={"=":"=0",":":"=2"};return"$"+_.replace(/[=:]/g,function(Q){return G[Q]})}var ce=/\/+/g;function Ne(_,G){return typeof _=="object"&&_!==null&&_.key!=null?xe(""+_.key):G.toString(36)}function Ye(_){switch(_.status){case"fulfilled":return _.value;case"rejected":throw _.reason;default:switch(typeof _.status=="string"?_.then(W,W):(_.status="pending",_.then(function(G){_.status==="pending"&&(_.status="fulfilled",_.value=G)},function(G){_.status==="pending"&&(_.status="rejected",_.reason=G)})),_.status){case"fulfilled":return _.value;case"rejected":throw _.reason}}throw _}function R(_,G,Q,J,ue){var se=typeof _;(se==="undefined"||se==="boolean")&&(_=null);var Se=!1;if(_===null)Se=!0;else switch(se){case"bigint":case"string":case"number":Se=!0;break;case"object":switch(_.$$typeof){case u:case r:Se=!0;break;case p:return Se=_._init,R(Se(_._payload),G,Q,J,ue)}}if(Se)return ue=ue(_),Se=J===""?"."+Ne(_,0):J,$(ue)?(Q="",Se!=null&&(Q=Se.replace(ce,"$&/")+"/"),R(ue,G,Q,"",function(Tt){return Tt})):ue!=null&&(Ce(ue)&&(ue=Me(ue,Q+(ue.key==null||_&&_.key===ue.key?"":(""+ue.key).replace(ce,"$&/")+"/")+Se)),G.push(ue)),1;Se=0;var Be=J===""?".":J+":";if($(_))for(var He=0;He<_.length;He++)J=_[He],se=Be+Ne(J,He),Se+=R(J,G,Q,se,ue);else if(He=Y(_),typeof He=="function")for(_=He.call(_),He=0;!(J=_.next()).done;)J=J.value,se=Be+Ne(J,He++),Se+=R(J,G,Q,se,ue);else if(se==="object"){if(typeof _.then=="function")return R(Ye(_),G,Q,J,ue);throw G=String(_),Error("Objects are not valid as a React child (found: "+(G==="[object Object]"?"object with keys {"+Object.keys(_).join(", ")+"}":G)+"). If you meant to render a collection of children, use an array instead.")}return Se}function L(_,G,Q){if(_==null)return _;var J=[],ue=0;return R(_,J,"","",function(se){return G.call(Q,se,ue++)}),J}function le(_){if(_._status===-1){var G=_._result;G=G(),G.then(function(Q){(_._status===0||_._status===-1)&&(_._status=1,_._result=Q)},function(Q){(_._status===0||_._status===-1)&&(_._status=2,_._result=Q)}),_._status===-1&&(_._status=0,_._result=G)}if(_._status===1)return _._result.default;throw _._result}var Ee=typeof reportError=="function"?reportError:function(_){if(typeof window=="object"&&typeof window.ErrorEvent=="function"){var G=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:typeof _=="object"&&_!==null&&typeof _.message=="string"?String(_.message):String(_),error:_});if(!window.dispatchEvent(G))return}else if(typeof process=="object"&&typeof process.emit=="function"){process.emit("uncaughtException",_);return}console.error(_)},je={map:L,forEach:function(_,G,Q){L(_,function(){G.apply(this,arguments)},Q)},count:function(_){var G=0;return L(_,function(){G++}),G},toArray:function(_){return L(_,function(G){return G})||[]},only:function(_){if(!Ce(_))throw Error("React.Children.only expected to receive a single React element child.");return _}};return re.Activity=M,re.Children=je,re.Component=k,re.Fragment=f,re.Profiler=m,re.PureComponent=w,re.StrictMode=o,re.Suspense=j,re.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE=K,re.__COMPILER_RUNTIME={__proto__:null,c:function(_){return K.H.useMemoCache(_)}},re.cache=function(_){return function(){return _.apply(null,arguments)}},re.cacheSignal=function(){return null},re.cloneElement=function(_,G,Q){if(_==null)throw Error("The argument must be a React element, but you passed "+_+".");var J=V({},_.props),ue=_.key;if(G!=null)for(se in G.key!==void 0&&(ue=""+G.key),G)!ne.call(G,se)||se==="key"||se==="__self"||se==="__source"||se==="ref"&&G.ref===void 0||(J[se]=G[se]);var se=arguments.length-2;if(se===1)J.children=Q;else if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(u)}catch(r){console.error(r)}}return u(),po.exports=Jg(),po.exports}var Bo=Ch(),vo={exports:{}},Si={},go={exports:{}},yo={};var sh;function $g(){return sh||(sh=1,(function(u){function r(R,L){var le=R.length;R.push(L);e:for(;0>>1,je=R[Ee];if(0>>1;Ee<_;){var G=2*(Ee+1)-1,Q=R[G],J=G+1,ue=R[J];if(0>m(Q,le))Jm(ue,Q)?(R[Ee]=ue,R[J]=le,Ee=J):(R[Ee]=Q,R[G]=le,Ee=G);else if(Jm(ue,le))R[Ee]=ue,R[J]=le,Ee=J;else break e}}return L}function m(R,L){var le=R.sortIndex-L.sortIndex;return le!==0?le:R.id-L.id}if(u.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var h=performance;u.unstable_now=function(){return h.now()}}else{var S=Date,E=S.now();u.unstable_now=function(){return S.now()-E}}var j=[],y=[],p=1,M=null,O=3,Y=!1,H=!1,V=!1,X=!1,k=typeof setTimeout=="function"?setTimeout:null,Z=typeof clearTimeout=="function"?clearTimeout:null,w=typeof setImmediate<"u"?setImmediate:null;function q(R){for(var L=f(y);L!==null;){if(L.callback===null)o(y);else if(L.startTime<=R)o(y),L.sortIndex=L.expirationTime,r(j,L);else break;L=f(y)}}function $(R){if(V=!1,q(R),!H)if(f(j)!==null)H=!0,W||(W=!0,xe());else{var L=f(y);L!==null&&Ye($,L.startTime-R)}}var W=!1,K=-1,ne=5,ee=-1;function Me(){return X?!0:!(u.unstable_now()-eeR&&Me());){var Ee=M.callback;if(typeof Ee=="function"){M.callback=null,O=M.priorityLevel;var je=Ee(M.expirationTime<=R);if(R=u.unstable_now(),typeof je=="function"){M.callback=je,q(R),L=!0;break t}M===f(j)&&o(j),q(R)}else o(j);M=f(j)}if(M!==null)L=!0;else{var _=f(y);_!==null&&Ye($,_.startTime-R),L=!1}}break e}finally{M=null,O=le,Y=!1}L=void 0}}finally{L?xe():W=!1}}}var xe;if(typeof w=="function")xe=function(){w(Ce)};else if(typeof MessageChannel<"u"){var ce=new MessageChannel,Ne=ce.port2;ce.port1.onmessage=Ce,xe=function(){Ne.postMessage(null)}}else xe=function(){k(Ce,0)};function Ye(R,L){K=k(function(){R(u.unstable_now())},L)}u.unstable_IdlePriority=5,u.unstable_ImmediatePriority=1,u.unstable_LowPriority=4,u.unstable_NormalPriority=3,u.unstable_Profiling=null,u.unstable_UserBlockingPriority=2,u.unstable_cancelCallback=function(R){R.callback=null},u.unstable_forceFrameRate=function(R){0>R||125Ee?(R.sortIndex=le,r(y,R),f(j)===null&&R===f(y)&&(V?(Z(K),K=-1):V=!0,Ye($,le-Ee))):(R.sortIndex=je,r(j,R),H||Y||(H=!0,W||(W=!0,xe()))),R},u.unstable_shouldYield=Me,u.unstable_wrapCallback=function(R){var L=O;return function(){var le=O;O=L;try{return R.apply(this,arguments)}finally{O=le}}}})(yo)),yo}var oh;function Fg(){return oh||(oh=1,go.exports=$g()),go.exports}var rh;function Wg(){if(rh)return Si;rh=1;var u=Fg(),r=Go(),f=Ch();function o(e){var t="https://react.dev/errors/"+e;if(1je||(e.current=Ee[je],Ee[je]=null,je--)}function Q(e,t){je++,Ee[je]=e.current,e.current=t}var J=_(null),ue=_(null),se=_(null),Se=_(null);function Be(e,t){switch(Q(se,t),Q(ue,e),Q(J,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?xm(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=xm(t),e=jm(t,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}G(J),Q(J,e)}function He(){G(J),G(ue),G(se)}function Tt(e){e.memoizedState!==null&&Q(Se,e);var t=J.current,l=jm(t,e.type);t!==l&&(Q(ue,e),Q(J,l))}function Wt(e){ue.current===e&&(G(J),G(ue)),Se.current===e&&(G(Se),pi._currentValue=le)}var ml,il;function ct(e){if(ml===void 0)try{throw Error()}catch(l){var t=l.stack.trim().match(/\n( *(at )?)/);ml=t&&t[1]||"",il=-1)":-1n||v[a]!==A[n]){var O=` -`+v[a].replace(" at new "," at ");return e.displayName&&O.includes("")&&(O=O.replace("",e.displayName)),O}while(1<=a&&0<=n);break}}}finally{It=!1,Error.prepareStackTrace=l}return(l=e?e.displayName||e.name:"")?F(l):""}function Pt(e,t){switch(e.tag){case 26:case 27:case 5:return F(e.type);case 16:return F("Lazy");case 13:return e.child!==t&&t!==null?F("Suspense Fallback"):F("Suspense");case 19:return F("SuspenseList");case 0:case 15:return Et(e.type,!1);case 11:return Et(e.type.render,!1);case 1:return Et(e.type,!0);case 31:return F("Activity");default:return""}}function Ea(e){try{var t="",l=null;do t+=Pt(e,l),l=e,e=e.return;while(e);return t}catch(a){return` +`);for(n=a=0;an||v[a]!==A[n]){var D=` +`+v[a].replace(" at new "," at ");return e.displayName&&D.includes("")&&(D=D.replace("",e.displayName)),D}while(1<=a&&0<=n);break}}}finally{ul=!1,Error.prepareStackTrace=l}return(l=e?e.displayName||e.name:"")?ct(l):""}function fa(e,t){switch(e.tag){case 26:case 27:case 5:return ct(e.type);case 16:return ct("Lazy");case 13:return e.child!==t&&t!==null?ct("Suspense Fallback"):ct("Suspense");case 19:return ct("SuspenseList");case 0:case 15:return P(e.type,!1);case 11:return P(e.type.render,!1);case 1:return P(e.type,!0);case 31:return ct("Activity");default:return""}}function hl(e){try{var t="",l=null;do t+=fa(e,l),l=e,e=e.return;while(e);return t}catch(a){return` Error generating stack: `+a.message+` -`+a.stack}}var bn=Object.prototype.hasOwnProperty,Ma=u.unstable_scheduleCallback,De=u.unstable_cancelCallback,ta=u.unstable_shouldYield,la=u.unstable_requestPaint,Ve=u.unstable_now,Zu=u.unstable_getCurrentPriorityLevel,gi=u.unstable_ImmediatePriority,bi=u.unstable_UserBlockingPriority,aa=u.unstable_NormalPriority,_i=u.unstable_LowPriority,Si=u.unstable_IdlePriority,Ku=u.log,xi=u.unstable_setDisableYieldValue,na=null,pt=null;function C(e){if(typeof Ku=="function"&&xi(e),pt&&typeof pt.setStrictMode=="function")try{pt.setStrictMode(na,e)}catch{}}var ce=Math.clz32?Math.clz32:Ju,Se=Math.log,tt=Math.LN2;function Ju(e){return e>>>=0,e===0?32:31-(Se(e)/tt|0)|0}var ji=256,Ci=262144,Ei=4194304;function ia(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Mi(e,t,l){var a=e.pendingLanes;if(a===0)return 0;var n=0,i=e.suspendedLanes,s=e.pingedLanes;e=e.warmLanes;var d=a&134217727;return d!==0?(a=d&~i,a!==0?n=ia(a):(s&=d,s!==0?n=ia(s):l||(l=d&~e,l!==0&&(n=ia(l))))):(d=a&~i,d!==0?n=ia(d):s!==0?n=ia(s):l||(l=a&~e,l!==0&&(n=ia(l)))),n===0?0:t!==0&&t!==n&&(t&i)===0&&(i=n&-n,l=t&-t,i>=l||i===32&&(l&4194048)!==0)?t:n}function _n(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Cp(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Po(){var e=Ei;return Ei<<=1,(Ei&62914560)===0&&(Ei=4194304),e}function $u(e){for(var t=[],l=0;31>l;l++)t.push(e);return t}function Sn(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function Ep(e,t,l,a,n,i){var s=e.pendingLanes;e.pendingLanes=l,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=l,e.entangledLanes&=l,e.errorRecoveryDisabledLanes&=l,e.shellSuspendCounter=0;var d=e.entanglements,v=e.expirationTimes,A=e.hiddenUpdates;for(l=s&~l;0"u")return null;try{return e.activeElement||e.body}catch{return e.body}}var Rp=/[\n"\\]/g;function Gt(e){return e.replace(Rp,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function tc(e,t,l,a,n,i,s,d){e.name="",s!=null&&typeof s!="function"&&typeof s!="symbol"&&typeof s!="boolean"?e.type=s:e.removeAttribute("type"),t!=null?s==="number"?(t===0&&e.value===""||e.value!=t)&&(e.value=""+Bt(t)):e.value!==""+Bt(t)&&(e.value=""+Bt(t)):s!=="submit"&&s!=="reset"||e.removeAttribute("value"),t!=null?lc(e,s,Bt(t)):l!=null?lc(e,s,Bt(l)):a!=null&&e.removeAttribute("value"),n==null&&i!=null&&(e.defaultChecked=!!i),n!=null&&(e.checked=n&&typeof n!="function"&&typeof n!="symbol"),d!=null&&typeof d!="function"&&typeof d!="symbol"&&typeof d!="boolean"?e.name=""+Bt(d):e.removeAttribute("name")}function dr(e,t,l,a,n,i,s,d){if(i!=null&&typeof i!="function"&&typeof i!="symbol"&&typeof i!="boolean"&&(e.type=i),t!=null||l!=null){if(!(i!=="submit"&&i!=="reset"||t!=null)){ec(e);return}l=l!=null?""+Bt(l):"",t=t!=null?""+Bt(t):l,d||t===e.value||(e.value=t),e.defaultValue=t}a=a??n,a=typeof a!="function"&&typeof a!="symbol"&&!!a,e.checked=d?e.checked:!!a,e.defaultChecked=!!a,s!=null&&typeof s!="function"&&typeof s!="symbol"&&typeof s!="boolean"&&(e.name=s),ec(e)}function lc(e,t,l){t==="number"&&Ni(e.ownerDocument)===e||e.defaultValue===""+l||(e.defaultValue=""+l)}function Oa(e,t,l,a){if(e=e.options,t){t={};for(var n=0;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),cc=!1;if(cl)try{var En={};Object.defineProperty(En,"passive",{get:function(){cc=!0}}),window.addEventListener("test",En,En),window.removeEventListener("test",En,En)}catch{cc=!1}var Al=null,sc=null,Ri=null;function br(){if(Ri)return Ri;var e,t=sc,l=t.length,a,n="value"in Al?Al.value:Al.textContent,i=n.length;for(e=0;e=An),Er=" ",Mr=!1;function Tr(e,t){switch(e){case"keyup":return iv.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Ar(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var Ba=!1;function cv(e,t){switch(e){case"compositionend":return Ar(t);case"keypress":return t.which!==32?null:(Mr=!0,Er);case"textInput":return e=t.data,e===Er&&Mr?null:e;default:return null}}function sv(e,t){if(Ba)return e==="compositionend"||!mc&&Tr(e,t)?(e=br(),Ri=sc=Al=null,Ba=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:l,offset:t-e};e=a}e:{for(;l;){if(l.nextSibling){l=l.nextSibling;break e}l=l.parentNode}l=void 0}l=Br(l)}}function Hr(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Hr(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function qr(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=Ni(e.document);t instanceof e.HTMLIFrameElement;){try{var l=typeof t.contentWindow.location.href=="string"}catch{l=!1}if(l)e=t.contentWindow;else break;t=Ni(e.document)}return t}function vc(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}var vv=cl&&"documentMode"in document&&11>=document.documentMode,Ga=null,yc=null,On=null,gc=!1;function kr(e,t,l){var a=l.window===l?l.document:l.nodeType===9?l:l.ownerDocument;gc||Ga==null||Ga!==Ni(a)||(a=Ga,"selectionStart"in a&&vc(a)?a={start:a.selectionStart,end:a.selectionEnd}:(a=(a.ownerDocument&&a.ownerDocument.defaultView||window).getSelection(),a={anchorNode:a.anchorNode,anchorOffset:a.anchorOffset,focusNode:a.focusNode,focusOffset:a.focusOffset}),On&&Rn(On,a)||(On=a,a=Cu(yc,"onSelect"),0>=s,n-=s,el=1<<32-ce(t)+n|l<re?(ve=W,W=null):ve=W.sibling;var je=N(E,W,T[re],U);if(je===null){W===null&&(W=ve);break}e&&W&&je.alternate===null&&t(E,W),_=i(je,_,re),xe===null?ee=je:xe.sibling=je,xe=je,W=ve}if(re===T.length)return l(E,W),be&&ol(E,re),ee;if(W===null){for(;rere?(ve=W,W=null):ve=W.sibling;var Fl=N(E,W,je.value,U);if(Fl===null){W===null&&(W=ve);break}e&&W&&Fl.alternate===null&&t(E,W),_=i(Fl,_,re),xe===null?ee=Fl:xe.sibling=Fl,xe=Fl,W=ve}if(je.done)return l(E,W),be&&ol(E,re),ee;if(W===null){for(;!je.done;re++,je=T.next())je=B(E,je.value,U),je!==null&&(_=i(je,_,re),xe===null?ee=je:xe.sibling=je,xe=je);return be&&ol(E,re),ee}for(W=a(W);!je.done;re++,je=T.next())je=z(W,E,re,je.value,U),je!==null&&(e&&je.alternate!==null&&W.delete(je.key===null?re:je.key),_=i(je,_,re),xe===null?ee=je:xe.sibling=je,xe=je);return e&&W.forEach(function(By){return t(E,By)}),be&&ol(E,re),ee}function Ne(E,_,T,U){if(typeof T=="object"&&T!==null&&T.type===Q&&T.key===null&&(T=T.props.children),typeof T=="object"&&T!==null){switch(T.$$typeof){case H:e:{for(var ee=T.key;_!==null;){if(_.key===ee){if(ee=T.type,ee===Q){if(_.tag===7){l(E,_.sibling),U=n(_,T.props.children),U.return=E,E=U;break e}}else if(_.elementType===ee||typeof ee=="object"&&ee!==null&&ee.$$typeof===me&&va(ee)===_.type){l(E,_.sibling),U=n(_,T.props),Hn(U,T),U.return=E,E=U;break e}l(E,_);break}else t(E,_);_=_.sibling}T.type===Q?(U=fa(T.props.children,E.mode,U,T.key),U.return=E,E=U):(U=Li(T.type,T.key,T.props,null,E.mode,U),Hn(U,T),U.return=E,E=U)}return s(E);case L:e:{for(ee=T.key;_!==null;){if(_.key===ee)if(_.tag===4&&_.stateNode.containerInfo===T.containerInfo&&_.stateNode.implementation===T.implementation){l(E,_.sibling),U=n(_,T.children||[]),U.return=E,E=U;break e}else{l(E,_);break}else t(E,_);_=_.sibling}U=Ec(T,E.mode,U),U.return=E,E=U}return s(E);case me:return T=va(T),Ne(E,_,T,U)}if(Ke(T))return $(E,_,T,U);if(_e(T)){if(ee=_e(T),typeof ee!="function")throw Error(o(150));return T=ee.call(T),te(E,_,T,U)}if(typeof T.then=="function")return Ne(E,_,Ji(T),U);if(T.$$typeof===G)return Ne(E,_,Xi(E,T),U);$i(E,T)}return typeof T=="string"&&T!==""||typeof T=="number"||typeof T=="bigint"?(T=""+T,_!==null&&_.tag===6?(l(E,_.sibling),U=n(_,T),U.return=E,E=U):(l(E,_),U=Cc(T,E.mode,U),U.return=E,E=U),s(E)):l(E,_)}return function(E,_,T,U){try{Gn=0;var ee=Ne(E,_,T,U);return Ja=null,ee}catch(W){if(W===Ka||W===Zi)throw W;var xe=Tt(29,W,null,E.mode);return xe.lanes=U,xe.return=E,xe}}}var ga=rf(!0),ff=rf(!1),Dl=!1;function Gc(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Hc(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function wl(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function Ul(e,t,l){var a=e.updateQueue;if(a===null)return null;if(a=a.shared,(Ce&2)!==0){var n=a.pending;return n===null?t.next=t:(t.next=n.next,n.next=t),a.pending=t,t=ki(e),Kr(e,null,l),t}return qi(e,a,t,l),ki(e)}function qn(e,t,l){if(t=t.updateQueue,t!==null&&(t=t.shared,(l&4194048)!==0)){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,tr(e,l)}}function qc(e,t){var l=e.updateQueue,a=e.alternate;if(a!==null&&(a=a.updateQueue,l===a)){var n=null,i=null;if(l=l.firstBaseUpdate,l!==null){do{var s={lane:l.lane,tag:l.tag,payload:l.payload,callback:null,next:null};i===null?n=i=s:i=i.next=s,l=l.next}while(l!==null);i===null?n=i=t:i=i.next=t}else n=i=t;l={baseState:a.baseState,firstBaseUpdate:n,lastBaseUpdate:i,shared:a.shared,callbacks:a.callbacks},e.updateQueue=l;return}e=l.lastBaseUpdate,e===null?l.firstBaseUpdate=t:e.next=t,l.lastBaseUpdate=t}var kc=!1;function kn(){if(kc){var e=Za;if(e!==null)throw e}}function Ln(e,t,l,a){kc=!1;var n=e.updateQueue;Dl=!1;var i=n.firstBaseUpdate,s=n.lastBaseUpdate,d=n.shared.pending;if(d!==null){n.shared.pending=null;var v=d,A=v.next;v.next=null,s===null?i=A:s.next=A,s=v;var O=e.alternate;O!==null&&(O=O.updateQueue,d=O.lastBaseUpdate,d!==s&&(d===null?O.firstBaseUpdate=A:d.next=A,O.lastBaseUpdate=v))}if(i!==null){var B=n.baseState;s=0,O=A=v=null,d=i;do{var N=d.lane&-536870913,z=N!==d.lane;if(z?(pe&N)===N:(a&N)===N){N!==0&&N===Qa&&(kc=!0),O!==null&&(O=O.next={lane:0,tag:d.tag,payload:d.payload,callback:null,next:null});e:{var $=e,te=d;N=t;var Ne=l;switch(te.tag){case 1:if($=te.payload,typeof $=="function"){B=$.call(Ne,B,N);break e}B=$;break e;case 3:$.flags=$.flags&-65537|128;case 0:if($=te.payload,N=typeof $=="function"?$.call(Ne,B,N):$,N==null)break e;B=x({},B,N);break e;case 2:Dl=!0}}N=d.callback,N!==null&&(e.flags|=64,z&&(e.flags|=8192),z=n.callbacks,z===null?n.callbacks=[N]:z.push(N))}else z={lane:N,tag:d.tag,payload:d.payload,callback:d.callback,next:null},O===null?(A=O=z,v=B):O=O.next=z,s|=N;if(d=d.next,d===null){if(d=n.shared.pending,d===null)break;z=d,d=z.next,z.next=null,n.lastBaseUpdate=z,n.shared.pending=null}}while(!0);O===null&&(v=B),n.baseState=v,n.firstBaseUpdate=A,n.lastBaseUpdate=O,i===null&&(n.shared.lanes=0),kl|=s,e.lanes=s,e.memoizedState=B}}function df(e,t){if(typeof e!="function")throw Error(o(191,e));e.call(t)}function mf(e,t){var l=e.callbacks;if(l!==null)for(e.callbacks=null,e=0;ei?i:8;var s=R.T,d={};R.T=d,is(e,!1,t,l);try{var v=n(),A=R.S;if(A!==null&&A(d,v),v!==null&&typeof v=="object"&&typeof v.then=="function"){var O=Ev(v,a);Xn(e,t,O,Ot(e))}else Xn(e,t,a,Ot(e))}catch(B){Xn(e,t,{then:function(){},status:"rejected",reason:B},Ot())}finally{q.p=i,s!==null&&d.types!==null&&(s.types=d.types),R.T=s}}function Rv(){}function as(e,t,l,a){if(e.tag!==5)throw Error(o(476));var n=Qf(e).queue;Xf(e,n,t,I,l===null?Rv:function(){return Zf(e),l(a)})}function Qf(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:I,baseState:I,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:ml,lastRenderedState:I},next:null};var l={};return t.next={memoizedState:l,baseState:l,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:ml,lastRenderedState:l},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function Zf(e){var t=Qf(e);t.next===null&&(t=e.alternate.memoizedState),Xn(e,t.next.queue,{},Ot())}function ns(){return rt(ci)}function Kf(){return $e().memoizedState}function Jf(){return $e().memoizedState}function Ov(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var l=Ot();e=wl(l);var a=Ul(t,e,l);a!==null&&(jt(a,t,l),qn(a,t,l)),t={cache:Dc()},e.payload=t;return}t=t.return}}function Dv(e,t,l){var a=Ot();l={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null},iu(e)?Ff(t,l):(l=xc(e,t,l,a),l!==null&&(jt(l,e,a),Wf(l,t,a)))}function $f(e,t,l){var a=Ot();Xn(e,t,l,a)}function Xn(e,t,l,a){var n={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null};if(iu(e))Ff(t,n);else{var i=e.alternate;if(e.lanes===0&&(i===null||i.lanes===0)&&(i=t.lastRenderedReducer,i!==null))try{var s=t.lastRenderedState,d=i(s,l);if(n.hasEagerState=!0,n.eagerState=d,Mt(d,s))return qi(e,t,n,0),Re===null&&Hi(),!1}catch{}if(l=xc(e,t,n,a),l!==null)return jt(l,e,a),Wf(l,t,a),!0}return!1}function is(e,t,l,a){if(a={lane:2,revertLane:Gs(),gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},iu(e)){if(t)throw Error(o(479))}else t=xc(e,l,a,2),t!==null&&jt(t,e,2)}function iu(e){var t=e.alternate;return e===oe||t!==null&&t===oe}function Ff(e,t){Fa=Ii=!0;var l=e.pending;l===null?t.next=t:(t.next=l.next,l.next=t),e.pending=t}function Wf(e,t,l){if((l&4194048)!==0){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,tr(e,l)}}var Qn={readContext:rt,use:tu,useCallback:Xe,useContext:Xe,useEffect:Xe,useImperativeHandle:Xe,useLayoutEffect:Xe,useInsertionEffect:Xe,useMemo:Xe,useReducer:Xe,useRef:Xe,useState:Xe,useDebugValue:Xe,useDeferredValue:Xe,useTransition:Xe,useSyncExternalStore:Xe,useId:Xe,useHostTransitionStatus:Xe,useFormState:Xe,useActionState:Xe,useOptimistic:Xe,useMemoCache:Xe,useCacheRefresh:Xe};Qn.useEffectEvent=Xe;var If={readContext:rt,use:tu,useCallback:function(e,t){return vt().memoizedState=[e,t===void 0?null:t],e},useContext:rt,useEffect:Uf,useImperativeHandle:function(e,t,l){l=l!=null?l.concat([e]):null,au(4194308,4,qf.bind(null,t,e),l)},useLayoutEffect:function(e,t){return au(4194308,4,e,t)},useInsertionEffect:function(e,t){au(4,2,e,t)},useMemo:function(e,t){var l=vt();t=t===void 0?null:t;var a=e();if(ba){C(!0);try{e()}finally{C(!1)}}return l.memoizedState=[a,t],a},useReducer:function(e,t,l){var a=vt();if(l!==void 0){var n=l(t);if(ba){C(!0);try{l(t)}finally{C(!1)}}}else n=t;return a.memoizedState=a.baseState=n,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:n},a.queue=e,e=e.dispatch=Dv.bind(null,oe,e),[a.memoizedState,e]},useRef:function(e){var t=vt();return e={current:e},t.memoizedState=e},useState:function(e){e=Ic(e);var t=e.queue,l=$f.bind(null,oe,t);return t.dispatch=l,[e.memoizedState,l]},useDebugValue:ts,useDeferredValue:function(e,t){var l=vt();return ls(l,e,t)},useTransition:function(){var e=Ic(!1);return e=Xf.bind(null,oe,e.queue,!0,!1),vt().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,l){var a=oe,n=vt();if(be){if(l===void 0)throw Error(o(407));l=l()}else{if(l=t(),Re===null)throw Error(o(349));(pe&127)!==0||bf(a,t,l)}n.memoizedState=l;var i={value:l,getSnapshot:t};return n.queue=i,Uf(Sf.bind(null,a,i,e),[e]),a.flags|=2048,Ia(9,{destroy:void 0},_f.bind(null,a,i,l,t),null),l},useId:function(){var e=vt(),t=Re.identifierPrefix;if(be){var l=tl,a=el;l=(a&~(1<<32-ce(a)-1)).toString(32)+l,t="_"+t+"R_"+l,l=Pi++,0<\/script>",i=i.removeChild(i.firstChild);break;case"select":i=typeof a.is=="string"?s.createElement("select",{is:a.is}):s.createElement("select"),a.multiple?i.multiple=!0:a.size&&(i.size=a.size);break;default:i=typeof a.is=="string"?s.createElement(n,{is:a.is}):s.createElement(n)}}i[st]=t,i[yt]=a;e:for(s=t.child;s!==null;){if(s.tag===5||s.tag===6)i.appendChild(s.stateNode);else if(s.tag!==4&&s.tag!==27&&s.child!==null){s.child.return=s,s=s.child;continue}if(s===t)break e;for(;s.sibling===null;){if(s.return===null||s.return===t)break e;s=s.return}s.sibling.return=s.return,s=s.sibling}t.stateNode=i;e:switch(dt(i,n,a),n){case"button":case"input":case"select":case"textarea":a=!!a.autoFocus;break e;case"img":a=!0;break e;default:a=!1}a&&pl(t)}}return Ge(t),bs(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,l),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==a&&pl(t);else{if(typeof a!="string"&&t.stateNode===null)throw Error(o(166));if(e=ne.current,Va(t)){if(e=t.stateNode,l=t.memoizedProps,a=null,n=ot,n!==null)switch(n.tag){case 27:case 5:a=n.memoizedProps}e[st]=t,e=!!(e.nodeValue===l||a!==null&&a.suppressHydrationWarning===!0||ym(e.nodeValue,l)),e||Rl(t,!0)}else e=Eu(e).createTextNode(a),e[st]=t,t.stateNode=e}return Ge(t),null;case 31:if(l=t.memoizedState,e===null||e.memoizedState!==null){if(a=Va(t),l!==null){if(e===null){if(!a)throw Error(o(318));if(e=t.memoizedState,e=e!==null?e.dehydrated:null,!e)throw Error(o(557));e[st]=t}else da(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Ge(t),e=!1}else l=Nc(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=l),e=!0;if(!e)return t.flags&256?(Nt(t),t):(Nt(t),null);if((t.flags&128)!==0)throw Error(o(558))}return Ge(t),null;case 13:if(a=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(n=Va(t),a!==null&&a.dehydrated!==null){if(e===null){if(!n)throw Error(o(318));if(n=t.memoizedState,n=n!==null?n.dehydrated:null,!n)throw Error(o(317));n[st]=t}else da(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Ge(t),n=!1}else n=Nc(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=n),n=!0;if(!n)return t.flags&256?(Nt(t),t):(Nt(t),null)}return Nt(t),(t.flags&128)!==0?(t.lanes=l,t):(l=a!==null,e=e!==null&&e.memoizedState!==null,l&&(a=t.child,n=null,a.alternate!==null&&a.alternate.memoizedState!==null&&a.alternate.memoizedState.cachePool!==null&&(n=a.alternate.memoizedState.cachePool.pool),i=null,a.memoizedState!==null&&a.memoizedState.cachePool!==null&&(i=a.memoizedState.cachePool.pool),i!==n&&(a.flags|=2048)),l!==e&&l&&(t.child.flags|=8192),ru(t,t.updateQueue),Ge(t),null);case 4:return qe(),e===null&&Ls(t.stateNode.containerInfo),Ge(t),null;case 10:return fl(t.type),Ge(t),null;case 19:if(w(Je),a=t.memoizedState,a===null)return Ge(t),null;if(n=(t.flags&128)!==0,i=a.rendering,i===null)if(n)Kn(a,!1);else{if(Qe!==0||e!==null&&(e.flags&128)!==0)for(e=t.child;e!==null;){if(i=Wi(e),i!==null){for(t.flags|=128,Kn(a,!1),e=i.updateQueue,t.updateQueue=e,ru(t,e),t.subtreeFlags=0,e=l,l=t.child;l!==null;)Jr(l,e),l=l.sibling;return X(Je,Je.current&1|2),be&&ol(t,a.treeForkCount),t.child}e=e.sibling}a.tail!==null&&Ve()>pu&&(t.flags|=128,n=!0,Kn(a,!1),t.lanes=4194304)}else{if(!n)if(e=Wi(i),e!==null){if(t.flags|=128,n=!0,e=e.updateQueue,t.updateQueue=e,ru(t,e),Kn(a,!0),a.tail===null&&a.tailMode==="hidden"&&!i.alternate&&!be)return Ge(t),null}else 2*Ve()-a.renderingStartTime>pu&&l!==536870912&&(t.flags|=128,n=!0,Kn(a,!1),t.lanes=4194304);a.isBackwards?(i.sibling=t.child,t.child=i):(e=a.last,e!==null?e.sibling=i:t.child=i,a.last=i)}return a.tail!==null?(e=a.tail,a.rendering=e,a.tail=e.sibling,a.renderingStartTime=Ve(),e.sibling=null,l=Je.current,X(Je,n?l&1|2:l&1),be&&ol(t,a.treeForkCount),e):(Ge(t),null);case 22:case 23:return Nt(t),Yc(),a=t.memoizedState!==null,e!==null?e.memoizedState!==null!==a&&(t.flags|=8192):a&&(t.flags|=8192),a?(l&536870912)!==0&&(t.flags&128)===0&&(Ge(t),t.subtreeFlags&6&&(t.flags|=8192)):Ge(t),l=t.updateQueue,l!==null&&ru(t,l.retryQueue),l=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(l=e.memoizedState.cachePool.pool),a=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(a=t.memoizedState.cachePool.pool),a!==l&&(t.flags|=2048),e!==null&&w(pa),null;case 24:return l=null,e!==null&&(l=e.memoizedState.cache),t.memoizedState.cache!==l&&(t.flags|=2048),fl(Fe),Ge(t),null;case 25:return null;case 30:return null}throw Error(o(156,t.tag))}function Hv(e,t){switch(Tc(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return fl(Fe),qe(),e=t.flags,(e&65536)!==0&&(e&128)===0?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return ie(t),null;case 31:if(t.memoizedState!==null){if(Nt(t),t.alternate===null)throw Error(o(340));da()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(Nt(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(o(340));da()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return w(Je),null;case 4:return qe(),null;case 10:return fl(t.type),null;case 22:case 23:return Nt(t),Yc(),e!==null&&w(pa),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return fl(Fe),null;case 25:return null;default:return null}}function xd(e,t){switch(Tc(t),t.tag){case 3:fl(Fe),qe();break;case 26:case 27:case 5:ie(t);break;case 4:qe();break;case 31:t.memoizedState!==null&&Nt(t);break;case 13:Nt(t);break;case 19:w(Je);break;case 10:fl(t.type);break;case 22:case 23:Nt(t),Yc(),e!==null&&w(pa);break;case 24:fl(Fe)}}function Jn(e,t){try{var l=t.updateQueue,a=l!==null?l.lastEffect:null;if(a!==null){var n=a.next;l=n;do{if((l.tag&e)===e){a=void 0;var i=l.create,s=l.inst;a=i(),s.destroy=a}l=l.next}while(l!==n)}}catch(d){Me(t,t.return,d)}}function Hl(e,t,l){try{var a=t.updateQueue,n=a!==null?a.lastEffect:null;if(n!==null){var i=n.next;a=i;do{if((a.tag&e)===e){var s=a.inst,d=s.destroy;if(d!==void 0){s.destroy=void 0,n=t;var v=l,A=d;try{A()}catch(O){Me(n,v,O)}}}a=a.next}while(a!==i)}}catch(O){Me(t,t.return,O)}}function jd(e){var t=e.updateQueue;if(t!==null){var l=e.stateNode;try{mf(t,l)}catch(a){Me(e,e.return,a)}}}function Cd(e,t,l){l.props=_a(e.type,e.memoizedProps),l.state=e.memoizedState;try{l.componentWillUnmount()}catch(a){Me(e,t,a)}}function $n(e,t){try{var l=e.ref;if(l!==null){switch(e.tag){case 26:case 27:case 5:var a=e.stateNode;break;case 30:a=e.stateNode;break;default:a=e.stateNode}typeof l=="function"?e.refCleanup=l(a):l.current=a}}catch(n){Me(e,t,n)}}function ll(e,t){var l=e.ref,a=e.refCleanup;if(l!==null)if(typeof a=="function")try{a()}catch(n){Me(e,t,n)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof l=="function")try{l(null)}catch(n){Me(e,t,n)}else l.current=null}function Ed(e){var t=e.type,l=e.memoizedProps,a=e.stateNode;try{e:switch(t){case"button":case"input":case"select":case"textarea":l.autoFocus&&a.focus();break e;case"img":l.src?a.src=l.src:l.srcSet&&(a.srcset=l.srcSet)}}catch(n){Me(e,e.return,n)}}function _s(e,t,l){try{var a=e.stateNode;uy(a,e.type,l,t),a[yt]=t}catch(n){Me(e,e.return,n)}}function Md(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&Ql(e.type)||e.tag===4}function Ss(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Md(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&Ql(e.type)||e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function xs(e,t,l){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?(l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l).insertBefore(e,t):(t=l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l,t.appendChild(e),l=l._reactRootContainer,l!=null||t.onclick!==null||(t.onclick=ul));else if(a!==4&&(a===27&&Ql(e.type)&&(l=e.stateNode,t=null),e=e.child,e!==null))for(xs(e,t,l),e=e.sibling;e!==null;)xs(e,t,l),e=e.sibling}function fu(e,t,l){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?l.insertBefore(e,t):l.appendChild(e);else if(a!==4&&(a===27&&Ql(e.type)&&(l=e.stateNode),e=e.child,e!==null))for(fu(e,t,l),e=e.sibling;e!==null;)fu(e,t,l),e=e.sibling}function Td(e){var t=e.stateNode,l=e.memoizedProps;try{for(var a=e.type,n=t.attributes;n.length;)t.removeAttributeNode(n[0]);dt(t,a,l),t[st]=e,t[yt]=l}catch(i){Me(e,e.return,i)}}var vl=!1,Pe=!1,js=!1,Ad=typeof WeakSet=="function"?WeakSet:Set,nt=null;function qv(e,t){if(e=e.containerInfo,Xs=Ou,e=qr(e),vc(e)){if("selectionStart"in e)var l={start:e.selectionStart,end:e.selectionEnd};else e:{l=(l=e.ownerDocument)&&l.defaultView||window;var a=l.getSelection&&l.getSelection();if(a&&a.rangeCount!==0){l=a.anchorNode;var n=a.anchorOffset,i=a.focusNode;a=a.focusOffset;try{l.nodeType,i.nodeType}catch{l=null;break e}var s=0,d=-1,v=-1,A=0,O=0,B=e,N=null;t:for(;;){for(var z;B!==l||n!==0&&B.nodeType!==3||(d=s+n),B!==i||a!==0&&B.nodeType!==3||(v=s+a),B.nodeType===3&&(s+=B.nodeValue.length),(z=B.firstChild)!==null;)N=B,B=z;for(;;){if(B===e)break t;if(N===l&&++A===n&&(d=s),N===i&&++O===a&&(v=s),(z=B.nextSibling)!==null)break;B=N,N=B.parentNode}B=z}l=d===-1||v===-1?null:{start:d,end:v}}else l=null}l=l||{start:0,end:0}}else l=null;for(Qs={focusedElem:e,selectionRange:l},Ou=!1,nt=t;nt!==null;)if(t=nt,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,nt=e;else for(;nt!==null;){switch(t=nt,i=t.alternate,e=t.flags,t.tag){case 0:if((e&4)!==0&&(e=t.updateQueue,e=e!==null?e.events:null,e!==null))for(l=0;l title"))),dt(i,a,l),i[st]=e,at(i),a=i;break e;case"link":var s=wm("link","href",n).get(a+(l.href||""));if(s){for(var d=0;dNe&&(s=Ne,Ne=te,te=s);var E=Gr(d,te),_=Gr(d,Ne);if(E&&_&&(z.rangeCount!==1||z.anchorNode!==E.node||z.anchorOffset!==E.offset||z.focusNode!==_.node||z.focusOffset!==_.offset)){var T=B.createRange();T.setStart(E.node,E.offset),z.removeAllRanges(),te>Ne?(z.addRange(T),z.extend(_.node,_.offset)):(T.setEnd(_.node,_.offset),z.addRange(T))}}}}for(B=[],z=d;z=z.parentNode;)z.nodeType===1&&B.push({element:z,left:z.scrollLeft,top:z.scrollTop});for(typeof d.focus=="function"&&d.focus(),d=0;dl?32:l,R.T=null,l=zs,zs=null;var i=Yl,s=Sl;if(lt=0,an=Yl=null,Sl=0,(Ce&6)!==0)throw Error(o(331));var d=Ce;if(Ce|=4,qd(i.current),Bd(i,i.current,s,l),Ce=d,ti(0,!1),pt&&typeof pt.onPostCommitFiberRoot=="function")try{pt.onPostCommitFiberRoot(na,i)}catch{}return!0}finally{q.p=n,R.T=a,am(e,t)}}function im(e,t,l){t=qt(l,t),t=os(e.stateNode,t,2),e=Ul(e,t,2),e!==null&&(Sn(e,2),al(e))}function Me(e,t,l){if(e.tag===3)im(e,e,l);else for(;t!==null;){if(t.tag===3){im(t,e,l);break}else if(t.tag===1){var a=t.stateNode;if(typeof t.type.getDerivedStateFromError=="function"||typeof a.componentDidCatch=="function"&&(Ll===null||!Ll.has(a))){e=qt(l,e),l=ud(2),a=Ul(t,l,2),a!==null&&(cd(l,a,t,e),Sn(a,2),al(a));break}}t=t.return}}function ws(e,t,l){var a=e.pingCache;if(a===null){a=e.pingCache=new Yv;var n=new Set;a.set(t,n)}else n=a.get(t),n===void 0&&(n=new Set,a.set(t,n));n.has(l)||(Ms=!0,n.add(l),e=Kv.bind(null,e,t,l),t.then(e,e))}function Kv(e,t,l){var a=e.pingCache;a!==null&&a.delete(t),e.pingedLanes|=e.suspendedLanes&l,e.warmLanes&=~l,Re===e&&(pe&l)===l&&(Qe===4||Qe===3&&(pe&62914560)===pe&&300>Ve()-hu?(Ce&2)===0&&nn(e,0):Ts|=l,ln===pe&&(ln=0)),al(e)}function um(e,t){t===0&&(t=Po()),e=ra(e,t),e!==null&&(Sn(e,t),al(e))}function Jv(e){var t=e.memoizedState,l=0;t!==null&&(l=t.retryLane),um(e,l)}function $v(e,t){var l=0;switch(e.tag){case 31:case 13:var a=e.stateNode,n=e.memoizedState;n!==null&&(l=n.retryLane);break;case 19:a=e.stateNode;break;case 22:a=e.stateNode._retryCache;break;default:throw Error(o(314))}a!==null&&a.delete(t),um(e,l)}function Fv(e,t){return Ma(e,t)}var Su=null,cn=null,Us=!1,xu=!1,Bs=!1,Xl=0;function al(e){e!==cn&&e.next===null&&(cn===null?Su=cn=e:cn=cn.next=e),xu=!0,Us||(Us=!0,Iv())}function ti(e,t){if(!Bs&&xu){Bs=!0;do for(var l=!1,a=Su;a!==null;){if(e!==0){var n=a.pendingLanes;if(n===0)var i=0;else{var s=a.suspendedLanes,d=a.pingedLanes;i=(1<<31-ce(42|e)+1)-1,i&=n&~(s&~d),i=i&201326741?i&201326741|1:i?i|2:0}i!==0&&(l=!0,rm(a,i))}else i=pe,i=Mi(a,a===Re?i:0,a.cancelPendingCommit!==null||a.timeoutHandle!==-1),(i&3)===0||_n(a,i)||(l=!0,rm(a,i));a=a.next}while(l);Bs=!1}}function Wv(){cm()}function cm(){xu=Us=!1;var e=0;Xl!==0&&sy()&&(e=Xl);for(var t=Ve(),l=null,a=Su;a!==null;){var n=a.next,i=sm(a,t);i===0?(a.next=null,l===null?Su=n:l.next=n,n===null&&(cn=l)):(l=a,(e!==0||(i&3)!==0)&&(xu=!0)),a=n}lt!==0&<!==5||ti(e),Xl!==0&&(Xl=0)}function sm(e,t){for(var l=e.suspendedLanes,a=e.pingedLanes,n=e.expirationTimes,i=e.pendingLanes&-62914561;0d)break;var O=v.transferSize,B=v.initiatorType;O&&gm(B)&&(v=v.responseEnd,s+=O*(v"u"?null:document;function zm(e,t,l){var a=sn;if(a&&typeof t=="string"&&t){var n=Gt(t);n='link[rel="'+e+'"][href="'+n+'"]',typeof l=="string"&&(n+='[crossorigin="'+l+'"]'),Nm.has(n)||(Nm.add(n),e={rel:e,crossOrigin:l,href:t},a.querySelector(n)===null&&(t=a.createElement("link"),dt(t,"link",e),at(t),a.head.appendChild(t)))}}function yy(e){xl.D(e),zm("dns-prefetch",e,null)}function gy(e,t){xl.C(e,t),zm("preconnect",e,t)}function by(e,t,l){xl.L(e,t,l);var a=sn;if(a&&e&&t){var n='link[rel="preload"][as="'+Gt(t)+'"]';t==="image"&&l&&l.imageSrcSet?(n+='[imagesrcset="'+Gt(l.imageSrcSet)+'"]',typeof l.imageSizes=="string"&&(n+='[imagesizes="'+Gt(l.imageSizes)+'"]')):n+='[href="'+Gt(e)+'"]';var i=n;switch(t){case"style":i=on(e);break;case"script":i=rn(e)}Qt.has(i)||(e=x({rel:"preload",href:t==="image"&&l&&l.imageSrcSet?void 0:e,as:t},l),Qt.set(i,e),a.querySelector(n)!==null||t==="style"&&a.querySelector(ii(i))||t==="script"&&a.querySelector(ui(i))||(t=a.createElement("link"),dt(t,"link",e),at(t),a.head.appendChild(t)))}}function _y(e,t){xl.m(e,t);var l=sn;if(l&&e){var a=t&&typeof t.as=="string"?t.as:"script",n='link[rel="modulepreload"][as="'+Gt(a)+'"][href="'+Gt(e)+'"]',i=n;switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":i=rn(e)}if(!Qt.has(i)&&(e=x({rel:"modulepreload",href:e},t),Qt.set(i,e),l.querySelector(n)===null)){switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(l.querySelector(ui(i)))return}a=l.createElement("link"),dt(a,"link",e),at(a),l.head.appendChild(a)}}}function Sy(e,t,l){xl.S(e,t,l);var a=sn;if(a&&e){var n=za(a).hoistableStyles,i=on(e);t=t||"default";var s=n.get(i);if(!s){var d={loading:0,preload:null};if(s=a.querySelector(ii(i)))d.loading=5;else{e=x({rel:"stylesheet",href:e,"data-precedence":t},l),(l=Qt.get(i))&&Is(e,l);var v=s=a.createElement("link");at(v),dt(v,"link",e),v._p=new Promise(function(A,O){v.onload=A,v.onerror=O}),v.addEventListener("load",function(){d.loading|=1}),v.addEventListener("error",function(){d.loading|=2}),d.loading|=4,Tu(s,t,a)}s={type:"stylesheet",instance:s,count:1,state:d},n.set(i,s)}}}function xy(e,t){xl.X(e,t);var l=sn;if(l&&e){var a=za(l).hoistableScripts,n=rn(e),i=a.get(n);i||(i=l.querySelector(ui(n)),i||(e=x({src:e,async:!0},t),(t=Qt.get(n))&&Ps(e,t),i=l.createElement("script"),at(i),dt(i,"link",e),l.head.appendChild(i)),i={type:"script",instance:i,count:1,state:null},a.set(n,i))}}function jy(e,t){xl.M(e,t);var l=sn;if(l&&e){var a=za(l).hoistableScripts,n=rn(e),i=a.get(n);i||(i=l.querySelector(ui(n)),i||(e=x({src:e,async:!0,type:"module"},t),(t=Qt.get(n))&&Ps(e,t),i=l.createElement("script"),at(i),dt(i,"link",e),l.head.appendChild(i)),i={type:"script",instance:i,count:1,state:null},a.set(n,i))}}function Rm(e,t,l,a){var n=(n=ne.current)?Mu(n):null;if(!n)throw Error(o(446));switch(e){case"meta":case"title":return null;case"style":return typeof l.precedence=="string"&&typeof l.href=="string"?(t=on(l.href),l=za(n).hoistableStyles,a=l.get(t),a||(a={type:"style",instance:null,count:0,state:null},l.set(t,a)),a):{type:"void",instance:null,count:0,state:null};case"link":if(l.rel==="stylesheet"&&typeof l.href=="string"&&typeof l.precedence=="string"){e=on(l.href);var i=za(n).hoistableStyles,s=i.get(e);if(s||(n=n.ownerDocument||n,s={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},i.set(e,s),(i=n.querySelector(ii(e)))&&!i._p&&(s.instance=i,s.state.loading=5),Qt.has(e)||(l={rel:"preload",as:"style",href:l.href,crossOrigin:l.crossOrigin,integrity:l.integrity,media:l.media,hrefLang:l.hrefLang,referrerPolicy:l.referrerPolicy},Qt.set(e,l),i||Cy(n,e,l,s.state))),t&&a===null)throw Error(o(528,""));return s}if(t&&a!==null)throw Error(o(529,""));return null;case"script":return t=l.async,l=l.src,typeof l=="string"&&t&&typeof t!="function"&&typeof t!="symbol"?(t=rn(l),l=za(n).hoistableScripts,a=l.get(t),a||(a={type:"script",instance:null,count:0,state:null},l.set(t,a)),a):{type:"void",instance:null,count:0,state:null};default:throw Error(o(444,e))}}function on(e){return'href="'+Gt(e)+'"'}function ii(e){return'link[rel="stylesheet"]['+e+"]"}function Om(e){return x({},e,{"data-precedence":e.precedence,precedence:null})}function Cy(e,t,l,a){e.querySelector('link[rel="preload"][as="style"]['+t+"]")?a.loading=1:(t=e.createElement("link"),a.preload=t,t.addEventListener("load",function(){return a.loading|=1}),t.addEventListener("error",function(){return a.loading|=2}),dt(t,"link",l),at(t),e.head.appendChild(t))}function rn(e){return'[src="'+Gt(e)+'"]'}function ui(e){return"script[async]"+e}function Dm(e,t,l){if(t.count++,t.instance===null)switch(t.type){case"style":var a=e.querySelector('style[data-href~="'+Gt(l.href)+'"]');if(a)return t.instance=a,at(a),a;var n=x({},l,{"data-href":l.href,"data-precedence":l.precedence,href:null,precedence:null});return a=(e.ownerDocument||e).createElement("style"),at(a),dt(a,"style",n),Tu(a,l.precedence,e),t.instance=a;case"stylesheet":n=on(l.href);var i=e.querySelector(ii(n));if(i)return t.state.loading|=4,t.instance=i,at(i),i;a=Om(l),(n=Qt.get(n))&&Is(a,n),i=(e.ownerDocument||e).createElement("link"),at(i);var s=i;return s._p=new Promise(function(d,v){s.onload=d,s.onerror=v}),dt(i,"link",a),t.state.loading|=4,Tu(i,l.precedence,e),t.instance=i;case"script":return i=rn(l.src),(n=e.querySelector(ui(i)))?(t.instance=n,at(n),n):(a=l,(n=Qt.get(i))&&(a=x({},l),Ps(a,n)),e=e.ownerDocument||e,n=e.createElement("script"),at(n),dt(n,"link",a),e.head.appendChild(n),t.instance=n);case"void":return null;default:throw Error(o(443,t.type))}else t.type==="stylesheet"&&(t.state.loading&4)===0&&(a=t.instance,t.state.loading|=4,Tu(a,l.precedence,e));return t.instance}function Tu(e,t,l){for(var a=l.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),n=a.length?a[a.length-1]:null,i=n,s=0;s title"):null)}function Ey(e,t,l){if(l===1||t.itemProp!=null)return!1;switch(e){case"meta":case"title":return!0;case"style":if(typeof t.precedence!="string"||typeof t.href!="string"||t.href==="")break;return!0;case"link":if(typeof t.rel!="string"||typeof t.href!="string"||t.href===""||t.onLoad||t.onError)break;return t.rel==="stylesheet"?(e=t.disabled,typeof t.precedence=="string"&&e==null):!0;case"script":if(t.async&&typeof t.async!="function"&&typeof t.async!="symbol"&&!t.onLoad&&!t.onError&&t.src&&typeof t.src=="string")return!0}return!1}function Bm(e){return!(e.type==="stylesheet"&&(e.state.loading&3)===0)}function My(e,t,l,a){if(l.type==="stylesheet"&&(typeof a.media!="string"||matchMedia(a.media).matches!==!1)&&(l.state.loading&4)===0){if(l.instance===null){var n=on(a.href),i=t.querySelector(ii(n));if(i){t=i._p,t!==null&&typeof t=="object"&&typeof t.then=="function"&&(e.count++,e=Nu.bind(e),t.then(e,e)),l.state.loading|=4,l.instance=i,at(i);return}i=t.ownerDocument||t,a=Om(a),(n=Qt.get(n))&&Is(a,n),i=i.createElement("link"),at(i);var s=i;s._p=new Promise(function(d,v){s.onload=d,s.onerror=v}),dt(i,"link",a),l.instance=i}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(l,t),(t=l.state.preload)&&(l.state.loading&3)===0&&(e.count++,l=Nu.bind(e),t.addEventListener("load",l),t.addEventListener("error",l))}}var eo=0;function Ty(e,t){return e.stylesheets&&e.count===0&&Ru(e,e.stylesheets),0eo?50:800)+t);return e.unsuspend=l,function(){e.unsuspend=null,clearTimeout(a),clearTimeout(n)}}:null}function Nu(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)Ru(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var zu=null;function Ru(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,zu=new Map,t.forEach(Ay,e),zu=null,Nu.call(e))}function Ay(e,t){if(!(t.state.loading&4)){var l=zu.get(e);if(l)var a=l.get(null);else{l=new Map,zu.set(e,l);for(var n=e.querySelectorAll("link[data-precedence],style[data-precedence]"),i=0;i"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(u)}catch(r){console.error(r)}}return u(),fo.exports=Zy(),fo.exports}var Jy=Ky(),$y=Object.defineProperty,yn=(u,r)=>$y(u,"name",{value:r,configurable:!0}),xh=!!(typeof window<"u"&&window.document&&window.document.createElement);function Ut(u,r,{checkForDefaultPrevented:f=!0}={}){return yn(function(m){if(u?.(m),f===!1||!m||!m.defaultPrevented)return r?.(m)},"handleEvent")}yn(Ut,"composeEventHandlers");function Fy(u){if(!xh)throw new Error("Cannot access window outside of the DOM");return u?.ownerDocument?.defaultView??window}yn(Fy,"getOwnerWindow");function xo(u){if(!xh)throw new Error("Cannot access document outside of the DOM");return u?.ownerDocument??document}yn(xo,"getOwnerDocument");function jh(u,r=!1){const{activeElement:f}=xo(u);if(!f?.nodeName)return null;if(Ch(f)&&f.contentDocument)return jh(f.contentDocument.body,r);if(r){const o=f.getAttribute("aria-activedescendant");if(o){const m=xo(f).getElementById(o);if(m)return m}}return f}yn(jh,"getActiveElement");function Ch(u){return u.tagName==="IFRAME"}yn(Ch,"isFrame");var Wy=Object.defineProperty,Zt=(u,r)=>Wy(u,"name",{value:r,configurable:!0});function Iy(u,r){const f=b.createContext(r);f.displayName=u+"Context";const o=Zt(h=>{const{children:S,...M}=h,j=b.useMemo(()=>M,Object.values(M));return c.jsx(f.Provider,{value:j,children:S})},"Provider");o.displayName=u+"Provider";function m(h,S={}){const{optional:M=!1}=S,j=b.useContext(f);if(j)return j;if(r!==void 0)return r;if(!M)throw new Error(`\`${h}\` must be used within \`${u}\``)}return Zt(m,"useContext"),[o,m]}Zt(Iy,"createContext");function ea(u,r=[]){let f=[];function o(h,S){const M=b.createContext(S);M.displayName=h+"Context";const j=f.length;f=[...f,S];const y=Zt(x=>{const{scope:D,children:H,...L}=x,Q=D?.[u]?.[j]||M,V=b.useMemo(()=>L,Object.values(L));return c.jsx(Q.Provider,{value:V,children:H})},"Provider");y.displayName=h+"Provider";function p(x,D,H={}){const{optional:L=!1}=H,Q=D?.[u]?.[j]||M,V=b.useContext(Q);if(V)return V;if(S!==void 0)return S;if(!L)throw new Error(`\`${x}\` must be used within \`${h}\``)}return Zt(p,"useContext"),[y,p]}Zt(o,"createContext");const m=Zt(()=>{const h=f.map(S=>b.createContext(S));return Zt(function(M){const j=M?.[u]||h;return b.useMemo(()=>({[`__scope${u}`]:{...M,[u]:j}}),[M,j])},"useScope")},"createScope");return m.scopeName=u,[o,Eh(m,...r)]}Zt(ea,"createContextScope");function Eh(...u){const r=u[0];if(u.length===1)return r;const f=Zt(()=>{const o=u.map(m=>({useScope:m(),scopeName:m.scopeName}));return Zt(function(h){const S=o.reduce((M,{useScope:j,scopeName:y})=>{const x=j(h)[`__scope${y}`];return{...M,...x}},{});return b.useMemo(()=>({[`__scope${r.scopeName}`]:S}),[S])},"useComposedScopes")},"createScope");return f.scopeName=r.scopeName,f}Zt(Eh,"composeContextScopes");var Il=globalThis?.document?b.useLayoutEffect:()=>{},Py=Object.defineProperty,eg=(u,r)=>Py(u,"name",{value:r,configurable:!0}),oh=vn[" useEffectEvent ".trim().toString()],rh=vn[" useInsertionEffect ".trim().toString()];function Mh(u){if(typeof oh=="function")return oh(u);const r=b.useRef(()=>{throw new Error("Cannot call an event handler while rendering.")});return typeof rh=="function"?rh(()=>{r.current=u}):Il(()=>{r.current=u}),b.useMemo(()=>((...f)=>r.current?.(...f)),[])}eg(Mh,"useEffectEvent");var tg=Object.defineProperty,pi=(u,r)=>tg(u,"name",{value:r,configurable:!0}),lg=vn[" useInsertionEffect ".trim().toString()]||Il;function vi({prop:u,defaultProp:r,onChange:f=pi(()=>{},"onChange"),caller:o}){const[m,h,S]=Th({defaultProp:r,onChange:f}),M=u!==void 0,j=M?u:m,y=b.useCallback(p=>{if(M){const x=Ah(p)?p(u):p;x!==u&&S.current?.(x)}else h(p)},[M,u,h,S]);return[j,y]}pi(vi,"useControllableState");function Th({defaultProp:u,onChange:r}){const[f,o]=b.useState(u),m=b.useRef(f),h=b.useRef(r);return lg(()=>{h.current=r},[r]),b.useEffect(()=>{m.current!==f&&(h.current?.(f),m.current=f)},[f,m]),[f,o,h]}pi(Th,"useUncontrolledState");function Ah(u){return typeof u=="function"}pi(Ah,"isFunction");var fh=Symbol("RADIX:SYNC_STATE");function ag(u,r,f,o){const{prop:m,defaultProp:h,onChange:S,caller:M}=r,j=m!==void 0,y=Mh(S),p=[{...f,state:h}];o&&p.push(o);const[x,D]=b.useReducer((V,k)=>{if(k.type===fh)return{...V,state:k.state};const Y=u(V,k);return j&&!Object.is(Y.state,V.state)&&y(Y.state),Y},...p),H=x.state,L=b.useRef(H);b.useEffect(()=>{L.current!==H&&(L.current=H,j||y(H))},[H,L,j]);const Q=b.useMemo(()=>m!==void 0?{...x,state:m}:x,[x,m]);return b.useEffect(()=>{j&&!Object.is(m,x.state)&&D({type:fh,state:m})},[m,x.state,j]),[Q,D]}pi(ag,"useControllableStateReducer");var ng=Object.defineProperty,wo=(u,r)=>ng(u,"name",{value:r,configurable:!0});function jo(u,r){if(typeof u=="function")return u(r);u!=null&&(u.current=r)}wo(jo,"setRef");function Nh(...u){return r=>{let f=!1;const o=u.map(m=>{const h=jo(m,r);return!f&&typeof h=="function"&&(f=!0),h});if(f)return()=>{for(let m=0;mig(u,"name",{value:r,configurable:!0});function mn(u){const r=b.forwardRef((f,o)=>{let{children:m,...h}=f,S=null,M=!1;const j=[];Co(m)&&typeof qu=="function"&&(m=qu(m._payload)),b.Children.forEach(m,D=>{if(Dh(D)){M=!0;const H=D;let L="child"in H.props?H.props.child:H.props.children;Co(L)&&typeof qu=="function"&&(L=qu(L._payload)),S=cg(H,L),j.push(S?.props?.children)}else j.push(D)}),S?S=b.cloneElement(S,void 0,j):!M&&b.Children.count(m)===1&&b.isValidElement(m)&&(S=m);const y=S?Oh(S):void 0,p=Ft(o,y);if(!S){if(m||m===0)throw new Error(M?rg(u):og(u));return m}const x=Rh(h,S.props??{});return S.type!==b.Fragment&&(x.ref=o?p:y),b.cloneElement(S,x)});return r.displayName=`${u}.Slot`,r}Wt(mn,"createSlot");var zh=Symbol.for("radix.slottable");function ug(u){const r=Wt(f=>"child"in f?f.children(f.child):f.children,"Slottable");return r.displayName=`${u}.Slottable`,r.__radixId=zh,r}Wt(ug,"createSlottable");var cg=Wt((u,r)=>{if("child"in u.props){const f=u.props.child;return b.isValidElement(f)?b.cloneElement(f,void 0,u.props.children(f.props.children)):null}return b.isValidElement(r)?r:null},"getSlottableElementFromSlottable");function Rh(u,r){const f={...r};for(const o in r){const m=u[o],h=r[o];/^on[A-Z]/.test(o)?m&&h?f[o]=(...M)=>{const j=h(...M);return m(...M),j}:m&&(f[o]=m):o==="style"?f[o]={...m,...h}:o==="className"&&(f[o]=[m,h].filter(Boolean).join(" "))}return{...u,...f}}Wt(Rh,"mergeProps");function Oh(u){let r=Object.getOwnPropertyDescriptor(u.props,"ref")?.get,f=r&&"isReactWarning"in r&&r.isReactWarning;return f?u.ref:(r=Object.getOwnPropertyDescriptor(u,"ref")?.get,f=r&&"isReactWarning"in r&&r.isReactWarning,f?u.props.ref:u.props.ref||u.ref)}Wt(Oh,"getElementRef");function Dh(u){return b.isValidElement(u)&&typeof u.type=="function"&&"__radixId"in u.type&&u.type.__radixId===zh}Wt(Dh,"isSlottable");var sg=Symbol.for("react.lazy");function Co(u){return u!=null&&typeof u=="object"&&"$$typeof"in u&&u.$$typeof===sg&&"_payload"in u&&wh(u._payload)}Wt(Co,"isLazyComponent");function wh(u){return typeof u=="object"&&u!==null&&"then"in u}Wt(wh,"isPromiseLike");var og=Wt(u=>`${u} failed to slot onto its children. Expected a single React element child or \`Slottable\`.`,"createSlotError"),rg=Wt(u=>`${u} failed to slot onto its \`Slottable\`. Expected \`Slottable\` to receive a single React element child.`,"createSlottableError"),qu=vn[" use ".trim().toString()],fg=Object.defineProperty,dg=(u,r)=>fg(u,"name",{value:r,configurable:!0}),mg=["a","button","div","form","h2","h3","img","input","label","li","nav","ol","p","select","span","svg","ul"],Ct=mg.reduce((u,r)=>{const f=mn(`Primitive.${r}`),o=b.forwardRef((m,h)=>{const{asChild:S,...M}=m,j=S?f:r;return typeof window<"u"&&(window[Symbol.for("radix-ui")]=!0),c.jsx(j,{...M,ref:h})});return o.displayName=`Primitive.${r}`,{...u,[r]:o}},{});function hg(u,r){u&&Do.flushSync(()=>u.dispatchEvent(r))}dg(hg,"dispatchDiscreteCustomEvent");var pg=Object.defineProperty,Cl=(u,r)=>pg(u,"name",{value:r,configurable:!0});function Uh(u,r){return b.useReducer((f,o)=>r[f][o]??f,u)}Cl(Uh,"useStateMachine");var Bh=Cl(u=>{const{present:r,children:f}=u,o=Gh(r),m=typeof f=="function"?f({present:o.isPresent}):b.Children.only(f),h=Hh(o.ref,qh(m));return typeof f=="function"||o.isPresent?b.cloneElement(m,{ref:h}):null},"Presence");function Gh(u){const[r,f]=b.useState(),o=b.useRef(null),m=b.useRef(u),h=b.useRef("none"),S=b.useRef(void 0),M=u?"mounted":"unmounted",[j,y]=Uh(M,{mounted:{UNMOUNT:"unmounted",ANIMATION_OUT:"unmountSuspended"},unmountSuspended:{MOUNT:"mounted",ANIMATION_END:"unmounted"},unmounted:{MOUNT:"mounted"}});return b.useEffect(()=>{j==="mounted"?(h.current=S.current??dn(o.current),S.current=void 0):h.current="none"},[j]),Il(()=>{const p=o.current,x=m.current;if(x!==u){const H=h.current,L=dn(p);u?(S.current=L,y("MOUNT")):L==="none"||p?.display==="none"?y("UNMOUNT"):y(x&&H!==L?"ANIMATION_OUT":"UNMOUNT"),m.current=u}},[u,y]),Il(()=>{if(r){let p;const x=r.ownerDocument.defaultView??window,D=Cl(L=>{const V=dn(o.current).includes(CSS.escape(L.animationName));if(L.target===r&&V&&(y("ANIMATION_END"),!m.current)){const k=r.style.animationFillMode;r.style.animationFillMode="forwards",p=x.setTimeout(()=>{r.style.animationFillMode==="forwards"&&(r.style.animationFillMode=k)})}},"handleAnimationEnd"),H=Cl(L=>{L.target===r&&(h.current=dn(o.current))},"handleAnimationStart");return r.addEventListener("animationstart",H),r.addEventListener("animationcancel",D),r.addEventListener("animationend",D),()=>{x.clearTimeout(p),r.removeEventListener("animationstart",H),r.removeEventListener("animationcancel",D),r.removeEventListener("animationend",D)}}else y("ANIMATION_END")},[r,y]),{isPresent:["mounted","unmountSuspended"].includes(j),ref:b.useCallback(p=>{if(p){const x=getComputedStyle(p);o.current=x,S.current=dn(x)}else o.current=null;f(p)},[])}}Cl(Gh,"usePresence");function Eo(u,r){if(typeof u=="function")return u(r);u!=null&&(u.current=r)}Cl(Eo,"setRef");function Hh(...u){const r=b.useRef(u);return r.current=u,b.useCallback(f=>{const o=r.current;let m=!1;const h=o.map(S=>{const M=Eo(S,f);return!m&&typeof M=="function"&&(m=!0),M});if(m)return()=>{for(let S=0;Svg(u,"name",{value:r,configurable:!0}),gg=vn[" useId ".trim().toString()]||(()=>{}),bg=0;function Lu(u){const[r,f]=b.useState(gg());return Il(()=>{u||f(o=>o??String(bg++))},[u]),u||(r?`radix-${r}`:"")}yg(Lu,"useId");var _g=Object.defineProperty,yi=(u,r)=>_g(u,"name",{value:r,configurable:!0}),Uo="Collapsible",[Sg,p1]=ea(Uo),[xg,Bo]=Sg(Uo),jg=b.forwardRef(yi(function(r,f){const{__scopeCollapsible:o,open:m,defaultOpen:h,disabled:S,onOpenChange:M,...j}=r,[y,p]=vi({prop:m,defaultProp:h??!1,onChange:M,caller:Uo});return c.jsx(xg,{scope:o,disabled:S,contentId:Lu(),open:y,onOpenToggle:b.useCallback(()=>p(x=>!x),[p]),children:c.jsx(Ct.div,{"data-state":Yu(y),"data-disabled":S?"":void 0,...j,ref:f})})},"Collapsible")),Cg="CollapsibleTrigger",Eg=b.forwardRef(yi(function(r,f){const{__scopeCollapsible:o,...m}=r,h=Bo(Cg,o);return c.jsx(Ct.button,{type:"button","aria-controls":h.open?h.contentId:void 0,"aria-expanded":h.open||!1,"data-state":Yu(h.open),"data-disabled":h.disabled?"":void 0,disabled:h.disabled,...m,ref:f,onClick:Ut(r.onClick,h.onOpenToggle)})},"CollapsibleTrigger")),kh="CollapsibleContent",Mg=b.forwardRef(yi(function(r,f){const{forceMount:o,...m}=r,h=Bo(kh,r.__scopeCollapsible);return c.jsx(Bh,{present:o||h.open,children:({present:S})=>c.jsx(Tg,{...m,ref:f,present:S})})},"CollapsibleContent")),Tg=b.forwardRef(yi(function(r,f){const{__scopeCollapsible:o,present:m,children:h,...S}=r,M=Bo(kh,o),[j,y]=b.useState(m),p=b.useRef(null),x=Ft(f,p),D=b.useRef(0),H=D.current,L=b.useRef(0),Q=L.current,V=M.open||j,k=b.useRef(V),Y=b.useRef(void 0);return b.useEffect(()=>{const G=requestAnimationFrame(()=>k.current=!1);return()=>cancelAnimationFrame(G)},[]),Il(()=>{const G=p.current;if(G){Y.current=Y.current||{transitionDuration:G.style.transitionDuration,animationName:G.style.animationName},G.style.transitionDuration="0s",G.style.animationName="none";const Z=G.getBoundingClientRect();D.current=Z.height,L.current=Z.width,k.current||(G.style.transitionDuration=Y.current.transitionDuration,G.style.animationName=Y.current.animationName),y(m)}},[M.open,m]),c.jsx(Ct.div,{"data-state":Yu(M.open),"data-disabled":M.disabled?"":void 0,id:M.contentId,hidden:!V,...S,ref:x,style:{"--radix-collapsible-content-height":H?`${H}px`:void 0,"--radix-collapsible-content-width":Q?`${Q}px`:void 0,...r.style},children:V&&h})},"CollapsibleContentImpl"));function Yu(u){return u?"open":"closed"}yi(Yu,"getState");var Ag=jg,Ng=Eg,zg=Mg,Rg=Object.defineProperty,Ml=(u,r)=>Rg(u,"name",{value:r,configurable:!0}),Lh="Progress",Go=100,[Og,v1]=ea(Lh),[Dg,wg]=Og(Lh),Ug=b.forwardRef(Ml(function(r,f){const{__scopeProgress:o,value:m=null,max:h,getValueLabel:S=Yh,...M}=r;(h||h===0)&&!Mo(h)&&console.error(Vh(`${h}`,"Progress"));const j=Mo(h)?h:Go;m!==null&&!To(m,j)&&console.error(Xh(`${m}`,"Progress"));const y=To(m,j)?m:null,p=mi(y)?S(y,j):void 0;return c.jsx(Dg,{scope:o,value:y,max:j,children:c.jsx(Ct.div,{"aria-valuemax":j,"aria-valuemin":0,"aria-valuenow":mi(y)?y:void 0,"aria-valuetext":p,role:"progressbar","data-state":Ho(y,j),"data-value":y??void 0,"data-max":j,...M,ref:f})})},"Progress")),Bg="ProgressIndicator",Gg=b.forwardRef(Ml(function(r,f){const{__scopeProgress:o,...m}=r,h=wg(Bg,o);return c.jsx(Ct.div,{"data-state":Ho(h.value,h.max),"data-value":h.value??void 0,"data-max":h.max,...m,ref:f})},"ProgressIndicator"));function Yh(u,r){return`${Math.round(u/r*100)}%`}Ml(Yh,"defaultGetValueLabel");function Ho(u,r){return u==null?"indeterminate":u===r?"complete":"loading"}Ml(Ho,"getProgressState");function mi(u){return typeof u=="number"}Ml(mi,"isNumber");function Mo(u){return mi(u)&&!isNaN(u)&&u>0}Ml(Mo,"isValidMaxNumber");function To(u,r){return mi(u)&&!isNaN(u)&&u<=r&&u>=0}Ml(To,"isValidValueNumber");function Vh(u,r){return`Invalid prop \`max\` of value \`${u}\` supplied to \`${r}\`. Only numbers greater than 0 are valid max values. Defaulting to \`${Go}\`.`}Ml(Vh,"getInvalidMaxError");function Xh(u,r){return`Invalid prop \`value\` of value \`${u}\` supplied to \`${r}\`. The \`value\` prop must be: +`+a.stack}}var Ht=Object.prototype.hasOwnProperty,da=u.unstable_scheduleCallback,ma=u.unstable_cancelCallback,F=u.unstable_shouldYield,oe=u.unstable_requestPaint,me=u.unstable_now,mt=u.unstable_getCurrentPriorityLevel,Je=u.unstable_ImmediatePriority,cl=u.unstable_UserBlockingPriority,kt=u.unstable_NormalPriority,pl=u.unstable_LowPriority,ha=u.unstable_IdlePriority,Ai=u.log,zi=u.unstable_setDisableYieldValue,Bl=null,gt=null;function sl(e){if(typeof Ai=="function"&&zi(e),gt&&typeof gt.setStrictMode=="function")try{gt.setStrictMode(Bl,e)}catch{}}var ht=Math.clz32?Math.clz32:Iu,Fu=Math.log,Wu=Math.LN2;function Iu(e){return e>>>=0,e===0?32:31-(Fu(e)/Wu|0)|0}var pa=256,Ga=262144,Ba=4194304;function x(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function fe(e,t,l){var a=e.pendingLanes;if(a===0)return 0;var n=0,i=e.suspendedLanes,s=e.pingedLanes;e=e.warmLanes;var d=a&134217727;return d!==0?(a=d&~i,a!==0?n=x(a):(s&=d,s!==0?n=x(s):l||(l=d&~e,l!==0&&(n=x(l))))):(d=a&~i,d!==0?n=x(d):s!==0?n=x(s):l||(l=a&~e,l!==0&&(n=x(l)))),n===0?0:t!==0&&t!==n&&(t&i)===0&&(i=n&-n,l=t&-t,i>=l||i===32&&(l&4194048)!==0)?t:n}function pe(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Ve(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Ni(){var e=Ba;return Ba<<=1,(Ba&62914560)===0&&(Ba=4194304),e}function Pu(e){for(var t=[],l=0;31>l;l++)t.push(e);return t}function zn(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function Np(e,t,l,a,n,i){var s=e.pendingLanes;e.pendingLanes=l,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=l,e.entangledLanes&=l,e.errorRecoveryDisabledLanes&=l,e.shellSuspendCounter=0;var d=e.entanglements,v=e.expirationTimes,A=e.hiddenUpdates;for(l=s&~l;0"u")return null;try{return e.activeElement||e.body}catch{return e.body}}var Gp=/[\n"\\]/g;function Lt(e){return e.replace(Gp,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function ic(e,t,l,a,n,i,s,d){e.name="",s!=null&&typeof s!="function"&&typeof s!="symbol"&&typeof s!="boolean"?e.type=s:e.removeAttribute("type"),t!=null?s==="number"?(t===0&&e.value===""||e.value!=t)&&(e.value=""+qt(t)):e.value!==""+qt(t)&&(e.value=""+qt(t)):s!=="submit"&&s!=="reset"||e.removeAttribute("value"),t!=null?uc(e,s,qt(t)):l!=null?uc(e,s,qt(l)):a!=null&&e.removeAttribute("value"),n==null&&i!=null&&(e.defaultChecked=!!i),n!=null&&(e.checked=n&&typeof n!="function"&&typeof n!="symbol"),d!=null&&typeof d!="function"&&typeof d!="symbol"&&typeof d!="boolean"?e.name=""+qt(d):e.removeAttribute("name")}function pr(e,t,l,a,n,i,s,d){if(i!=null&&typeof i!="function"&&typeof i!="symbol"&&typeof i!="boolean"&&(e.type=i),t!=null||l!=null){if(!(i!=="submit"&&i!=="reset"||t!=null)){nc(e);return}l=l!=null?""+qt(l):"",t=t!=null?""+qt(t):l,d||t===e.value||(e.value=t),e.defaultValue=t}a=a??n,a=typeof a!="function"&&typeof a!="symbol"&&!!a,e.checked=d?e.checked:!!a,e.defaultChecked=!!a,s!=null&&typeof s!="function"&&typeof s!="symbol"&&typeof s!="boolean"&&(e.name=s),nc(e)}function uc(e,t,l){t==="number"&&Di(e.ownerDocument)===e||e.defaultValue===""+l||(e.defaultValue=""+l)}function Va(e,t,l,a){if(e=e.options,t){t={};for(var n=0;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),fc=!1;if(yl)try{var Dn={};Object.defineProperty(Dn,"passive",{get:function(){fc=!0}}),window.addEventListener("test",Dn,Dn),window.removeEventListener("test",Dn,Dn)}catch{fc=!1}var kl=null,dc=null,Ui=null;function xr(){if(Ui)return Ui;var e,t=dc,l=t.length,a,n="value"in kl?kl.value:kl.textContent,i=n.length;for(e=0;e=Gn),Ar=" ",zr=!1;function Nr(e,t){switch(e){case"keyup":return rv.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Rr(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var Ka=!1;function dv(e,t){switch(e){case"compositionend":return Rr(t);case"keypress":return t.which!==32?null:(zr=!0,Ar);case"textInput":return e=t.data,e===Ar&&zr?null:e;default:return null}}function mv(e,t){if(Ka)return e==="compositionend"||!gc&&Nr(e,t)?(e=xr(),Ui=dc=kl=null,Ka=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:l,offset:t-e};e=a}e:{for(;l;){if(l.nextSibling){l=l.nextSibling;break e}l=l.parentNode}l=void 0}l=kr(l)}}function Lr(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Lr(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Yr(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=Di(e.document);t instanceof e.HTMLIFrameElement;){try{var l=typeof t.contentWindow.location.href=="string"}catch{l=!1}if(l)e=t.contentWindow;else break;t=Di(e.document)}return t}function Sc(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}var _v=yl&&"documentMode"in document&&11>=document.documentMode,Ja=null,_c=null,qn=null,xc=!1;function Vr(e,t,l){var a=l.window===l?l.document:l.nodeType===9?l:l.ownerDocument;xc||Ja==null||Ja!==Di(a)||(a=Ja,"selectionStart"in a&&Sc(a)?a={start:a.selectionStart,end:a.selectionEnd}:(a=(a.ownerDocument&&a.ownerDocument.defaultView||window).getSelection(),a={anchorNode:a.anchorNode,anchorOffset:a.anchorOffset,focusNode:a.focusNode,focusOffset:a.focusOffset}),qn&&kn(qn,a)||(qn=a,a=Au(_c,"onSelect"),0>=s,n-=s,ol=1<<32-ht(t)+n|l<he?(be=te,te=null):be=te.sibling;var Ae=z(C,te,T[he],U);if(Ae===null){te===null&&(te=be);break}e&&te&&Ae.alternate===null&&t(C,te),b=i(Ae,b,he),Te===null?ae=Ae:Te.sibling=Ae,Te=Ae,te=be}if(he===T.length)return l(C,te),_e&&Sl(C,he),ae;if(te===null){for(;hehe?(be=te,te=null):be=te.sibling;var ca=z(C,te,Ae.value,U);if(ca===null){te===null&&(te=be);break}e&&te&&ca.alternate===null&&t(C,te),b=i(ca,b,he),Te===null?ae=ca:Te.sibling=ca,Te=ca,te=be}if(Ae.done)return l(C,te),_e&&Sl(C,he),ae;if(te===null){for(;!Ae.done;he++,Ae=T.next())Ae=B(C,Ae.value,U),Ae!==null&&(b=i(Ae,b,he),Te===null?ae=Ae:Te.sibling=Ae,Te=Ae);return _e&&Sl(C,he),ae}for(te=a(te);!Ae.done;he++,Ae=T.next())Ae=N(te,C,he,Ae.value,U),Ae!==null&&(e&&Ae.alternate!==null&&te.delete(Ae.key===null?he:Ae.key),b=i(Ae,b,he),Te===null?ae=Ae:Te.sibling=Ae,Te=Ae);return e&&te.forEach(function(Lg){return t(C,Lg)}),_e&&Sl(C,he),ae}function Ue(C,b,T,U){if(typeof T=="object"&&T!==null&&T.type===V&&T.key===null&&(T=T.props.children),typeof T=="object"&&T!==null){switch(T.$$typeof){case Y:e:{for(var ae=T.key;b!==null;){if(b.key===ae){if(ae=T.type,ae===V){if(b.tag===7){l(C,b.sibling),U=n(b,T.props.children),U.return=C,C=U;break e}}else if(b.elementType===ae||typeof ae=="object"&&ae!==null&&ae.$$typeof===ne&&Ea(ae)===b.type){l(C,b.sibling),U=n(b,T.props),Zn(U,T),U.return=C,C=U;break e}l(C,b);break}else t(C,b);b=b.sibling}T.type===V?(U=_a(T.props.children,C.mode,U,T.key),U.return=C,C=U):(U=Qi(T.type,T.key,T.props,null,C.mode,U),Zn(U,T),U.return=C,C=U)}return s(C);case H:e:{for(ae=T.key;b!==null;){if(b.key===ae)if(b.tag===4&&b.stateNode.containerInfo===T.containerInfo&&b.stateNode.implementation===T.implementation){l(C,b.sibling),U=n(b,T.children||[]),U.return=C,C=U;break e}else{l(C,b);break}else t(C,b);b=b.sibling}U=zc(T,C.mode,U),U.return=C,C=U}return s(C);case ne:return T=Ea(T),Ue(C,b,T,U)}if(Ye(T))return I(C,b,T,U);if(xe(T)){if(ae=xe(T),typeof ae!="function")throw Error(o(150));return T=ae.call(T),ie(C,b,T,U)}if(typeof T.then=="function")return Ue(C,b,Ii(T),U);if(T.$$typeof===w)return Ue(C,b,Ji(C,T),U);Pi(C,T)}return typeof T=="string"&&T!==""||typeof T=="number"||typeof T=="bigint"?(T=""+T,b!==null&&b.tag===6?(l(C,b.sibling),U=n(b,T),U.return=C,C=U):(l(C,b),U=Ac(T,C.mode,U),U.return=C,C=U),s(C)):l(C,b)}return function(C,b,T,U){try{Qn=0;var ae=Ue(C,b,T,U);return un=null,ae}catch(te){if(te===nn||te===Fi)throw te;var Te=zt(29,te,null,C.mode);return Te.lanes=U,Te.return=C,Te}}}var Aa=mf(!0),hf=mf(!1),Xl=!1;function Lc(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Yc(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Ql(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function Zl(e,t,l){var a=e.updateQueue;if(a===null)return null;if(a=a.shared,(ze&2)!==0){var n=a.pending;return n===null?t.next=t:(t.next=n.next,n.next=t),a.pending=t,t=Xi(e),Fr(e,null,l),t}return Vi(e,a,t,l),Xi(e)}function Kn(e,t,l){if(t=t.updateQueue,t!==null&&(t=t.shared,(l&4194048)!==0)){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,nr(e,l)}}function Vc(e,t){var l=e.updateQueue,a=e.alternate;if(a!==null&&(a=a.updateQueue,l===a)){var n=null,i=null;if(l=l.firstBaseUpdate,l!==null){do{var s={lane:l.lane,tag:l.tag,payload:l.payload,callback:null,next:null};i===null?n=i=s:i=i.next=s,l=l.next}while(l!==null);i===null?n=i=t:i=i.next=t}else n=i=t;l={baseState:a.baseState,firstBaseUpdate:n,lastBaseUpdate:i,shared:a.shared,callbacks:a.callbacks},e.updateQueue=l;return}e=l.lastBaseUpdate,e===null?l.firstBaseUpdate=t:e.next=t,l.lastBaseUpdate=t}var Xc=!1;function Jn(){if(Xc){var e=an;if(e!==null)throw e}}function $n(e,t,l,a){Xc=!1;var n=e.updateQueue;Xl=!1;var i=n.firstBaseUpdate,s=n.lastBaseUpdate,d=n.shared.pending;if(d!==null){n.shared.pending=null;var v=d,A=v.next;v.next=null,s===null?i=A:s.next=A,s=v;var D=e.alternate;D!==null&&(D=D.updateQueue,d=D.lastBaseUpdate,d!==s&&(d===null?D.firstBaseUpdate=A:d.next=A,D.lastBaseUpdate=v))}if(i!==null){var B=n.baseState;s=0,D=A=v=null,d=i;do{var z=d.lane&-536870913,N=z!==d.lane;if(N?(ye&z)===z:(a&z)===z){z!==0&&z===ln&&(Xc=!0),D!==null&&(D=D.next={lane:0,tag:d.tag,payload:d.payload,callback:null,next:null});e:{var I=e,ie=d;z=t;var Ue=l;switch(ie.tag){case 1:if(I=ie.payload,typeof I=="function"){B=I.call(Ue,B,z);break e}B=I;break e;case 3:I.flags=I.flags&-65537|128;case 0:if(I=ie.payload,z=typeof I=="function"?I.call(Ue,B,z):I,z==null)break e;B=M({},B,z);break e;case 2:Xl=!0}}z=d.callback,z!==null&&(e.flags|=64,N&&(e.flags|=8192),N=n.callbacks,N===null?n.callbacks=[z]:N.push(z))}else N={lane:z,tag:d.tag,payload:d.payload,callback:d.callback,next:null},D===null?(A=D=N,v=B):D=D.next=N,s|=z;if(d=d.next,d===null){if(d=n.shared.pending,d===null)break;N=d,d=N.next,N.next=null,n.lastBaseUpdate=N,n.shared.pending=null}}while(!0);D===null&&(v=B),n.baseState=v,n.firstBaseUpdate=A,n.lastBaseUpdate=D,i===null&&(n.shared.lanes=0),Wl|=s,e.lanes=s,e.memoizedState=B}}function pf(e,t){if(typeof e!="function")throw Error(o(191,e));e.call(t)}function vf(e,t){var l=e.callbacks;if(l!==null)for(e.callbacks=null,e=0;ei?i:8;var s=R.T,d={};R.T=d,os(e,!1,t,l);try{var v=n(),A=R.S;if(A!==null&&A(d,v),v!==null&&typeof v=="object"&&typeof v.then=="function"){var D=Nv(v,a);In(e,t,D,wt(e))}else In(e,t,a,wt(e))}catch(B){In(e,t,{then:function(){},status:"rejected",reason:B},wt())}finally{L.p=i,s!==null&&d.types!==null&&(s.types=d.types),R.T=s}}function Gv(){}function cs(e,t,l,a){if(e.tag!==5)throw Error(o(476));var n=Jf(e).queue;Kf(e,n,t,le,l===null?Gv:function(){return $f(e),l(a)})}function Jf(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:le,baseState:le,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Ml,lastRenderedState:le},next:null};var l={};return t.next={memoizedState:l,baseState:l,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Ml,lastRenderedState:l},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function $f(e){var t=Jf(e);t.next===null&&(t=e.alternate.memoizedState),In(e,t.next.queue,{},wt())}function ss(){return rt(pi)}function Ff(){return Fe().memoizedState}function Wf(){return Fe().memoizedState}function Bv(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var l=wt();e=Ql(l);var a=Zl(t,e,l);a!==null&&(Ct(a,t,l),Kn(a,t,l)),t={cache:Bc()},e.payload=t;return}t=t.return}}function Hv(e,t,l){var a=wt();l={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null},ou(e)?Pf(t,l):(l=Ec(e,t,l,a),l!==null&&(Ct(l,e,a),ed(l,t,a)))}function If(e,t,l){var a=wt();In(e,t,l,a)}function In(e,t,l,a){var n={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null};if(ou(e))Pf(t,n);else{var i=e.alternate;if(e.lanes===0&&(i===null||i.lanes===0)&&(i=t.lastRenderedReducer,i!==null))try{var s=t.lastRenderedState,d=i(s,l);if(n.hasEagerState=!0,n.eagerState=d,At(d,s))return Vi(e,t,n,0),Ge===null&&Yi(),!1}catch{}if(l=Ec(e,t,n,a),l!==null)return Ct(l,e,a),ed(l,t,a),!0}return!1}function os(e,t,l,a){if(a={lane:2,revertLane:Ls(),gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},ou(e)){if(t)throw Error(o(479))}else t=Ec(e,l,a,2),t!==null&&Ct(t,e,2)}function ou(e){var t=e.alternate;return e===de||t!==null&&t===de}function Pf(e,t){sn=lu=!0;var l=e.pending;l===null?t.next=t:(t.next=l.next,l.next=t),e.pending=t}function ed(e,t,l){if((l&4194048)!==0){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,nr(e,l)}}var Pn={readContext:rt,use:iu,useCallback:Ze,useContext:Ze,useEffect:Ze,useImperativeHandle:Ze,useLayoutEffect:Ze,useInsertionEffect:Ze,useMemo:Ze,useReducer:Ze,useRef:Ze,useState:Ze,useDebugValue:Ze,useDeferredValue:Ze,useTransition:Ze,useSyncExternalStore:Ze,useId:Ze,useHostTransitionStatus:Ze,useFormState:Ze,useActionState:Ze,useOptimistic:Ze,useMemoCache:Ze,useCacheRefresh:Ze};Pn.useEffectEvent=Ze;var td={readContext:rt,use:iu,useCallback:function(e,t){return yt().memoizedState=[e,t===void 0?null:t],e},useContext:rt,useEffect:Hf,useImperativeHandle:function(e,t,l){l=l!=null?l.concat([e]):null,cu(4194308,4,Yf.bind(null,t,e),l)},useLayoutEffect:function(e,t){return cu(4194308,4,e,t)},useInsertionEffect:function(e,t){cu(4,2,e,t)},useMemo:function(e,t){var l=yt();t=t===void 0?null:t;var a=e();if(za){sl(!0);try{e()}finally{sl(!1)}}return l.memoizedState=[a,t],a},useReducer:function(e,t,l){var a=yt();if(l!==void 0){var n=l(t);if(za){sl(!0);try{l(t)}finally{sl(!1)}}}else n=t;return a.memoizedState=a.baseState=n,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:n},a.queue=e,e=e.dispatch=Hv.bind(null,de,e),[a.memoizedState,e]},useRef:function(e){var t=yt();return e={current:e},t.memoizedState=e},useState:function(e){e=ls(e);var t=e.queue,l=If.bind(null,de,t);return t.dispatch=l,[e.memoizedState,l]},useDebugValue:is,useDeferredValue:function(e,t){var l=yt();return us(l,e,t)},useTransition:function(){var e=ls(!1);return e=Kf.bind(null,de,e.queue,!0,!1),yt().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,l){var a=de,n=yt();if(_e){if(l===void 0)throw Error(o(407));l=l()}else{if(l=t(),Ge===null)throw Error(o(349));(ye&127)!==0||xf(a,t,l)}n.memoizedState=l;var i={value:l,getSnapshot:t};return n.queue=i,Hf(Mf.bind(null,a,i,e),[e]),a.flags|=2048,rn(9,{destroy:void 0},jf.bind(null,a,i,l,t),null),l},useId:function(){var e=yt(),t=Ge.identifierPrefix;if(_e){var l=rl,a=ol;l=(a&~(1<<32-ht(a)-1)).toString(32)+l,t="_"+t+"R_"+l,l=au++,0<\/script>",i=i.removeChild(i.firstChild);break;case"select":i=typeof a.is=="string"?s.createElement("select",{is:a.is}):s.createElement("select"),a.multiple?i.multiple=!0:a.size&&(i.size=a.size);break;default:i=typeof a.is=="string"?s.createElement(n,{is:a.is}):s.createElement(n)}}i[st]=t,i[bt]=a;e:for(s=t.child;s!==null;){if(s.tag===5||s.tag===6)i.appendChild(s.stateNode);else if(s.tag!==4&&s.tag!==27&&s.child!==null){s.child.return=s,s=s.child;continue}if(s===t)break e;for(;s.sibling===null;){if(s.return===null||s.return===t)break e;s=s.return}s.sibling.return=s.return,s=s.sibling}t.stateNode=i;e:switch(dt(i,n,a),n){case"button":case"input":case"select":case"textarea":a=!!a.autoFocus;break e;case"img":a=!0;break e;default:a=!1}a&&El(t)}}return Le(t),js(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,l),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==a&&El(t);else{if(typeof a!="string"&&t.stateNode===null)throw Error(o(166));if(e=se.current,en(t)){if(e=t.stateNode,l=t.memoizedProps,a=null,n=ot,n!==null)switch(n.tag){case 27:case 5:a=n.memoizedProps}e[st]=t,e=!!(e.nodeValue===l||a!==null&&a.suppressHydrationWarning===!0||Sm(e.nodeValue,l)),e||Yl(t,!0)}else e=zu(e).createTextNode(a),e[st]=t,t.stateNode=e}return Le(t),null;case 31:if(l=t.memoizedState,e===null||e.memoizedState!==null){if(a=en(t),l!==null){if(e===null){if(!a)throw Error(o(318));if(e=t.memoizedState,e=e!==null?e.dehydrated:null,!e)throw Error(o(557));e[st]=t}else xa(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Le(t),e=!1}else l=Dc(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=l),e=!0;if(!e)return t.flags&256?(Rt(t),t):(Rt(t),null);if((t.flags&128)!==0)throw Error(o(558))}return Le(t),null;case 13:if(a=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(n=en(t),a!==null&&a.dehydrated!==null){if(e===null){if(!n)throw Error(o(318));if(n=t.memoizedState,n=n!==null?n.dehydrated:null,!n)throw Error(o(317));n[st]=t}else xa(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Le(t),n=!1}else n=Dc(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=n),n=!0;if(!n)return t.flags&256?(Rt(t),t):(Rt(t),null)}return Rt(t),(t.flags&128)!==0?(t.lanes=l,t):(l=a!==null,e=e!==null&&e.memoizedState!==null,l&&(a=t.child,n=null,a.alternate!==null&&a.alternate.memoizedState!==null&&a.alternate.memoizedState.cachePool!==null&&(n=a.alternate.memoizedState.cachePool.pool),i=null,a.memoizedState!==null&&a.memoizedState.cachePool!==null&&(i=a.memoizedState.cachePool.pool),i!==n&&(a.flags|=2048)),l!==e&&l&&(t.child.flags|=8192),hu(t,t.updateQueue),Le(t),null);case 4:return He(),e===null&&Qs(t.stateNode.containerInfo),Le(t),null;case 10:return xl(t.type),Le(t),null;case 19:if(G($e),a=t.memoizedState,a===null)return Le(t),null;if(n=(t.flags&128)!==0,i=a.rendering,i===null)if(n)ti(a,!1);else{if(Ke!==0||e!==null&&(e.flags&128)!==0)for(e=t.child;e!==null;){if(i=tu(e),i!==null){for(t.flags|=128,ti(a,!1),e=i.updateQueue,t.updateQueue=e,hu(t,e),t.subtreeFlags=0,e=l,l=t.child;l!==null;)Wr(l,e),l=l.sibling;return Q($e,$e.current&1|2),_e&&Sl(t,a.treeForkCount),t.child}e=e.sibling}a.tail!==null&&me()>bu&&(t.flags|=128,n=!0,ti(a,!1),t.lanes=4194304)}else{if(!n)if(e=tu(i),e!==null){if(t.flags|=128,n=!0,e=e.updateQueue,t.updateQueue=e,hu(t,e),ti(a,!0),a.tail===null&&a.tailMode==="hidden"&&!i.alternate&&!_e)return Le(t),null}else 2*me()-a.renderingStartTime>bu&&l!==536870912&&(t.flags|=128,n=!0,ti(a,!1),t.lanes=4194304);a.isBackwards?(i.sibling=t.child,t.child=i):(e=a.last,e!==null?e.sibling=i:t.child=i,a.last=i)}return a.tail!==null?(e=a.tail,a.rendering=e,a.tail=e.sibling,a.renderingStartTime=me(),e.sibling=null,l=$e.current,Q($e,n?l&1|2:l&1),_e&&Sl(t,a.treeForkCount),e):(Le(t),null);case 22:case 23:return Rt(t),Zc(),a=t.memoizedState!==null,e!==null?e.memoizedState!==null!==a&&(t.flags|=8192):a&&(t.flags|=8192),a?(l&536870912)!==0&&(t.flags&128)===0&&(Le(t),t.subtreeFlags&6&&(t.flags|=8192)):Le(t),l=t.updateQueue,l!==null&&hu(t,l.retryQueue),l=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(l=e.memoizedState.cachePool.pool),a=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(a=t.memoizedState.cachePool.pool),a!==l&&(t.flags|=2048),e!==null&&G(Ca),null;case 24:return l=null,e!==null&&(l=e.memoizedState.cache),t.memoizedState.cache!==l&&(t.flags|=2048),xl(We),Le(t),null;case 25:return null;case 30:return null}throw Error(o(156,t.tag))}function Vv(e,t){switch(Rc(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return xl(We),He(),e=t.flags,(e&65536)!==0&&(e&128)===0?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return Wt(t),null;case 31:if(t.memoizedState!==null){if(Rt(t),t.alternate===null)throw Error(o(340));xa()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(Rt(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(o(340));xa()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return G($e),null;case 4:return He(),null;case 10:return xl(t.type),null;case 22:case 23:return Rt(t),Zc(),e!==null&&G(Ca),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return xl(We),null;case 25:return null;default:return null}}function Cd(e,t){switch(Rc(t),t.tag){case 3:xl(We),He();break;case 26:case 27:case 5:Wt(t);break;case 4:He();break;case 31:t.memoizedState!==null&&Rt(t);break;case 13:Rt(t);break;case 19:G($e);break;case 10:xl(t.type);break;case 22:case 23:Rt(t),Zc(),e!==null&&G(Ca);break;case 24:xl(We)}}function li(e,t){try{var l=t.updateQueue,a=l!==null?l.lastEffect:null;if(a!==null){var n=a.next;l=n;do{if((l.tag&e)===e){a=void 0;var i=l.create,s=l.inst;a=i(),s.destroy=a}l=l.next}while(l!==n)}}catch(d){Oe(t,t.return,d)}}function $l(e,t,l){try{var a=t.updateQueue,n=a!==null?a.lastEffect:null;if(n!==null){var i=n.next;a=i;do{if((a.tag&e)===e){var s=a.inst,d=s.destroy;if(d!==void 0){s.destroy=void 0,n=t;var v=l,A=d;try{A()}catch(D){Oe(n,v,D)}}}a=a.next}while(a!==i)}}catch(D){Oe(t,t.return,D)}}function Ed(e){var t=e.updateQueue;if(t!==null){var l=e.stateNode;try{vf(t,l)}catch(a){Oe(e,e.return,a)}}}function Td(e,t,l){l.props=Na(e.type,e.memoizedProps),l.state=e.memoizedState;try{l.componentWillUnmount()}catch(a){Oe(e,t,a)}}function ai(e,t){try{var l=e.ref;if(l!==null){switch(e.tag){case 26:case 27:case 5:var a=e.stateNode;break;case 30:a=e.stateNode;break;default:a=e.stateNode}typeof l=="function"?e.refCleanup=l(a):l.current=a}}catch(n){Oe(e,t,n)}}function fl(e,t){var l=e.ref,a=e.refCleanup;if(l!==null)if(typeof a=="function")try{a()}catch(n){Oe(e,t,n)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof l=="function")try{l(null)}catch(n){Oe(e,t,n)}else l.current=null}function Ad(e){var t=e.type,l=e.memoizedProps,a=e.stateNode;try{e:switch(t){case"button":case"input":case"select":case"textarea":l.autoFocus&&a.focus();break e;case"img":l.src?a.src=l.src:l.srcSet&&(a.srcset=l.srcSet)}}catch(n){Oe(e,e.return,n)}}function Ms(e,t,l){try{var a=e.stateNode;fg(a,e.type,l,t),a[bt]=t}catch(n){Oe(e,e.return,n)}}function zd(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&la(e.type)||e.tag===4}function Cs(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||zd(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&la(e.type)||e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Es(e,t,l){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?(l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l).insertBefore(e,t):(t=l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l,t.appendChild(e),l=l._reactRootContainer,l!=null||t.onclick!==null||(t.onclick=gl));else if(a!==4&&(a===27&&la(e.type)&&(l=e.stateNode,t=null),e=e.child,e!==null))for(Es(e,t,l),e=e.sibling;e!==null;)Es(e,t,l),e=e.sibling}function pu(e,t,l){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?l.insertBefore(e,t):l.appendChild(e);else if(a!==4&&(a===27&&la(e.type)&&(l=e.stateNode),e=e.child,e!==null))for(pu(e,t,l),e=e.sibling;e!==null;)pu(e,t,l),e=e.sibling}function Nd(e){var t=e.stateNode,l=e.memoizedProps;try{for(var a=e.type,n=t.attributes;n.length;)t.removeAttributeNode(n[0]);dt(t,a,l),t[st]=e,t[bt]=l}catch(i){Oe(e,e.return,i)}}var Tl=!1,et=!1,Ts=!1,Rd=typeof WeakSet=="function"?WeakSet:Set,nt=null;function Xv(e,t){if(e=e.containerInfo,Js=Gu,e=Yr(e),Sc(e)){if("selectionStart"in e)var l={start:e.selectionStart,end:e.selectionEnd};else e:{l=(l=e.ownerDocument)&&l.defaultView||window;var a=l.getSelection&&l.getSelection();if(a&&a.rangeCount!==0){l=a.anchorNode;var n=a.anchorOffset,i=a.focusNode;a=a.focusOffset;try{l.nodeType,i.nodeType}catch{l=null;break e}var s=0,d=-1,v=-1,A=0,D=0,B=e,z=null;t:for(;;){for(var N;B!==l||n!==0&&B.nodeType!==3||(d=s+n),B!==i||a!==0&&B.nodeType!==3||(v=s+a),B.nodeType===3&&(s+=B.nodeValue.length),(N=B.firstChild)!==null;)z=B,B=N;for(;;){if(B===e)break t;if(z===l&&++A===n&&(d=s),z===i&&++D===a&&(v=s),(N=B.nextSibling)!==null)break;B=z,z=B.parentNode}B=N}l=d===-1||v===-1?null:{start:d,end:v}}else l=null}l=l||{start:0,end:0}}else l=null;for($s={focusedElem:e,selectionRange:l},Gu=!1,nt=t;nt!==null;)if(t=nt,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,nt=e;else for(;nt!==null;){switch(t=nt,i=t.alternate,e=t.flags,t.tag){case 0:if((e&4)!==0&&(e=t.updateQueue,e=e!==null?e.events:null,e!==null))for(l=0;l title"))),dt(i,a,l),i[st]=e,at(i),a=i;break e;case"link":var s=Bm("link","href",n).get(a+(l.href||""));if(s){for(var d=0;dUe&&(s=Ue,Ue=ie,ie=s);var C=qr(d,ie),b=qr(d,Ue);if(C&&b&&(N.rangeCount!==1||N.anchorNode!==C.node||N.anchorOffset!==C.offset||N.focusNode!==b.node||N.focusOffset!==b.offset)){var T=B.createRange();T.setStart(C.node,C.offset),N.removeAllRanges(),ie>Ue?(N.addRange(T),N.extend(b.node,b.offset)):(T.setEnd(b.node,b.offset),N.addRange(T))}}}}for(B=[],N=d;N=N.parentNode;)N.nodeType===1&&B.push({element:N,left:N.scrollLeft,top:N.scrollTop});for(typeof d.focus=="function"&&d.focus(),d=0;dl?32:l,R.T=null,l=ws,ws=null;var i=Pl,s=Ol;if(lt=0,pn=Pl=null,Ol=0,(ze&6)!==0)throw Error(o(331));var d=ze;if(ze|=4,Yd(i.current),kd(i,i.current,s,l),ze=d,oi(0,!1),gt&&typeof gt.onPostCommitFiberRoot=="function")try{gt.onPostCommitFiberRoot(Bl,i)}catch{}return!0}finally{L.p=n,R.T=a,um(e,t)}}function sm(e,t,l){t=Vt(l,t),t=ms(e.stateNode,t,2),e=Zl(e,t,2),e!==null&&(zn(e,2),dl(e))}function Oe(e,t,l){if(e.tag===3)sm(e,e,l);else for(;t!==null;){if(t.tag===3){sm(t,e,l);break}else if(t.tag===1){var a=t.stateNode;if(typeof t.type.getDerivedStateFromError=="function"||typeof a.componentDidCatch=="function"&&(Il===null||!Il.has(a))){e=Vt(l,e),l=od(2),a=Zl(t,l,2),a!==null&&(rd(l,a,t,e),zn(a,2),dl(a));break}}t=t.return}}function Hs(e,t,l){var a=e.pingCache;if(a===null){a=e.pingCache=new Kv;var n=new Set;a.set(t,n)}else n=a.get(t),n===void 0&&(n=new Set,a.set(t,n));n.has(l)||(Ns=!0,n.add(l),e=Iv.bind(null,e,t,l),t.then(e,e))}function Iv(e,t,l){var a=e.pingCache;a!==null&&a.delete(t),e.pingedLanes|=e.suspendedLanes&l,e.warmLanes&=~l,Ge===e&&(ye&l)===l&&(Ke===4||Ke===3&&(ye&62914560)===ye&&300>me()-yu?(ze&2)===0&&vn(e,0):Rs|=l,hn===ye&&(hn=0)),dl(e)}function om(e,t){t===0&&(t=Ni()),e=Sa(e,t),e!==null&&(zn(e,t),dl(e))}function Pv(e){var t=e.memoizedState,l=0;t!==null&&(l=t.retryLane),om(e,l)}function eg(e,t){var l=0;switch(e.tag){case 31:case 13:var a=e.stateNode,n=e.memoizedState;n!==null&&(l=n.retryLane);break;case 19:a=e.stateNode;break;case 22:a=e.stateNode._retryCache;break;default:throw Error(o(314))}a!==null&&a.delete(t),om(e,l)}function tg(e,t){return da(e,t)}var Cu=null,yn=null,ks=!1,Eu=!1,qs=!1,ta=0;function dl(e){e!==yn&&e.next===null&&(yn===null?Cu=yn=e:yn=yn.next=e),Eu=!0,ks||(ks=!0,ag())}function oi(e,t){if(!qs&&Eu){qs=!0;do for(var l=!1,a=Cu;a!==null;){if(e!==0){var n=a.pendingLanes;if(n===0)var i=0;else{var s=a.suspendedLanes,d=a.pingedLanes;i=(1<<31-ht(42|e)+1)-1,i&=n&~(s&~d),i=i&201326741?i&201326741|1:i?i|2:0}i!==0&&(l=!0,mm(a,i))}else i=ye,i=fe(a,a===Ge?i:0,a.cancelPendingCommit!==null||a.timeoutHandle!==-1),(i&3)===0||pe(a,i)||(l=!0,mm(a,i));a=a.next}while(l);qs=!1}}function lg(){rm()}function rm(){Eu=ks=!1;var e=0;ta!==0&&mg()&&(e=ta);for(var t=me(),l=null,a=Cu;a!==null;){var n=a.next,i=fm(a,t);i===0?(a.next=null,l===null?Cu=n:l.next=n,n===null&&(yn=l)):(l=a,(e!==0||(i&3)!==0)&&(Eu=!0)),a=n}lt!==0&<!==5||oi(e),ta!==0&&(ta=0)}function fm(e,t){for(var l=e.suspendedLanes,a=e.pingedLanes,n=e.expirationTimes,i=e.pendingLanes&-62914561;0d)break;var D=v.transferSize,B=v.initiatorType;D&&_m(B)&&(v=v.responseEnd,s+=D*(v"u"?null:document;function Dm(e,t,l){var a=bn;if(a&&typeof t=="string"&&t){var n=Lt(t);n='link[rel="'+e+'"][href="'+n+'"]',typeof l=="string"&&(n+='[crossorigin="'+l+'"]'),Om.has(n)||(Om.add(n),e={rel:e,crossOrigin:l,href:t},a.querySelector(n)===null&&(t=a.createElement("link"),dt(t,"link",e),at(t),a.head.appendChild(t)))}}function xg(e){Dl.D(e),Dm("dns-prefetch",e,null)}function jg(e,t){Dl.C(e,t),Dm("preconnect",e,t)}function Mg(e,t,l){Dl.L(e,t,l);var a=bn;if(a&&e&&t){var n='link[rel="preload"][as="'+Lt(t)+'"]';t==="image"&&l&&l.imageSrcSet?(n+='[imagesrcset="'+Lt(l.imageSrcSet)+'"]',typeof l.imageSizes=="string"&&(n+='[imagesizes="'+Lt(l.imageSizes)+'"]')):n+='[href="'+Lt(e)+'"]';var i=n;switch(t){case"style":i=Sn(e);break;case"script":i=_n(e)}$t.has(i)||(e=M({rel:"preload",href:t==="image"&&l&&l.imageSrcSet?void 0:e,as:t},l),$t.set(i,e),a.querySelector(n)!==null||t==="style"&&a.querySelector(mi(i))||t==="script"&&a.querySelector(hi(i))||(t=a.createElement("link"),dt(t,"link",e),at(t),a.head.appendChild(t)))}}function Cg(e,t){Dl.m(e,t);var l=bn;if(l&&e){var a=t&&typeof t.as=="string"?t.as:"script",n='link[rel="modulepreload"][as="'+Lt(a)+'"][href="'+Lt(e)+'"]',i=n;switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":i=_n(e)}if(!$t.has(i)&&(e=M({rel:"modulepreload",href:e},t),$t.set(i,e),l.querySelector(n)===null)){switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(l.querySelector(hi(i)))return}a=l.createElement("link"),dt(a,"link",e),at(a),l.head.appendChild(a)}}}function Eg(e,t,l){Dl.S(e,t,l);var a=bn;if(a&&e){var n=La(a).hoistableStyles,i=Sn(e);t=t||"default";var s=n.get(i);if(!s){var d={loading:0,preload:null};if(s=a.querySelector(mi(i)))d.loading=5;else{e=M({rel:"stylesheet",href:e,"data-precedence":t},l),(l=$t.get(i))&&lo(e,l);var v=s=a.createElement("link");at(v),dt(v,"link",e),v._p=new Promise(function(A,D){v.onload=A,v.onerror=D}),v.addEventListener("load",function(){d.loading|=1}),v.addEventListener("error",function(){d.loading|=2}),d.loading|=4,Ru(s,t,a)}s={type:"stylesheet",instance:s,count:1,state:d},n.set(i,s)}}}function Tg(e,t){Dl.X(e,t);var l=bn;if(l&&e){var a=La(l).hoistableScripts,n=_n(e),i=a.get(n);i||(i=l.querySelector(hi(n)),i||(e=M({src:e,async:!0},t),(t=$t.get(n))&&ao(e,t),i=l.createElement("script"),at(i),dt(i,"link",e),l.head.appendChild(i)),i={type:"script",instance:i,count:1,state:null},a.set(n,i))}}function Ag(e,t){Dl.M(e,t);var l=bn;if(l&&e){var a=La(l).hoistableScripts,n=_n(e),i=a.get(n);i||(i=l.querySelector(hi(n)),i||(e=M({src:e,async:!0,type:"module"},t),(t=$t.get(n))&&ao(e,t),i=l.createElement("script"),at(i),dt(i,"link",e),l.head.appendChild(i)),i={type:"script",instance:i,count:1,state:null},a.set(n,i))}}function wm(e,t,l,a){var n=(n=se.current)?Nu(n):null;if(!n)throw Error(o(446));switch(e){case"meta":case"title":return null;case"style":return typeof l.precedence=="string"&&typeof l.href=="string"?(t=Sn(l.href),l=La(n).hoistableStyles,a=l.get(t),a||(a={type:"style",instance:null,count:0,state:null},l.set(t,a)),a):{type:"void",instance:null,count:0,state:null};case"link":if(l.rel==="stylesheet"&&typeof l.href=="string"&&typeof l.precedence=="string"){e=Sn(l.href);var i=La(n).hoistableStyles,s=i.get(e);if(s||(n=n.ownerDocument||n,s={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},i.set(e,s),(i=n.querySelector(mi(e)))&&!i._p&&(s.instance=i,s.state.loading=5),$t.has(e)||(l={rel:"preload",as:"style",href:l.href,crossOrigin:l.crossOrigin,integrity:l.integrity,media:l.media,hrefLang:l.hrefLang,referrerPolicy:l.referrerPolicy},$t.set(e,l),i||zg(n,e,l,s.state))),t&&a===null)throw Error(o(528,""));return s}if(t&&a!==null)throw Error(o(529,""));return null;case"script":return t=l.async,l=l.src,typeof l=="string"&&t&&typeof t!="function"&&typeof t!="symbol"?(t=_n(l),l=La(n).hoistableScripts,a=l.get(t),a||(a={type:"script",instance:null,count:0,state:null},l.set(t,a)),a):{type:"void",instance:null,count:0,state:null};default:throw Error(o(444,e))}}function Sn(e){return'href="'+Lt(e)+'"'}function mi(e){return'link[rel="stylesheet"]['+e+"]"}function Um(e){return M({},e,{"data-precedence":e.precedence,precedence:null})}function zg(e,t,l,a){e.querySelector('link[rel="preload"][as="style"]['+t+"]")?a.loading=1:(t=e.createElement("link"),a.preload=t,t.addEventListener("load",function(){return a.loading|=1}),t.addEventListener("error",function(){return a.loading|=2}),dt(t,"link",l),at(t),e.head.appendChild(t))}function _n(e){return'[src="'+Lt(e)+'"]'}function hi(e){return"script[async]"+e}function Gm(e,t,l){if(t.count++,t.instance===null)switch(t.type){case"style":var a=e.querySelector('style[data-href~="'+Lt(l.href)+'"]');if(a)return t.instance=a,at(a),a;var n=M({},l,{"data-href":l.href,"data-precedence":l.precedence,href:null,precedence:null});return a=(e.ownerDocument||e).createElement("style"),at(a),dt(a,"style",n),Ru(a,l.precedence,e),t.instance=a;case"stylesheet":n=Sn(l.href);var i=e.querySelector(mi(n));if(i)return t.state.loading|=4,t.instance=i,at(i),i;a=Um(l),(n=$t.get(n))&&lo(a,n),i=(e.ownerDocument||e).createElement("link"),at(i);var s=i;return s._p=new Promise(function(d,v){s.onload=d,s.onerror=v}),dt(i,"link",a),t.state.loading|=4,Ru(i,l.precedence,e),t.instance=i;case"script":return i=_n(l.src),(n=e.querySelector(hi(i)))?(t.instance=n,at(n),n):(a=l,(n=$t.get(i))&&(a=M({},l),ao(a,n)),e=e.ownerDocument||e,n=e.createElement("script"),at(n),dt(n,"link",a),e.head.appendChild(n),t.instance=n);case"void":return null;default:throw Error(o(443,t.type))}else t.type==="stylesheet"&&(t.state.loading&4)===0&&(a=t.instance,t.state.loading|=4,Ru(a,l.precedence,e));return t.instance}function Ru(e,t,l){for(var a=l.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),n=a.length?a[a.length-1]:null,i=n,s=0;s title"):null)}function Ng(e,t,l){if(l===1||t.itemProp!=null)return!1;switch(e){case"meta":case"title":return!0;case"style":if(typeof t.precedence!="string"||typeof t.href!="string"||t.href==="")break;return!0;case"link":if(typeof t.rel!="string"||typeof t.href!="string"||t.href===""||t.onLoad||t.onError)break;return t.rel==="stylesheet"?(e=t.disabled,typeof t.precedence=="string"&&e==null):!0;case"script":if(t.async&&typeof t.async!="function"&&typeof t.async!="symbol"&&!t.onLoad&&!t.onError&&t.src&&typeof t.src=="string")return!0}return!1}function km(e){return!(e.type==="stylesheet"&&(e.state.loading&3)===0)}function Rg(e,t,l,a){if(l.type==="stylesheet"&&(typeof a.media!="string"||matchMedia(a.media).matches!==!1)&&(l.state.loading&4)===0){if(l.instance===null){var n=Sn(a.href),i=t.querySelector(mi(n));if(i){t=i._p,t!==null&&typeof t=="object"&&typeof t.then=="function"&&(e.count++,e=Du.bind(e),t.then(e,e)),l.state.loading|=4,l.instance=i,at(i);return}i=t.ownerDocument||t,a=Um(a),(n=$t.get(n))&&lo(a,n),i=i.createElement("link"),at(i);var s=i;s._p=new Promise(function(d,v){s.onload=d,s.onerror=v}),dt(i,"link",a),l.instance=i}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(l,t),(t=l.state.preload)&&(l.state.loading&3)===0&&(e.count++,l=Du.bind(e),t.addEventListener("load",l),t.addEventListener("error",l))}}var no=0;function Og(e,t){return e.stylesheets&&e.count===0&&Uu(e,e.stylesheets),0no?50:800)+t);return e.unsuspend=l,function(){e.unsuspend=null,clearTimeout(a),clearTimeout(n)}}:null}function Du(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)Uu(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var wu=null;function Uu(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,wu=new Map,t.forEach(Dg,e),wu=null,Du.call(e))}function Dg(e,t){if(!(t.state.loading&4)){var l=wu.get(e);if(l)var a=l.get(null);else{l=new Map,wu.set(e,l);for(var n=e.querySelectorAll("link[data-precedence],style[data-precedence]"),i=0;i"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(u)}catch(r){console.error(r)}}return u(),vo.exports=Wg(),vo.exports}var Pg=Ig(),ey=Object.defineProperty,Tn=(u,r)=>ey(u,"name",{value:r,configurable:!0}),Eh=!!(typeof window<"u"&&window.document&&window.document.createElement);function Bt(u,r,{checkForDefaultPrevented:f=!0}={}){return Tn(function(m){if(u?.(m),f===!1||!m||!m.defaultPrevented)return r?.(m)},"handleEvent")}Tn(Bt,"composeEventHandlers");function ty(u){if(!Eh)throw new Error("Cannot access window outside of the DOM");return u?.ownerDocument?.defaultView??window}Tn(ty,"getOwnerWindow");function Eo(u){if(!Eh)throw new Error("Cannot access document outside of the DOM");return u?.ownerDocument??document}Tn(Eo,"getOwnerDocument");function Th(u,r=!1){const{activeElement:f}=Eo(u);if(!f?.nodeName)return null;if(Ah(f)&&f.contentDocument)return Th(f.contentDocument.body,r);if(r){const o=f.getAttribute("aria-activedescendant");if(o){const m=Eo(f).getElementById(o);if(m)return m}}return f}Tn(Th,"getActiveElement");function Ah(u){return u.tagName==="IFRAME"}Tn(Ah,"isFrame");var ly=Object.defineProperty,Ft=(u,r)=>ly(u,"name",{value:r,configurable:!0});function ay(u,r){const f=g.createContext(r);f.displayName=u+"Context";const o=Ft(h=>{const{children:S,...E}=h,j=g.useMemo(()=>E,Object.values(E));return c.jsx(f.Provider,{value:j,children:S})},"Provider");o.displayName=u+"Provider";function m(h,S={}){const{optional:E=!1}=S,j=g.useContext(f);if(j)return j;if(r!==void 0)return r;if(!E)throw new Error(`\`${h}\` must be used within \`${u}\``)}return Ft(m,"useContext"),[o,m]}Ft(ay,"createContext");function ra(u,r=[]){let f=[];function o(h,S){const E=g.createContext(S);E.displayName=h+"Context";const j=f.length;f=[...f,S];const y=Ft(M=>{const{scope:O,children:Y,...H}=M,V=O?.[u]?.[j]||E,X=g.useMemo(()=>H,Object.values(H));return c.jsx(V.Provider,{value:X,children:Y})},"Provider");y.displayName=h+"Provider";function p(M,O,Y={}){const{optional:H=!1}=Y,V=O?.[u]?.[j]||E,X=g.useContext(V);if(X)return X;if(S!==void 0)return S;if(!H)throw new Error(`\`${M}\` must be used within \`${h}\``)}return Ft(p,"useContext"),[y,p]}Ft(o,"createContext");const m=Ft(()=>{const h=f.map(S=>g.createContext(S));return Ft(function(E){const j=E?.[u]||h;return g.useMemo(()=>({[`__scope${u}`]:{...E,[u]:j}}),[E,j])},"useScope")},"createScope");return m.scopeName=u,[o,zh(m,...r)]}Ft(ra,"createContextScope");function zh(...u){const r=u[0];if(u.length===1)return r;const f=Ft(()=>{const o=u.map(m=>({useScope:m(),scopeName:m.scopeName}));return Ft(function(h){const S=o.reduce((E,{useScope:j,scopeName:y})=>{const M=j(h)[`__scope${y}`];return{...E,...M}},{});return g.useMemo(()=>({[`__scope${r.scopeName}`]:S}),[S])},"useComposedScopes")},"createScope");return f.scopeName=r.scopeName,f}Ft(zh,"composeContextScopes");var sa=globalThis?.document?g.useLayoutEffect:()=>{},ny=Object.defineProperty,iy=(u,r)=>ny(u,"name",{value:r,configurable:!0}),dh=En[" useEffectEvent ".trim().toString()],mh=En[" useInsertionEffect ".trim().toString()];function Nh(u){if(typeof dh=="function")return dh(u);const r=g.useRef(()=>{throw new Error("Cannot call an event handler while rendering.")});return typeof mh=="function"?mh(()=>{r.current=u}):sa(()=>{r.current=u}),g.useMemo(()=>((...f)=>r.current?.(...f)),[])}iy(Nh,"useEffectEvent");var uy=Object.defineProperty,Mi=(u,r)=>uy(u,"name",{value:r,configurable:!0}),cy=En[" useInsertionEffect ".trim().toString()]||sa;function Ci({prop:u,defaultProp:r,onChange:f=Mi(()=>{},"onChange"),caller:o}){const[m,h,S]=Rh({defaultProp:r,onChange:f}),E=u!==void 0,j=E?u:m,y=g.useCallback(p=>{if(E){const M=Oh(p)?p(u):p;M!==u&&S.current?.(M)}else h(p)},[E,u,h,S]);return[j,y]}Mi(Ci,"useControllableState");function Rh({defaultProp:u,onChange:r}){const[f,o]=g.useState(u),m=g.useRef(f),h=g.useRef(r);return cy(()=>{h.current=r},[r]),g.useEffect(()=>{m.current!==f&&(h.current?.(f),m.current=f)},[f,m]),[f,o,h]}Mi(Rh,"useUncontrolledState");function Oh(u){return typeof u=="function"}Mi(Oh,"isFunction");var hh=Symbol("RADIX:SYNC_STATE");function sy(u,r,f,o){const{prop:m,defaultProp:h,onChange:S,caller:E}=r,j=m!==void 0,y=Nh(S),p=[{...f,state:h}];o&&p.push(o);const[M,O]=g.useReducer((X,k)=>{if(k.type===hh)return{...X,state:k.state};const Z=u(X,k);return j&&!Object.is(Z.state,X.state)&&y(Z.state),Z},...p),Y=M.state,H=g.useRef(Y);g.useEffect(()=>{H.current!==Y&&(H.current=Y,j||y(Y))},[Y,H,j]);const V=g.useMemo(()=>m!==void 0?{...M,state:m}:M,[M,m]);return g.useEffect(()=>{j&&!Object.is(m,M.state)&&O({type:hh,state:m})},[m,M.state,j]),[V,O]}Mi(sy,"useControllableStateReducer");var oy=Object.defineProperty,Ho=(u,r)=>oy(u,"name",{value:r,configurable:!0});function To(u,r){if(typeof u=="function")return u(r);u!=null&&(u.current=r)}Ho(To,"setRef");function Dh(...u){return r=>{let f=!1;const o=u.map(m=>{const h=To(m,r);return!f&&typeof h=="function"&&(f=!0),h});if(f)return()=>{for(let m=0;mry(u,"name",{value:r,configurable:!0});function Mn(u){const r=g.forwardRef((f,o)=>{let{children:m,...h}=f,S=null,E=!1;const j=[];Ao(m)&&typeof Vu=="function"&&(m=Vu(m._payload)),g.Children.forEach(m,O=>{if(Bh(O)){E=!0;const Y=O;let H="child"in Y.props?Y.props.child:Y.props.children;Ao(H)&&typeof Vu=="function"&&(H=Vu(H._payload)),S=dy(Y,H),j.push(S?.props?.children)}else j.push(O)}),S?S=g.cloneElement(S,void 0,j):!E&&g.Children.count(m)===1&&g.isValidElement(m)&&(S=m);const y=S?Gh(S):void 0,p=ll(o,y);if(!S){if(m||m===0)throw new Error(E?py(u):hy(u));return m}const M=Uh(h,S.props??{});return S.type!==g.Fragment&&(M.ref=o?p:y),g.cloneElement(S,M)});return r.displayName=`${u}.Slot`,r}nl(Mn,"createSlot");var wh=Symbol.for("radix.slottable");function fy(u){const r=nl(f=>"child"in f?f.children(f.child):f.children,"Slottable");return r.displayName=`${u}.Slottable`,r.__radixId=wh,r}nl(fy,"createSlottable");var dy=nl((u,r)=>{if("child"in u.props){const f=u.props.child;return g.isValidElement(f)?g.cloneElement(f,void 0,u.props.children(f.props.children)):null}return g.isValidElement(r)?r:null},"getSlottableElementFromSlottable");function Uh(u,r){const f={...r};for(const o in r){const m=u[o],h=r[o];/^on[A-Z]/.test(o)?m&&h?f[o]=(...E)=>{const j=h(...E);return m(...E),j}:m&&(f[o]=m):o==="style"?f[o]={...m,...h}:o==="className"&&(f[o]=[m,h].filter(Boolean).join(" "))}return{...u,...f}}nl(Uh,"mergeProps");function Gh(u){let r=Object.getOwnPropertyDescriptor(u.props,"ref")?.get,f=r&&"isReactWarning"in r&&r.isReactWarning;return f?u.ref:(r=Object.getOwnPropertyDescriptor(u,"ref")?.get,f=r&&"isReactWarning"in r&&r.isReactWarning,f?u.props.ref:u.props.ref||u.ref)}nl(Gh,"getElementRef");function Bh(u){return g.isValidElement(u)&&typeof u.type=="function"&&"__radixId"in u.type&&u.type.__radixId===wh}nl(Bh,"isSlottable");var my=Symbol.for("react.lazy");function Ao(u){return u!=null&&typeof u=="object"&&"$$typeof"in u&&u.$$typeof===my&&"_payload"in u&&Hh(u._payload)}nl(Ao,"isLazyComponent");function Hh(u){return typeof u=="object"&&u!==null&&"then"in u}nl(Hh,"isPromiseLike");var hy=nl(u=>`${u} failed to slot onto its children. Expected a single React element child or \`Slottable\`.`,"createSlotError"),py=nl(u=>`${u} failed to slot onto its \`Slottable\`. Expected \`Slottable\` to receive a single React element child.`,"createSlottableError"),Vu=En[" use ".trim().toString()],vy=Object.defineProperty,gy=(u,r)=>vy(u,"name",{value:r,configurable:!0}),yy=["a","button","div","form","h2","h3","img","input","label","li","nav","ol","p","select","span","svg","ul"],Et=yy.reduce((u,r)=>{const f=Mn(`Primitive.${r}`),o=g.forwardRef((m,h)=>{const{asChild:S,...E}=m,j=S?f:r;return typeof window<"u"&&(window[Symbol.for("radix-ui")]=!0),c.jsx(j,{...E,ref:h})});return o.displayName=`Primitive.${r}`,{...u,[r]:o}},{});function by(u,r){u&&Bo.flushSync(()=>u.dispatchEvent(r))}gy(by,"dispatchDiscreteCustomEvent");var Sy=Object.defineProperty,Ul=(u,r)=>Sy(u,"name",{value:r,configurable:!0});function kh(u,r){return g.useReducer((f,o)=>r[f][o]??f,u)}Ul(kh,"useStateMachine");var qh=Ul(u=>{const{present:r,children:f}=u,o=Lh(r),m=typeof f=="function"?f({present:o.isPresent}):g.Children.only(f),h=Yh(o.ref,Vh(m));return typeof f=="function"||o.isPresent?g.cloneElement(m,{ref:h}):null},"Presence");function Lh(u){const[r,f]=g.useState(),o=g.useRef(null),m=g.useRef(u),h=g.useRef("none"),S=g.useRef(void 0),E=u?"mounted":"unmounted",[j,y]=kh(E,{mounted:{UNMOUNT:"unmounted",ANIMATION_OUT:"unmountSuspended"},unmountSuspended:{MOUNT:"mounted",ANIMATION_END:"unmounted"},unmounted:{MOUNT:"mounted"}});return g.useEffect(()=>{j==="mounted"?(h.current=S.current??jn(o.current),S.current=void 0):h.current="none"},[j]),sa(()=>{const p=o.current,M=m.current;if(M!==u){const Y=h.current,H=jn(p);u?(S.current=H,y("MOUNT")):H==="none"||p?.display==="none"?y("UNMOUNT"):y(M&&Y!==H?"ANIMATION_OUT":"UNMOUNT"),m.current=u}},[u,y]),sa(()=>{if(r){let p;const M=r.ownerDocument.defaultView??window,O=Ul(H=>{const X=jn(o.current).includes(CSS.escape(H.animationName));if(H.target===r&&X&&(y("ANIMATION_END"),!m.current)){const k=r.style.animationFillMode;r.style.animationFillMode="forwards",p=M.setTimeout(()=>{r.style.animationFillMode==="forwards"&&(r.style.animationFillMode=k)})}},"handleAnimationEnd"),Y=Ul(H=>{H.target===r&&(h.current=jn(o.current))},"handleAnimationStart");return r.addEventListener("animationstart",Y),r.addEventListener("animationcancel",O),r.addEventListener("animationend",O),()=>{M.clearTimeout(p),r.removeEventListener("animationstart",Y),r.removeEventListener("animationcancel",O),r.removeEventListener("animationend",O)}}else y("ANIMATION_END")},[r,y]),{isPresent:["mounted","unmountSuspended"].includes(j),ref:g.useCallback(p=>{if(p){const M=getComputedStyle(p);o.current=M,S.current=jn(M)}else o.current=null;f(p)},[])}}Ul(Lh,"usePresence");function zo(u,r){if(typeof u=="function")return u(r);u!=null&&(u.current=r)}Ul(zo,"setRef");function Yh(...u){const r=g.useRef(u);return r.current=u,g.useCallback(f=>{const o=r.current;let m=!1;const h=o.map(S=>{const E=zo(S,f);return!m&&typeof E=="function"&&(m=!0),E});if(m)return()=>{for(let S=0;S_y(u,"name",{value:r,configurable:!0}),jy=En[" useId ".trim().toString()]||(()=>{}),My=0;function Zu(u){const[r,f]=g.useState(jy());return sa(()=>{u||f(o=>o??String(My++))},[u]),u||(r?`radix-${r}`:"")}xy(Zu,"useId");var Cy=Object.defineProperty,Ei=(u,r)=>Cy(u,"name",{value:r,configurable:!0}),ko="Collapsible",[Ey,x1]=ra(ko),[Ty,qo]=Ey(ko),Ay=g.forwardRef(Ei(function(r,f){const{__scopeCollapsible:o,open:m,defaultOpen:h,disabled:S,onOpenChange:E,...j}=r,[y,p]=Ci({prop:m,defaultProp:h??!1,onChange:E,caller:ko});return c.jsx(Ty,{scope:o,disabled:S,contentId:Zu(),open:y,onOpenToggle:g.useCallback(()=>p(M=>!M),[p]),children:c.jsx(Et.div,{"data-state":Ku(y),"data-disabled":S?"":void 0,...j,ref:f})})},"Collapsible")),zy="CollapsibleTrigger",Ny=g.forwardRef(Ei(function(r,f){const{__scopeCollapsible:o,...m}=r,h=qo(zy,o);return c.jsx(Et.button,{type:"button","aria-controls":h.open?h.contentId:void 0,"aria-expanded":h.open||!1,"data-state":Ku(h.open),"data-disabled":h.disabled?"":void 0,disabled:h.disabled,...m,ref:f,onClick:Bt(r.onClick,h.onOpenToggle)})},"CollapsibleTrigger")),Xh="CollapsibleContent",Ry=g.forwardRef(Ei(function(r,f){const{forceMount:o,...m}=r,h=qo(Xh,r.__scopeCollapsible);return c.jsx(qh,{present:o||h.open,children:({present:S})=>c.jsx(Oy,{...m,ref:f,present:S})})},"CollapsibleContent")),Oy=g.forwardRef(Ei(function(r,f){const{__scopeCollapsible:o,present:m,children:h,...S}=r,E=qo(Xh,o),[j,y]=g.useState(m),p=g.useRef(null),M=ll(f,p),O=g.useRef(0),Y=O.current,H=g.useRef(0),V=H.current,X=E.open||j,k=g.useRef(X),Z=g.useRef(void 0);return g.useEffect(()=>{const w=requestAnimationFrame(()=>k.current=!1);return()=>cancelAnimationFrame(w)},[]),sa(()=>{const w=p.current;if(w){Z.current=Z.current||{transitionDuration:w.style.transitionDuration,animationName:w.style.animationName},w.style.transitionDuration="0s",w.style.animationName="none";const q=w.getBoundingClientRect();O.current=q.height,H.current=q.width,k.current||(w.style.transitionDuration=Z.current.transitionDuration,w.style.animationName=Z.current.animationName),y(m)}},[E.open,m]),c.jsx(Et.div,{"data-state":Ku(E.open),"data-disabled":E.disabled?"":void 0,id:E.contentId,hidden:!X,...S,ref:M,style:{"--radix-collapsible-content-height":Y?`${Y}px`:void 0,"--radix-collapsible-content-width":V?`${V}px`:void 0,...r.style},children:X&&h})},"CollapsibleContentImpl"));function Ku(u){return u?"open":"closed"}Ei(Ku,"getState");var Dy=Ay,wy=Ny,Uy=Ry,Gy=Object.defineProperty,Gl=(u,r)=>Gy(u,"name",{value:r,configurable:!0}),Qh="Progress",Lo=100,[By,j1]=ra(Qh),[Hy,ky]=By(Qh),qy=g.forwardRef(Gl(function(r,f){const{__scopeProgress:o,value:m=null,max:h,getValueLabel:S=Zh,...E}=r;(h||h===0)&&!No(h)&&console.error(Kh(`${h}`,"Progress"));const j=No(h)?h:Lo;m!==null&&!Ro(m,j)&&console.error(Jh(`${m}`,"Progress"));const y=Ro(m,j)?m:null,p=xi(y)?S(y,j):void 0;return c.jsx(Hy,{scope:o,value:y,max:j,children:c.jsx(Et.div,{"aria-valuemax":j,"aria-valuemin":0,"aria-valuenow":xi(y)?y:void 0,"aria-valuetext":p,role:"progressbar","data-state":Yo(y,j),"data-value":y??void 0,"data-max":j,...E,ref:f})})},"Progress")),Ly="ProgressIndicator",Yy=g.forwardRef(Gl(function(r,f){const{__scopeProgress:o,...m}=r,h=ky(Ly,o);return c.jsx(Et.div,{"data-state":Yo(h.value,h.max),"data-value":h.value??void 0,"data-max":h.max,...m,ref:f})},"ProgressIndicator"));function Zh(u,r){return`${Math.round(u/r*100)}%`}Gl(Zh,"defaultGetValueLabel");function Yo(u,r){return u==null?"indeterminate":u===r?"complete":"loading"}Gl(Yo,"getProgressState");function xi(u){return typeof u=="number"}Gl(xi,"isNumber");function No(u){return xi(u)&&!isNaN(u)&&u>0}Gl(No,"isValidMaxNumber");function Ro(u,r){return xi(u)&&!isNaN(u)&&u<=r&&u>=0}Gl(Ro,"isValidValueNumber");function Kh(u,r){return`Invalid prop \`max\` of value \`${u}\` supplied to \`${r}\`. Only numbers greater than 0 are valid max values. Defaulting to \`${Lo}\`.`}Gl(Kh,"getInvalidMaxError");function Jh(u,r){return`Invalid prop \`value\` of value \`${u}\` supplied to \`${r}\`. The \`value\` prop must be: - a positive number - - less than the value passed to \`max\` (or ${Go} if no \`max\` prop is set) + - less than the value passed to \`max\` (or ${Lo} if no \`max\` prop is set) - \`null\` or \`undefined\` if the progress is indeterminate. -Defaulting to \`null\`.`}Ml(Xh,"getInvalidValueError");var Hg=Ug,qg=Gg,kg=Object.defineProperty,Lg=(u,r)=>kg(u,"name",{value:r,configurable:!0});function Qh(u){const[r,f]=b.useState(void 0);return Il(()=>{if(u){f({width:u.offsetWidth,height:u.offsetHeight});const o=new ResizeObserver(m=>{if(!Array.isArray(m)||!m.length)return;const h=m[0];let S,M;if("borderBoxSize"in h){const j=h.borderBoxSize,y=Array.isArray(j)?j[0]:j;S=y.inlineSize,M=y.blockSize}else S=u.offsetWidth,M=u.offsetHeight;f({width:S,height:M})});return o.observe(u,{box:"border-box"}),()=>o.unobserve(u)}else f(void 0)},[u]),r}Lg(Qh,"useSize");var Yg=Object.defineProperty,Pl=(u,r)=>Yg(u,"name",{value:r,configurable:!0}),qo="Switch",[Vg,y1]=ea(qo),[Xg,ko]=Vg(qo);function Zh(u){const{__scopeSwitch:r,checked:f,children:o,defaultChecked:m,disabled:h,form:S,name:M,onCheckedChange:j,required:y,value:p="on",internal_do_not_use_render:x}=u,[D,H]=vi({prop:f,defaultProp:m??!1,onChange:j,caller:qo}),[L,Q]=b.useState(null),[V,k]=b.useState(null),Y=b.useRef(!1),[G,Z]=b.useReducer(J=>J+1,0),le=L?!!S||!!L.closest("form"):!0,P={checked:D,setChecked:H,disabled:h,control:L,setControl:Q,name:M,form:S,value:p,hasConsumerStoppedPropagationRef:Y,userInteractionCount:G,onUserInteraction:Z,required:y,defaultChecked:m,isFormControl:le,bubbleInput:V,setBubbleInput:k};return c.jsx(Xg,{scope:r,...P,children:Kh(x)?x(P):o})}Pl(Zh,"SwitchProvider");var Qg="SwitchTrigger",Zg=b.forwardRef(Pl(function({__scopeSwitch:r,onClick:f,...o},m){const{control:h,form:S,value:M,disabled:j,checked:y,required:p,setControl:x,setChecked:D,hasConsumerStoppedPropagationRef:H,onUserInteraction:L,isFormControl:Q,bubbleInput:V}=ko(Qg,r),k=Ft(m,x),Y=b.useRef(y);return b.useEffect(()=>{const G=S?h?.ownerDocument.getElementById(S):h?.form;if(G instanceof HTMLFormElement){const Z=Pl(()=>D(Y.current),"reset");return G.addEventListener("reset",Z),()=>G.removeEventListener("reset",Z)}},[h,S,D]),c.jsx(Ct.button,{type:"button",role:"switch","aria-checked":y,"aria-required":p,"data-state":Lo(y),"data-disabled":j?"":void 0,disabled:j,value:M,...o,ref:k,onClick:Ut(f,G=>{L(),D(Z=>!Z),V&&Q&&(H.current=G.isPropagationStopped(),H.current||G.stopPropagation())})})},"SwitchTrigger")),Kg=b.forwardRef(Pl(function(r,f){const{__scopeSwitch:o,name:m,checked:h,defaultChecked:S,required:M,disabled:j,value:y,onCheckedChange:p,form:x,...D}=r;return c.jsx(Zh,{__scopeSwitch:o,checked:h,defaultChecked:S,disabled:j,required:M,onCheckedChange:p,name:m,form:x,value:y,internal_do_not_use_render:({isFormControl:H})=>c.jsxs(c.Fragment,{children:[c.jsx(Zg,{...D,ref:f,__scopeSwitch:o}),H&&c.jsx(Wg,{__scopeSwitch:o})]})})},"Switch")),Jg="SwitchThumb",$g=b.forwardRef(Pl(function(r,f){const{__scopeSwitch:o,...m}=r,h=ko(Jg,o);return c.jsx(Ct.span,{"data-state":Lo(h.checked),"data-disabled":h.disabled?"":void 0,...m,ref:f})},"SwitchThumb")),Fg="SwitchBubbleInput",Wg=b.forwardRef(Pl(function({__scopeSwitch:r,onClick:f,...o},m){const{control:h,hasConsumerStoppedPropagationRef:S,userInteractionCount:M,checked:j,defaultChecked:y,required:p,disabled:x,name:D,value:H,form:L,bubbleInput:Q,setBubbleInput:V}=ko(Fg,r),k=Ft(m,V),Y=Qh(h),G=b.useRef(!1),Z=b.useRef(j),le=b.useRef(M);b.useEffect(()=>{const J=Q;if(!J)return;const me=window.HTMLInputElement.prototype,He=Object.getOwnPropertyDescriptor(me,"checked").set,Ue=M!==le.current;le.current=M;const _e=Z.current!==j;Z.current=j;const ze=!(Ue&&S.current);if(_e&&He){G.current=!Ue;const Ze=new Event("click",{bubbles:ze});He.call(J,j),J.dispatchEvent(Ze),G.current=!1}},[Q,j,S,M]);const P=b.useRef(j);return c.jsx(Ct.input,{type:"checkbox","aria-hidden":!0,defaultChecked:y??P.current,required:p,disabled:x,name:D,value:H,form:L,...o,tabIndex:-1,ref:k,onClick:Ut(f,J=>{G.current&&J.stopPropagation()}),style:{...o.style,...Y,position:"absolute",pointerEvents:"none",opacity:0,margin:0,transform:"translateX(-100%)"}})},"SwitchBubbleInput"));function Kh(u){return typeof u=="function"}Pl(Kh,"isFunction");function Lo(u){return u?"checked":"unchecked"}Pl(Lo,"getState");var Ig=Object.defineProperty,ut=(u,r)=>Ig(u,"name",{value:r,configurable:!0});function Jh(u){const r=u+"CollectionProvider",[f,o]=ea(r),[m,h]=f(r,{collectionRef:{current:null},itemMap:new Map}),S=ut(Q=>{const{scope:V,children:k}=Q,Y=b.useRef(null),G=b.useRef(new Map).current;return c.jsx(m,{scope:V,itemMap:G,collectionRef:Y,children:k})},"CollectionProvider");S.displayName=r;const M=u+"CollectionSlot",j=mn(M),y=b.forwardRef((Q,V)=>{const{scope:k,children:Y}=Q,G=h(M,k),Z=Ft(V,G.collectionRef);return c.jsx(j,{ref:Z,children:Y})});y.displayName=M;const p=u+"CollectionItemSlot",x="data-radix-collection-item",D=mn(p),H=b.forwardRef((Q,V)=>{const{scope:k,children:Y,...G}=Q,Z=b.useRef(null),le=Ft(V,Z),P=h(p,k);return b.useEffect(()=>(P.itemMap.set(Z,{ref:Z,...G}),()=>{P.itemMap.delete(Z)})),c.jsx(D,{[x]:"",ref:le,children:Y})});H.displayName=p;function L(Q){const V=h(u+"CollectionConsumer",Q);return b.useCallback(()=>{const Y=V.collectionRef.current;if(!Y)return[];const G=Array.from(Y.querySelectorAll(`[${x}]`));return Array.from(V.itemMap.values()).sort((P,J)=>G.indexOf(P.ref.current)-G.indexOf(J.ref.current))},[V.collectionRef,V.itemMap])}return ut(L,"useCollection"),[{Provider:S,Slot:y,ItemSlot:H},L,o]}ut(Jh,"createCollection");var dh=new WeakMap,et,Dt,po=(Dt=class extends Map{constructor(f){super(f);Im(this,et);co(this,et,[...super.keys()]),dh.set(this,!0)}set(f,o){return dh.get(this)&&(this.has(f)?mt(this,et)[mt(this,et).indexOf(f)]=f:mt(this,et).push(f)),super.set(f,o),this}insert(f,o,m){const h=this.has(o),S=mt(this,et).length,M=Yo(f);let j=M>=0?M:S+M;const y=j<0||j>=S?-1:j;if(y===this.size||h&&y===this.size-1||y===-1)return this.set(o,m),this;const p=this.size+(h?0:1);M<0&&j++;const x=[...mt(this,et)];let D,H=!1;for(let L=j;L=this.size&&(h=this.size-1),this.at(h)}keyFrom(f,o){const m=this.indexOf(f);if(m===-1)return;let h=m+o;return h<0&&(h=0),h>=this.size&&(h=this.size-1),this.keyAt(h)}find(f,o){let m=0;for(const h of this){if(Reflect.apply(f,o,[h,m,this]))return h;m++}}findIndex(f,o){let m=0;for(const h of this){if(Reflect.apply(f,o,[h,m,this]))return m;m++}return-1}filter(f,o){const m=[];let h=0;for(const S of this)Reflect.apply(f,o,[S,h,this])&&m.push(S),h++;return new Dt(m)}map(f,o){const m=[];let h=0;for(const S of this)m.push([S[0],Reflect.apply(f,o,[S,h,this])]),h++;return new Dt(m)}reduce(...f){const[o,m]=f;let h=0,S=m??this.at(0);for(const M of this)h===0&&f.length===1?S=M:S=Reflect.apply(o,this,[S,M,h,this]),h++;return S}reduceRight(...f){const[o,m]=f;let h=m??this.at(-1);for(let S=this.size-1;S>=0;S--){const M=this.at(S);S===this.size-1&&f.length===1?h=M:h=Reflect.apply(o,this,[h,M,S,this])}return h}toSorted(f){const o=[...this.entries()].sort(f);return new Dt(o)}toReversed(){const f=new Dt;for(let o=this.size-1;o>=0;o--){const m=this.keyAt(o),h=this.get(m);f.set(m,h)}return f}toSpliced(...f){const o=[...this.entries()];return o.splice(...f),new Dt(o)}slice(f,o){const m=new Dt;let h=this.size-1;if(f===void 0)return m;f<0&&(f=f+this.size),o!==void 0&&o>0&&(h=o-1);for(let S=f;S<=h;S++){const M=this.keyAt(S),j=this.get(M);m.set(M,j)}return m}every(f,o){let m=0;for(const h of this){if(!Reflect.apply(f,o,[h,m,this]))return!1;m++}return!0}some(f,o){let m=0;for(const h of this){if(Reflect.apply(f,o,[h,m,this]))return!0;m++}return!1}},et=new WeakMap,ut(Dt,"OrderedDict"),Dt);function ku(u,r){if("at"in Array.prototype)return Array.prototype.at.call(u,r);const f=$h(u,r);return f===-1?void 0:u[f]}ut(ku,"at");function $h(u,r){const f=u.length,o=Yo(r),m=o>=0?o:f+o;return m<0||m>=f?-1:m}ut($h,"toSafeIndex");function Yo(u){return u!==u||u===0?0:Math.trunc(u)}ut(Yo,"toSafeInteger");function Pg(u){const r=u+"CollectionProvider",[f,o]=ea(r),[m,h]=f(r,{collectionElement:null,collectionRef:{current:null},collectionRefObject:{current:null},itemMap:new po,setItemMap:ut(()=>{},"setItemMap")}),S=ut(({state:G,...Z})=>G?c.jsx(j,{...Z,state:G}):c.jsx(M,{...Z}),"CollectionProvider");S.displayName=r;const M=ut(G=>{const Z=V();return c.jsx(j,{...G,state:Z})},"CollectionInit");M.displayName=r+"Init";const j=ut(G=>{const{scope:Z,children:le,state:P}=G,J=b.useRef(null),[me,ue]=b.useState(null),He=Ft(J,ue),[Ue,_e]=P;return b.useEffect(()=>{if(!me)return;const ze=Ih(()=>{});return ze.observe(me,{childList:!0,subtree:!0}),()=>{ze.disconnect()}},[me]),c.jsx(m,{scope:Z,itemMap:Ue,setItemMap:_e,collectionRef:He,collectionRefObject:J,collectionElement:me,children:le})},"CollectionProviderImpl");j.displayName=r+"Impl";const y=u+"CollectionSlot",p=mn(y),x=b.forwardRef((G,Z)=>{const{scope:le,children:P}=G,J=h(y,le),me=Ft(Z,J.collectionRef);return c.jsx(p,{ref:me,children:P})});x.displayName=y;const D=u+"CollectionItemSlot",H="data-radix-collection-item",L=mn(D),Q=b.forwardRef((G,Z)=>{const{scope:le,children:P,...J}=G,me=b.useRef(null),[ue,He]=b.useState(null),Ue=Ft(Z,me,He),_e=h(D,le),{setItemMap:ze}=_e,Ze=b.useRef(J);Fh(Ze.current,J)||(Ze.current=J);const Ke=Ze.current;return b.useEffect(()=>{const R=Ke;return ze(q=>ue?q.has(ue)?q.set(ue,{...R,element:ue}).toSorted(Ao):(q.set(ue,{...R,element:ue}),q.toSorted(Ao)):q),()=>{ze(q=>!ue||!q.has(ue)?q:(q.delete(ue),new po(q)))}},[ue,Ke,ze]),c.jsx(L,{[H]:"",ref:Ue,children:P})});Q.displayName=D;function V(){return b.useState(new po)}ut(V,"useInitCollection");function k(G){const{itemMap:Z}=h(u+"CollectionConsumer",G);return Z}return ut(k,"useCollection"),[{Provider:S,Slot:x,ItemSlot:Q},{createCollectionScope:o,useCollection:k,useInitCollection:V}]}ut(Pg,"createCollection");function Fh(u,r){if(u===r)return!0;if(typeof u!="object"||typeof r!="object"||u==null||r==null)return!1;const f=Object.keys(u),o=Object.keys(r);if(f.length!==o.length)return!1;for(const m of f)if(!Object.prototype.hasOwnProperty.call(r,m)||u[m]!==r[m])return!1;return!0}ut(Fh,"shallowEqual");function Wh(u,r){return!!(r.compareDocumentPosition(u)&Node.DOCUMENT_POSITION_PRECEDING)}ut(Wh,"isElementPreceding");function Ao(u,r){return!u[1].element||!r[1].element?0:Wh(u[1].element,r[1].element)?-1:1}ut(Ao,"sortByDocumentPosition");function Ih(u){return new MutationObserver(f=>{for(const o of f)if(o.type==="childList"){u();return}})}ut(Ih,"getChildListObserver");var e0=Object.defineProperty,t0=(u,r)=>e0(u,"name",{value:r,configurable:!0});function Ph(u){const r=b.useRef(u);return b.useEffect(()=>{r.current=u}),b.useMemo(()=>((...f)=>r.current?.(...f)),[])}t0(Ph,"useCallbackRef");var l0=Object.defineProperty,a0=(u,r)=>l0(u,"name",{value:r,configurable:!0}),n0=b.createContext(void 0);function Vo(u){const r=b.useContext(n0);return u||r||"ltr"}a0(Vo,"useDirection");var i0=Object.defineProperty,Xo=(u,r)=>i0(u,"name",{value:r,configurable:!0}),vo=!1;function ep(){const[u,r]=b.useState(vo);return b.useEffect(()=>{vo||(vo=!0,r(!0))},[]),u}Xo(ep,"useIsHydrated");var tp=vn[" useSyncExternalStore ".trim().toString()];function lp(){return()=>{}}Xo(lp,"subscribe");function ap(){return tp(lp,()=>!0,()=>!1)}Xo(ap,"useIsHydratedModern");var u0=typeof tp=="function"?ap:ep,c0=Object.defineProperty,Ca=(u,r)=>c0(u,"name",{value:r,configurable:!0}),yo="rovingFocusGroup.onEntryFocus",s0={bubbles:!1,cancelable:!0},Vu="RovingFocusGroup",[No,np,o0]=Jh(Vu),[r0,ip]=ea(Vu,[o0]),[f0,d0]=r0(Vu),m0=b.forwardRef(Ca(function(r,f){return c.jsx(No.Provider,{scope:r.__scopeRovingFocusGroup,children:c.jsx(No.Slot,{scope:r.__scopeRovingFocusGroup,children:c.jsx(h0,{...r,ref:f})})})},"RovingFocusGroup")),h0=b.forwardRef(Ca(function(r,f){const{__scopeRovingFocusGroup:o,orientation:m,loop:h=!1,dir:S,currentTabStopId:M,defaultCurrentTabStopId:j,onCurrentTabStopIdChange:y,onEntryFocus:p,preventScrollOnEntryFocus:x=!1,...D}=r,H=b.useRef(null),L=Ft(f,H),Q=Vo(S),[V,k]=vi({prop:M,defaultProp:j??null,onChange:y,caller:Vu}),[Y,G]=b.useState(!1),Z=Ph(p),le=np(o),P=b.useRef(!1),[J,me]=b.useState(0);return b.useEffect(()=>{const ue=H.current;if(ue)return ue.addEventListener(yo,Z),()=>ue.removeEventListener(yo,Z)},[Z]),c.jsx(f0,{scope:o,orientation:m,dir:Q,loop:h,currentTabStopId:V,onItemFocus:b.useCallback(ue=>k(ue),[k]),onItemShiftTab:b.useCallback(()=>G(!0),[]),onFocusableItemAdd:b.useCallback(()=>me(ue=>ue+1),[]),onFocusableItemRemove:b.useCallback(()=>me(ue=>ue-1),[]),children:c.jsx(Ct.div,{tabIndex:Y||J===0?-1:0,"data-orientation":m,...D,ref:L,style:{outline:"none",...r.style},onMouseDown:Ut(r.onMouseDown,()=>{P.current=!0}),onFocus:Ut(r.onFocus,ue=>{const He=!P.current;if(ue.target===ue.currentTarget&&He&&!Y){const Ue=new CustomEvent(yo,s0);if(ue.currentTarget.dispatchEvent(Ue),!Ue.defaultPrevented){const _e=le().filter(q=>q.focusable),ze=_e.find(q=>q.active),Ze=_e.find(q=>q.id===V),R=[ze,Ze,..._e].filter(Boolean).map(q=>q.ref.current);Qo(R,x)}}P.current=!1}),onBlur:Ut(r.onBlur,()=>G(!1))})})},"RovingFocusGroupImpl")),p0="RovingFocusGroupItem",v0=b.forwardRef(Ca(function(r,f){const{__scopeRovingFocusGroup:o,focusable:m=!0,active:h=!1,tabStopId:S,children:M,...j}=r,y=Lu(),p=S||y,x=d0(p0,o),D=x.currentTabStopId===p,H=np(o),{onFocusableItemAdd:L,onFocusableItemRemove:Q,currentTabStopId:V}=x,k=u0();return Il(()=>{if(!(!k||!m))return L(),()=>Q()},[k,m,L,Q]),b.useEffect(()=>{if(!(k||!m))return L(),()=>Q()},[k,m,L,Q]),c.jsx(No.ItemSlot,{scope:o,id:p,focusable:m,active:h,children:c.jsx(Ct.span,{tabIndex:D?0:-1,"data-orientation":x.orientation,...j,ref:f,onMouseDown:Ut(r.onMouseDown,Y=>{m?x.onItemFocus(p):Y.preventDefault()}),onFocus:Ut(r.onFocus,()=>x.onItemFocus(p)),onKeyDown:Ut(r.onKeyDown,Y=>{if(Y.key==="Tab"&&Y.shiftKey){x.onItemShiftTab();return}if(Y.target!==Y.currentTarget)return;const G=cp(Y,x.orientation,x.dir);if(G!==void 0){if(Y.metaKey||Y.ctrlKey||Y.altKey||Y.shiftKey)return;Y.preventDefault();let le=H().filter(P=>P.focusable).map(P=>P.ref.current);if(G==="last")le.reverse();else if(G==="prev"||G==="next"){G==="prev"&&le.reverse();const P=le.indexOf(Y.currentTarget);le=x.loop?sp(le,P+1):le.slice(P+1)}setTimeout(()=>Qo(le))}}),children:typeof M=="function"?M({isCurrentTabStop:D,hasTabStop:V!=null}):M})})},"RovingFocusGroupItem")),y0={ArrowLeft:"prev",ArrowUp:"prev",ArrowRight:"next",ArrowDown:"next",PageUp:"first",Home:"first",PageDown:"last",End:"last"};function up(u,r){return r!=="rtl"?u:u==="ArrowLeft"?"ArrowRight":u==="ArrowRight"?"ArrowLeft":u}Ca(up,"getDirectionAwareKey");function cp(u,r,f){const o=up(u.key,f);if(!(r==="vertical"&&["ArrowLeft","ArrowRight"].includes(o))&&!(r==="horizontal"&&["ArrowUp","ArrowDown"].includes(o)))return y0[o]}Ca(cp,"getFocusIntent");function Qo(u,r=!1){const f=document.activeElement;for(const o of u)if(o===f||(o.focus({preventScroll:r}),document.activeElement!==f))return}Ca(Qo,"focusFirst");function sp(u,r){return u.map((f,o)=>u[(r+o)%u.length])}Ca(sp,"wrapArray");var g0=m0,b0=v0,_0=Object.defineProperty,gn=(u,r)=>_0(u,"name",{value:r,configurable:!0}),Zo="Tabs",[S0,g1]=ea(Zo,[ip]),op=ip(),[x0,Ko]=S0(Zo),j0=b.forwardRef(gn(function(r,f){const{__scopeTabs:o,value:m,onValueChange:h,defaultValue:S,orientation:M="horizontal",dir:j,activationMode:y="automatic",...p}=r,x=Vo(j),[D,H]=vi({prop:m,onChange:h,defaultProp:S??"",caller:Zo});return c.jsx(x0,{scope:o,baseId:Lu(),value:D,onValueChange:H,orientation:M,dir:x,activationMode:y,children:c.jsx(Ct.div,{dir:x,"data-orientation":M,...p,ref:f})})},"Tabs")),C0="TabsList",E0=b.forwardRef(gn(function(r,f){const{__scopeTabs:o,loop:m=!0,...h}=r,S=Ko(C0,o),M=op(o);return c.jsx(g0,{asChild:!0,...M,orientation:S.orientation,dir:S.dir,loop:m,children:c.jsx(Ct.div,{role:"tablist","aria-orientation":S.orientation,...h,ref:f})})},"TabsList")),M0="TabsTrigger",T0=b.forwardRef(gn(function(r,f){const{__scopeTabs:o,value:m,disabled:h=!1,...S}=r,M=Ko(M0,o),j=op(o),y=Jo(M.baseId,m),p=$o(M.baseId,m),x=m===M.value;return c.jsx(b0,{asChild:!0,...j,focusable:!h,active:x,children:c.jsx(Ct.button,{type:"button",role:"tab","aria-selected":x,"aria-controls":p,"data-state":x?"active":"inactive","data-disabled":h?"":void 0,disabled:h,id:y,...S,ref:f,onMouseDown:Ut(r.onMouseDown,D=>{!h&&D.button===0&&D.ctrlKey===!1?M.onValueChange(m):D.preventDefault()}),onKeyDown:Ut(r.onKeyDown,D=>{h||D.target!==D.currentTarget||[" ","Enter"].includes(D.key)&&M.onValueChange(m)}),onFocus:Ut(r.onFocus,()=>{const D=M.activationMode!=="manual";!x&&!h&&D&&M.onValueChange(m)})})})},"TabsTrigger")),A0="TabsContent",N0=b.forwardRef(gn(function(r,f){const{__scopeTabs:o,value:m,forceMount:h,children:S,...M}=r,j=Ko(A0,o),y=Jo(j.baseId,m),p=$o(j.baseId,m),x=m===j.value,D=b.useRef(x);return b.useEffect(()=>{const H=requestAnimationFrame(()=>D.current=!1);return()=>cancelAnimationFrame(H)},[]),c.jsx(Bh,{present:h||x,children:({present:H})=>c.jsx(Ct.div,{"data-state":x?"active":"inactive","data-orientation":j.orientation,role:"tabpanel","aria-labelledby":y,hidden:!H,id:p,tabIndex:0,...M,ref:f,style:{...r.style,animationDuration:D.current?"0s":void 0},children:H&&S})})},"TabsContent"));function Jo(u,r){return`${u}-trigger-${r}`}gn(Jo,"makeTriggerId");function $o(u,r){return`${u}-content-${r}`}gn($o,"makeContentId");var z0=j0,R0=E0,go=T0,bo=N0;const O0=u=>u.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),rp=(...u)=>u.filter((r,f,o)=>!!r&&r.trim()!==""&&o.indexOf(r)===f).join(" ").trim();var D0={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};const w0=b.forwardRef(({color:u="currentColor",size:r=24,strokeWidth:f=2,absoluteStrokeWidth:o,className:m="",children:h,iconNode:S,...M},j)=>b.createElement("svg",{ref:j,...D0,width:r,height:r,stroke:u,strokeWidth:o?Number(f)*24/Number(r):f,className:rp("lucide",m),...M},[...S.map(([y,p])=>b.createElement(y,p)),...Array.isArray(h)?h:[h]]));const we=(u,r)=>{const f=b.forwardRef(({className:o,...m},h)=>b.createElement(w0,{ref:h,iconNode:r,className:rp(`lucide-${O0(u)}`,o),...m}));return f.displayName=`${u}`,f};const fp=we("Activity",[["path",{d:"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2",key:"169zse"}]]);const U0=we("Box",[["path",{d:"M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z",key:"hh9hay"}],["path",{d:"m3.3 7 8.7 5 8.7-5",key:"g66t2b"}],["path",{d:"M12 22V12",key:"d0xqtd"}]]);const El=we("Check",[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]]);const dp=we("ChevronDown",[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]]);const mp=we("ChevronLeft",[["path",{d:"m15 18-6-6 6-6",key:"1wnfg3"}]]);const hp=we("ChevronRight",[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]]);const B0=we("ChevronUp",[["path",{d:"m18 15-6-6-6 6",key:"153udz"}]]);const Xu=we("CircleAlert",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]]);const G0=we("CircleCheck",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]]);const pp=we("Copy",[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]]);const H0=we("Cpu",[["rect",{width:"16",height:"16",x:"4",y:"4",rx:"2",key:"14l7u7"}],["rect",{width:"6",height:"6",x:"9",y:"9",rx:"1",key:"5aljv4"}],["path",{d:"M15 2v2",key:"13l42r"}],["path",{d:"M15 20v2",key:"15mkzm"}],["path",{d:"M2 15h2",key:"1gxd5l"}],["path",{d:"M2 9h2",key:"1bbxkp"}],["path",{d:"M20 15h2",key:"19e6y8"}],["path",{d:"M20 9h2",key:"19tzq7"}],["path",{d:"M9 2v2",key:"165o2o"}],["path",{d:"M9 20v2",key:"i2bqo8"}]]);const mh=we("Database",[["ellipse",{cx:"12",cy:"5",rx:"9",ry:"3",key:"msslwz"}],["path",{d:"M3 5V19A9 3 0 0 0 21 19V5",key:"1wlel7"}],["path",{d:"M3 12A9 3 0 0 0 21 12",key:"mv7ke4"}]]);const vp=we("Download",[["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["polyline",{points:"7 10 12 15 17 10",key:"2ggqvy"}],["line",{x1:"12",x2:"12",y1:"15",y2:"3",key:"1vk2je"}]]);const yp=we("FolderUp",[["path",{d:"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z",key:"1kt360"}],["path",{d:"M12 10v6",key:"1bos4e"}],["path",{d:"m9 13 3-3 3 3",key:"1pxg3c"}]]);const q0=we("Github",[["path",{d:"M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4",key:"tonef"}],["path",{d:"M9 18c-4.51 2-5-2-7-2",key:"9comsn"}]]);const k0=we("Maximize2",[["polyline",{points:"15 3 21 3 21 9",key:"mznyad"}],["polyline",{points:"9 21 3 21 3 15",key:"1avn1i"}],["line",{x1:"21",x2:"14",y1:"3",y2:"10",key:"ota7mn"}],["line",{x1:"3",x2:"10",y1:"21",y2:"14",key:"1atl0r"}]]);const zo=we("Minus",[["path",{d:"M5 12h14",key:"1ays0h"}]]);const L0=we("MonitorCog",[["path",{d:"M12 17v4",key:"1riwvh"}],["path",{d:"m15.2 4.9-.9-.4",key:"12wd2u"}],["path",{d:"m15.2 7.1-.9.4",key:"1r2vl7"}],["path",{d:"m16.9 3.2-.4-.9",key:"3zbo91"}],["path",{d:"m16.9 8.8-.4.9",key:"1qr2dn"}],["path",{d:"m19.5 2.3-.4.9",key:"1rjrkq"}],["path",{d:"m19.5 9.7-.4-.9",key:"heryx5"}],["path",{d:"m21.7 4.5-.9.4",key:"17fqt1"}],["path",{d:"m21.7 7.5-.9-.4",key:"14zyni"}],["path",{d:"M22 13v2a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7",key:"1tnzv8"}],["path",{d:"M8 21h8",key:"1ev6f3"}],["circle",{cx:"18",cy:"6",r:"3",key:"1h7g24"}]]);const gp=we("Play",[["polygon",{points:"6 3 20 12 6 21 6 3",key:"1oa8hb"}]]);const jl=we("RefreshCw",[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]]);const Ro=we("Server",[["rect",{width:"20",height:"8",x:"2",y:"2",rx:"2",ry:"2",key:"ngkwjq"}],["rect",{width:"20",height:"8",x:"2",y:"14",rx:"2",ry:"2",key:"iecqi9"}],["line",{x1:"6",x2:"6.01",y1:"6",y2:"6",key:"16zg32"}],["line",{x1:"6",x2:"6.01",y1:"18",y2:"18",key:"nzw8ys"}]]);const Y0=we("SlidersHorizontal",[["line",{x1:"21",x2:"14",y1:"4",y2:"4",key:"obuewd"}],["line",{x1:"10",x2:"3",y1:"4",y2:"4",key:"1q6298"}],["line",{x1:"21",x2:"12",y1:"12",y2:"12",key:"1iu8h1"}],["line",{x1:"8",x2:"3",y1:"12",y2:"12",key:"ntss68"}],["line",{x1:"21",x2:"16",y1:"20",y2:"20",key:"14d8ph"}],["line",{x1:"12",x2:"3",y1:"20",y2:"20",key:"m0wm8r"}],["line",{x1:"14",x2:"14",y1:"2",y2:"6",key:"14e1ph"}],["line",{x1:"8",x2:"8",y1:"10",y2:"14",key:"1i6ji0"}],["line",{x1:"16",x2:"16",y1:"18",y2:"22",key:"1lctlv"}]]);const Qu=we("Square",[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}]]);const Fo=we("Terminal",[["polyline",{points:"4 17 10 11 4 5",key:"akl6gq"}],["line",{x1:"12",x2:"20",y1:"19",y2:"19",key:"q2wloq"}]]);const V0=we("Wrench",[["path",{d:"M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z",key:"cbrjhi"}]]);const ja=we("X",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);async function bp(u){try{return await navigator.clipboard.writeText(u),!0}catch{const r=document.createElement("textarea");r.value=u,r.style.position="fixed",r.style.opacity="0",document.body.appendChild(r),r.focus(),r.select();try{return document.execCommand("copy")}catch{return!1}finally{r.remove()}}}function X0({deployment:u,onCancel:r,onClose:f}){const o=b.useRef(null),m=b.useRef(null),[h,S]=b.useState(!1),M=u.log_tail.join(` -`)||"Waiting for Modal build output…";b.useEffect(()=>{const y=p=>{p.key==="Escape"&&f()};return window.addEventListener("keydown",y),()=>window.removeEventListener("keydown",y)},[f]),b.useEffect(()=>{o.current&&(o.current.scrollTop=o.current.scrollHeight)},[u.log_tail.length]),b.useEffect(()=>()=>{m.current!==null&&window.clearTimeout(m.current)},[]);const j=async()=>{await bp(M)&&(S(!0),m.current!==null&&window.clearTimeout(m.current),m.current=window.setTimeout(()=>S(!1),1e3))};return Do.createPortal(c.jsx("div",{className:"modal-log-backdrop",onMouseDown:y=>{y.target===y.currentTarget&&f()},children:c.jsxs("section",{className:"modal-log-dialog",role:"dialog","aria-modal":"true","aria-labelledby":"modal-log-title",children:[c.jsxs("header",{children:[c.jsxs("div",{children:[c.jsx("span",{children:"MODAL SETUP & DEPLOYMENT"}),c.jsx("strong",{id:"modal-log-title",children:u.stage})]}),c.jsxs("small",{children:[u.gpu,u.cpu?` · ${u.cpu} CPU`:"",u.memory_mb?` · ${hi(u.memory_mb*1024*1024)}`:""," · ",u.status]}),["queued","running"].includes(u.status)&&c.jsxs("button",{className:"modal-dialog-stop",type:"button",onClick:r,title:"Stop Modal setup",children:[c.jsx(Qu,{size:11,fill:"currentColor"})," Stop"]}),c.jsxs("button",{type:"button",onClick:j,title:"Copy deployment logs",children:[h?c.jsx(El,{size:13}):c.jsx(pp,{size:13})," ",h?"Copied!":"Copy"]}),c.jsx("button",{type:"button",onClick:f,title:"Close deployment logs","aria-label":"Close deployment logs",children:c.jsx(ja,{size:15})})]}),c.jsx("pre",{ref:o,children:M})]})}),document.body)}const hh=[{id:"building",label:"Prepare CUDA image",detail:"Install and cache the GTSFM environment"},{id:"deploying",label:"Deploy workspace",detail:"Publish the FastAPI workspace on Modal"},{id:"verifying",label:"Verify connection",detail:"Find the endpoint and check availability"}];function Q0({deployment:u,onCancel:r,onExpand:f}){const o=u.phase==="ready"?"verifying":u.phase??"building",m=Math.max(0,hh.findIndex(S=>S.id===o)),h=u.image_source==="prebuilt"?"Pull the versioned GTSFM runtime; no package installation":"Install and cache the GTSFM environment";return c.jsxs("section",{className:`modal-deployment ${u.status}`,"aria-label":"Modal workspace progress",children:[c.jsxs("div",{className:"modal-deployment-heading",children:[c.jsxs("span",{children:[u.status==="completed"?c.jsx(El,{size:12}):u.status==="failed"?c.jsx(Xu,{size:12}):u.status==="cancelled"?c.jsx(zo,{size:12}):c.jsx(jl,{size:12}),c.jsx("strong",{children:u.stage})]}),c.jsxs("span",{className:"modal-deployment-actions",children:[c.jsxs("small",{children:[u.image_source==="prebuilt"?"PREBUILT":"SOURCE"," · ",u.gpu]}),["queued","running"].includes(u.status)&&c.jsxs("button",{className:"modal-stop-action",type:"button",onClick:r,title:"Stop Modal setup",children:[c.jsx(Qu,{size:9,fill:"currentColor"})," Stop"]}),c.jsx("button",{type:"button",onClick:f,title:"Expand setup logs","aria-label":"Expand setup logs",children:c.jsx(k0,{size:12})})]})]}),c.jsx("ol",{className:"modal-deployment-steps",children:hh.map((S,M)=>{const j=u.status==="completed"||M0&&c.jsx("pre",{children:u.log_tail.slice(-4).join(` -`)})]})}const Z0={name:"my-scene",sample_id:"",dataset_dir:"",images_dir:"",loader:"olsson",config_name:"vggt",splat_implementation:"gsplat",gaussian_splatting_config_name:"base_gs",gs_max_steps:7e3,live_preview_interval:250,run_mvs:!1,execution_target:"local",hardware:"cpu",remote_connection:"api",remote_provider:"modal",remote_endpoint:"",modal_api_key:"",modal_token_id:"",modal_token_secret:"",modal_gpu:"L40S",ssh_host:"",ssh_port:22,ssh_username:"",ssh_authentication:"agent",ssh_private_key:"",ssh_workspace:"",remote_hardware:"",max_resolution:"",num_workers:1,threads_per_worker:1,worker_memory_limit:"32GB",graph_partitioner:"",global_descriptor_config_name:"",retriever_config_name:"",correspondence_generator_config_name:"",verifier_config_name:"",max_frame_lookahead:"",num_matched:"",share_intrinsics:!1,log:"INFO",dashboard_port:"",input_worker:"",dask_tmpdir:"",cluster_config:"",num_retry_cluster_connection:"",advanced_overrides:""},K0={defaults:{config_name:"vggt",loader:"olsson",splat_implementation:"gsplat",num_workers:1,threads_per_worker:1,worker_memory_limit:"32GB",run_mvs:!1,gs_max_steps:7e3,live_preview_interval:250,hardware:"cpu"},models:[{id:"vggt",label:"VGGT",capabilities:{iterative_splat:!0,mvs:!1,share_intrinsics:!1}}],loaders:["olsson"],loader_options:{olsson:[]},graph_partitioners:[],global_descriptors:[],retrievers:[],correspondence_generators:[],verifiers:[],log_levels:["DEBUG","INFO","WARNING","ERROR","CRITICAL"],gaussian_splatting_models:["base_gs"],splat_implementations:[{id:"none",label:"No splats",description:"Run reconstruction only.",live:!1},{id:"gsplat",label:"Optimized Gaussian splats",description:"Iteratively optimize gsplat Gaussians and show live previews.",live:!0},{id:"anysplat",label:"AnySplat",description:"Generate splats with the feed-forward AnySplat model.",live:!1}]};function J0(u){const r=m=>{const h=m.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),S=u.match(new RegExp(`(?:^|\\s)${h}(?:=|\\s+)(?:"([^"]+)"|'([^']+)'|([^\\s]+))`));return(S?.[1]??S?.[2]??S?.[3]??"").trim()},f=r("--token-id"),o=r("--token-secret");return f&&o?{tokenId:f,tokenSecret:o}:null}const _o=u=>u.modal_api_key,hn=u=>String(u??"").split("_").map(r=>["api","ba","colmap","gpu","gs","mvs","sift","vggt"].includes(r)?r.toUpperCase():r==="anysplat"?"AnySplat":r==="megaloc"?"MegaLoc":r.charAt(0).toUpperCase()+r.slice(1)).join(" "),Wl=u=>u instanceof Error?u.message:String(u);async function wt(u,r){const f=await fetch(u,r),o=await f.json();if(!f.ok)throw new Error(o.error||`Request failed (${f.status})`);return o}const ph=u=>`${location.protocol==="https:"?"wss:":"ws:"}//${location.host}${u}`;function $0({collapsed:u,onToggle:r}){return c.jsxs("header",{className:"studio-header","aria-label":"SfM Studio",children:[c.jsx("div",{className:"brand-primary",children:c.jsx("img",{className:"brand-logo",src:"/static/brand/sfm-logo.png",alt:"SfM"})}),c.jsx("img",{className:"brand-mark",src:"/static/brand/bee-favicon.png",alt:"","aria-hidden":"true"}),c.jsx("button",{className:"sidebar-toggle",type:"button",onClick:r,title:u?"Expand side panel":"Collapse side panel","aria-label":u?"Expand side panel":"Collapse side panel",children:u?c.jsx(hp,{size:16}):c.jsx(mp,{size:16})})]})}function Wo({label:u,optional:r=!1,children:f}){return c.jsxs("label",{children:[u,r&&c.jsx("span",{className:"optional",children:"optional"}),f]})}function it({label:u,value:r,options:f,onChange:o,disabled:m=!1,empty:h=null,id:S}){return c.jsx(Wo,{label:u,children:c.jsxs("select",{id:S,value:r??"",onChange:M=>o(M.target.value),disabled:m,children:[h!==null&&c.jsx("option",{value:"",children:h}),f.map(M=>{const j=typeof M=="string"?{id:M,label:hn(M)}:M;return c.jsx("option",{value:j.id,disabled:!!(j.status&&j.status!=="available"),children:j.label},j.id)})]})})}function Ye({label:u,optional:r=!1,value:f,onChange:o,...m}){return c.jsx(Wo,{label:u,optional:r,children:c.jsx("input",{value:f??"",onChange:h=>o(h.target.value),...m})})}const hi=u=>{const r=["B","KB","MB","GB","TB"];let f=u,o=0;for(;f>=1024&&o0?f.toFixed(1):Math.round(f)} ${r[o]}`},pn=[{id:"T4",label:"NVIDIA T4 · 16 GB · $0.59/hr",pricePerSecond:164e-6,relativeSpeed:.3,memoryGiB:16},{id:"L4",label:"NVIDIA L4 · 24 GB · $0.80/hr",pricePerSecond:222e-6,relativeSpeed:.5,memoryGiB:24},{id:"A10",label:"NVIDIA A10 · 24 GB · $1.10/hr",pricePerSecond:306e-6,relativeSpeed:.58,memoryGiB:24},{id:"L40S",label:"NVIDIA L40S · 48 GB · $1.95/hr",pricePerSecond:542e-6,relativeSpeed:1,memoryGiB:48},{id:"A100-40GB",label:"NVIDIA A100 · 40 GB · $2.10/hr",pricePerSecond:583e-6,relativeSpeed:1.18,memoryGiB:40},{id:"A100-80GB",label:"NVIDIA A100 · 80 GB · $2.50/hr",pricePerSecond:694e-6,relativeSpeed:1.3,memoryGiB:80},{id:"RTX-PRO-6000",label:"NVIDIA RTX PRO 6000 · 96 GB · $3.03/hr",pricePerSecond:842e-6,relativeSpeed:1.45,memoryGiB:96},{id:"H100",label:"NVIDIA H100 · 80 GB · $3.95/hr",pricePerSecond:.001097,relativeSpeed:1.8,memoryGiB:80},{id:"H200",label:"NVIDIA H200 · 141 GB · $4.54/hr",pricePerSecond:.001261,relativeSpeed:1.95,memoryGiB:141},{id:"B200",label:"NVIDIA B200 · 180 GB · $6.25/hr",pricePerSecond:.001736,relativeSpeed:2.35,memoryGiB:180},{id:"B300",label:"NVIDIA B300 · 288 GB · Coming Soon!",status:"coming-soon",pricePerSecond:.001972,relativeSpeed:2.65,memoryGiB:288}];function F0(u,r,f=0){const o=r?.image_count||f;if(!o)return null;const m=r?.average_megapixels&&r.average_megapixels>0?r.average_megapixels:8,h=Number(u.max_resolution),S=Number.isFinite(h)&&h>0?h**2*.75/1e6:m,M=Math.max(.25,Math.min(m,S)),j=o*Math.sqrt(M/8),y=u.config_name==="vggt"?5:u.config_name.includes("fast")?3:7,p=u.splat_implementation==="gsplat"?3:u.splat_implementation==="anysplat"?6:0,x=Math.ceil(5+j*.1+y+p+(u.run_mvs?4:0));let D="L4";x<=14&&u.splat_implementation==="none"?D="T4":x<=22?D="L4":x<=44?D="L40S":x<=72&&j<350?D="A100-80GB":x<=72?D="H100":x<=125?D="H200":D="B200";const H=pn.find(Q=>Q.id===D)??pn[3],L=o<40?"small":o<140?"medium":o<350?"large":"very large";return{gpu:H,imageCount:o,effectiveMegapixels:M,estimatedMemoryGiB:x,reason:`${L} ${o}-image workload at about ${M.toFixed(M<10?1:0)} MP per image`}}function W0({recommendation:u,selectedGpu:r,onApply:f}){if(!u)return c.jsxs("div",{className:"modal-gpu-recommendation empty",children:[c.jsx("strong",{children:"VM recommendation"}),c.jsx("p",{children:"Choose a sample or upload images to size the Modal GPU automatically."})]});const o=r===u.gpu.id;return c.jsxs("section",{className:`modal-gpu-recommendation ${o?"selected":"overridden"}`,"aria-label":"Recommended Modal VM size",children:[c.jsxs("div",{children:[c.jsx("span",{children:"RECOMMENDED VM"}),c.jsxs("strong",{children:[u.gpu.id," · ",u.gpu.memoryGiB," GB"]})]}),c.jsxs("p",{children:[u.reason,". Estimated peak GPU memory is approximately ",u.estimatedMemoryGiB," GiB, including working headroom."]}),o?c.jsxs("small",{children:[c.jsx(El,{size:11})," Selected automatically"]}):c.jsx("button",{type:"button",onClick:f,children:"Use recommended"})]})}const vh=u=>u<60?`${Math.max(1,Math.round(u))} min`:`${(u/60).toFixed(u<120?1:0)} hr`,yh=u=>`$${u<10?u.toFixed(2):u.toFixed(1)}`;function Io(u){const r=u.trim().match(/^([\d.]+)\s*(gb|gib|mb|mib)?$/i);if(!r)return 32;const f=Number(r[1]);return/m/i.test(r[2]||"")?f/1024:f}const gh={T4:{cpu:4,memoryGiB:32},L4:{cpu:4,memoryGiB:32},A10:{cpu:6,memoryGiB:48},L40S:{cpu:8,memoryGiB:64},"A100-40GB":{cpu:8,memoryGiB:64},"A100-80GB":{cpu:12,memoryGiB:96},"RTX-PRO-6000":{cpu:16,memoryGiB:128},H100:{cpu:16,memoryGiB:128},H200:{cpu:20,memoryGiB:192},B200:{cpu:24,memoryGiB:256}};function I0(u,r,f){if(u.execution_target==="remote"){if(u.remote_connection==="api"&&u.remote_provider==="modal"){const p=gh[u.modal_gpu]??gh.L40S,x=pn.find(D=>D.id===u.modal_gpu);return{key:`modal:${u.modal_gpu}`,label:`Modal ${u.modal_gpu}`,description:`${x?.memoryGiB??48} GB GPU · CPU and RAM are provisioned when this workspace is deployed. One worker is fixed to the single GPU.`,workers:1,threadsPerWorker:p.cpu,memoryPerWorkerGiB:p.memoryGiB,allowWorkers:!1,allowThreads:!0,allowMemory:!0,allowLocalRuntime:!1}}return{key:`remote:${u.remote_connection}:${u.remote_provider}`,label:u.remote_connection==="ssh"?"Direct VM (coming soon)":`${hn(u.remote_provider)} VM`,description:"Machine-level tuning is unavailable until this remote provider is connected.",workers:1,threadsPerWorker:1,memoryPerWorkerGiB:32,allowWorkers:!1,allowThreads:!1,allowMemory:!1,allowLocalRuntime:!1}}const o=r?.devices.find(p=>p.kind==="cpu"),m=Math.max(1,Number(o?.details.match(/(\d+)\s+logical cores/i)?.[1])||1),h=Math.max(4,Io(o?.memory||"32GB")),S=!!(f&&f.kind!=="cpu"),M=S?1:Math.min(4,Math.max(1,Math.floor(m/4))),j=S?Math.min(8,m):Math.max(1,Math.floor(m/M)),y=Math.max(4,Math.floor(h*.75/M));return{key:`local:${f?.id??"detecting"}:${m}:${Math.round(h)}`,label:f?.label??"Detecting this machine",description:S?"One worker is assigned to the selected accelerator. CPU threads and host-memory limits remain adjustable.":"Worker count, CPU threads, and memory are tuned from the detected local resources.",workers:M,threadsPerWorker:j,memoryPerWorkerGiB:y,allowWorkers:!S,allowThreads:!!f,allowMemory:!!f,allowLocalRuntime:!0}}function P0({form:u,analysis:r,fallbackImageCount:f}){const o=r?.image_count||f;if(!o)return c.jsxs("div",{className:"modal-estimate empty",children:[c.jsx("strong",{children:"Cost estimate"}),c.jsx("p",{children:"Choose a GTSFM sample or upload an image dataset to calculate an estimate."})]});const m=pn.find(ue=>ue.id===u.modal_gpu)??pn[3],h=r?.average_megapixels||8,S=Number(u.max_resolution),M=Number.isFinite(S)&&S>0?S**2*.75/1e6:h,j=Math.min(h,M),y=Math.max(.65,Math.min(2.5,Math.sqrt(j/2))),p=u.config_name.includes("fast")?.75:u.config_name==="vggt"?1:1.35,x=(2+o*.09*y+Math.pow(o,1.35)*.025)*p,D=Math.max(1,Number(u.gs_max_steps)||7e3),H=u.splat_implementation==="gsplat"?D/1e3*(.45+Math.sqrt(o)*.08)*y:u.splat_implementation==="anysplat"?1.5+o*.04*y:0,L=u.run_mvs?1+o*.12*y:0,V=(x+H+L)/m.relativeSpeed,k=Math.max(1,V*.7),Y=Math.max(k+1,V*1.8+2),G=Math.max(1,Number(u.num_workers)*Number(u.threads_per_worker)||1),Z=Math.max(1,Io(u.worker_memory_limit)*Math.max(1,Number(u.num_workers)||1)),le=m.pricePerSecond+G*131e-7+Z*222e-8,P=k*60*le,J=Y*60*le,me=r?.image_count?`${r.image_count} images · ${r.total_megapixels.toLocaleString()} source MP · ${hi(r.image_bytes)}`:`${o} catalog images · resolution assumed`;return c.jsxs("section",{className:"modal-estimate","aria-label":"Estimated Modal compute cost",children:[c.jsxs("div",{className:"modal-estimate-heading",children:[c.jsxs("div",{children:[c.jsx("span",{children:"ESTIMATED MODAL COMPUTE"}),c.jsxs("strong",{children:[yh(P),"–",yh(J)]})]}),c.jsxs("em",{children:[vh(k),"–",vh(Y)]})]}),c.jsx("div",{className:"modal-estimate-bar",children:c.jsx("span",{style:{width:`${Math.min(100,Math.max(12,k/Y*100))}%`}})}),c.jsx("p",{children:me}),c.jsxs("small",{children:[hn(u.config_name)," · ",hn(u.splat_implementation),u.splat_implementation==="gsplat"?` · ${D.toLocaleString()} steps`:""," · ",m.id]}),c.jsxs("small",{children:["Estimate includes GPU plus approximately ",G," CPU core",G===1?"":"s"," and ",Z.toFixed(0)," GiB memory. Actual runtime and billing vary with scene complexity, caching, and utilization."]}),c.jsx("a",{href:"https://modal.com/pricing",target:"_blank",rel:"noreferrer",children:"Modal pricing · rates checked Aug 13, 2026 ↗"})]})}async function _p(u,r=""){const f=r?`${r}/${u.name}`:u.name;if(u.isFile)return[{file:await new Promise((S,M)=>u.file(S,M)),relativePath:f}];if(!u.isDirectory)return[];const o=u.createReader(),m=[];for(;;){const h=await new Promise((S,M)=>o.readEntries(S,M));if(!h.length)break;m.push(...h)}return(await Promise.all(m.map(h=>_p(h,f)))).flat()}async function e1(u){const r=Array.from(u.items).map(f=>f.webkitGetAsEntry?.()).filter(f=>!!f);return r.length?(await Promise.all(r.map(f=>_p(f)))).flat():Array.from(u.files).map(f=>({file:f,relativePath:f.name}))}function bh({label:u,optional:r=!1,value:f,onUploaded:o,onError:m}){const h=b.useRef(null),[S,M]=b.useState(!1),[j,y]=b.useState(!1),p=async x=>{if(!x.length){m("Choose a folder containing at least one file.");return}y(!0),m("");try{const D=new FormData;D.append("manifest",JSON.stringify(x.map(L=>L.relativePath))),x.forEach(L=>D.append("files",L.file,L.file.name));const H=await wt("/api/uploads",{method:"POST",body:D});o(H)}catch(D){m(Wl(D))}finally{y(!1)}};return c.jsxs("div",{className:"folder-field",children:[c.jsxs("div",{className:"folder-label",children:[u,r&&c.jsx("span",{className:"optional",children:"optional"})]}),c.jsxs("button",{type:"button",className:`folder-drop ${S?"dragging":""} ${f?"has-folder":""}`,onClick:()=>h.current?.click(),onDragEnter:x=>{x.preventDefault(),M(!0)},onDragOver:x=>{x.preventDefault(),x.dataTransfer.dropEffect="copy"},onDragLeave:x=>{x.currentTarget.contains(x.relatedTarget)||M(!1)},onDrop:async x=>{x.preventDefault(),M(!1),await p(await e1(x.dataTransfer))},disabled:j,children:[c.jsx("span",{className:"folder-icon",children:f?c.jsx(El,{size:17}):c.jsx(yp,{size:18})}),c.jsx("span",{className:"folder-copy",children:j?c.jsxs(c.Fragment,{children:[c.jsx("strong",{children:"Importing folder…"}),c.jsx("small",{children:"Keeping the directory structure intact"})]}):f?c.jsxs(c.Fragment,{children:[c.jsx("strong",{children:f.name}),c.jsxs("small",{children:[f.file_count," file",f.file_count===1?"":"s"," · ",hi(f.bytes)," · Click to replace"]})]}):c.jsxs(c.Fragment,{children:[c.jsx("strong",{children:"Drop a folder here"}),c.jsx("small",{children:"or click to choose one"})]})})]}),c.jsx("input",{ref:h,className:"folder-input",type:"file",multiple:!0,webkitdirectory:"",directory:"",onChange:async x=>{const D=Array.from(x.target.files??[]);await p(D.map(H=>({file:H,relativePath:H.webkitRelativePath||H.name}))),x.target.value=""}}),f&&c.jsx("button",{type:"button",className:"folder-remove",onClick:()=>o(null),children:"Remove selection"})]})}function _h({id:u,checked:r,onCheckedChange:f,disabled:o=!1,children:m}){return c.jsxs("div",{className:`toggle-row ${o?"disabled":""}`,children:[c.jsx(Kg,{id:u,className:"switch-root",checked:r,onCheckedChange:f,disabled:o,children:c.jsx($g,{className:"switch-thumb"})}),c.jsx("label",{htmlFor:u,children:m})]})}function So({number:u,title:r,subtitle:f,children:o}){return c.jsxs("section",{className:"form-section",children:[c.jsxs("div",{className:"section-heading",children:[c.jsx("span",{className:"step-number",children:u}),c.jsxs("div",{children:[c.jsx("strong",{children:r}),c.jsx("small",{children:f})]})]}),o]})}function t1({descriptors:u,values:r,setValues:f}){return u.length?c.jsxs("div",{className:"loader-options",children:[c.jsx("p",{className:"mini-heading",children:"Format-specific options"}),u.map(o=>o.type==="boolean"?c.jsx(it,{label:o.label,value:String(r[o.name]??o.default??!1),options:[{id:"true",label:"True"},{id:"false",label:"False"}],onChange:m=>f(h=>({...h,[o.name]:m==="true"}))},o.name):c.jsx(Ye,{label:o.label,optional:!o.required,required:o.required,type:["integer","number"].includes(o.type)?"number":"text",step:o.type==="number"?"any":void 0,value:r[o.name]??o.default??"",onChange:m=>f(h=>({...h,[o.name]:m}))},o.name))]}):null}function l1({device:u}){return u?c.jsxs("div",{className:"hardware-card",children:[c.jsx("strong",{children:u.label}),c.jsxs("small",{children:[u.details,u.memory?` · ${u.memory}`:""]}),c.jsx("span",{className:`capability ${u.supports_gaussian_splatting?"yes":"no"}`,children:u.supports_gaussian_splatting?"Splat ready":"Reconstruction"})]}):c.jsx("div",{className:"hardware-card",children:c.jsx("strong",{children:"Detecting hardware…"})})}function a1({schema:u,hardware:r,samples:f,samplesLoading:o,onStarted:m,onTabChange:h,remotePromptKey:S,schemaLoading:M,schemaError:j,onRetrySchema:y}){const[p,x]=b.useState(Z0),[D,H]=b.useState("upload"),[L,Q]=b.useState({}),[V,k]=b.useState(null),[Y,G]=b.useState(""),[Z,le]=b.useState(""),[P,J]=b.useState(!1),[me,ue]=b.useState(!1),[He,Ue]=b.useState(!1),[_e,ze]=b.useState(null),[Ze,Ke]=b.useState(!1),[R,q]=b.useState(!1),[I,ye]=b.useState(!1),[ge,g]=b.useState(""),[w,X]=b.useState(null),[K,ae]=b.useState(null),[ne,he]=b.useState(null),[Le,qe]=b.useState(!1),[nl,ie]=b.useState(""),ct=b.useRef(0),Oe=b.useRef(""),F=(C,ce)=>x(Se=>({...Se,[C]:ce}));b.useEffect(()=>{if(!r)return;const C=r.devices.find(ce=>ce.supports_gaussian_splatting);x(ce=>({...ce,hardware:C?.id??r.devices[0]?.id??"cpu",splat_implementation:ce.execution_target==="local"&&!C?"none":ce.splat_implementation}))},[r]),b.useEffect(()=>{S<1||(x(C=>({...C,execution_target:"remote",remote_connection:"api",remote_provider:"modal",splat_implementation:C.splat_implementation==="none"?u.defaults.splat_implementation:C.splat_implementation})),window.setTimeout(()=>document.getElementById("computeTarget")?.scrollIntoView({behavior:"smooth",block:"start"}),0))},[S,u]);const It=V?.configuration?.models??u.models,Et=It.find(C=>C.id===p.config_name),Pt=Et?.capabilities??{iterative_splat:!1,mvs:!1,share_intrinsics:!1},Ea=b.useMemo(()=>u.splat_implementations.map(C=>({...C,status:C.id==="gsplat"&&!Pt.iterative_splat?"disabled":"available"})),[u,Pt.iterative_splat]),bn=u.splat_implementations.find(C=>C.id===p.splat_implementation),Ma=r?.devices.find(C=>C.id===p.hardware),De=I0(p,r,Ma),ta=f.find(C=>C.id===p.sample_id),la=D==="sample"?ne?.analysis:K?.analysis?.image_count?K.analysis:w?.analysis,Ve=F0(p,la,ta?.image_count??0),Zu=[D,p.sample_id,la?.image_count??0,la?.average_megapixels??0,la?.total_megapixels??0,p.max_resolution,p.config_name,p.splat_implementation,p.run_mvs].join(":"),gi=pn.map(C=>({...C,label:C.id===Ve?.gpu.id?`${C.label} · Recommended`:C.label})),bi=[{id:"modal",label:"Modal"},{id:"lambda",label:"Lambda Cloud — Coming Soon!",status:"coming-soon"},{id:"runpod",label:"RunPod — Coming Soon!",status:"coming-soon"},{id:"vast",label:"Vast.ai — Coming Soon!",status:"coming-soon"},{id:"aws",label:"AWS EC2 — Coming Soon!",status:"coming-soon"}];b.useEffect(()=>{Ve&&x(C=>C.modal_gpu===Ve.gpu.id?C:{...C,modal_gpu:Ve.gpu.id})},[Ve?.gpu.id,Zu]),b.useEffect(()=>{x(C=>({...C,num_workers:De.workers,threads_per_worker:De.threadsPerWorker,worker_memory_limit:`${De.memoryPerWorkerGiB}GB`}))},[De.key]),b.useEffect(()=>{!ta||ne?.path!==""||ie(p.execution_target==="remote"?"Will download directly on Modal":ta.prepared?"Cached and ready":"Will download when the run starts")},[p.execution_target,ta,ne?.path]);const aa=(C,ce)=>{const Se=J0(ce);if(Se){x(tt=>({...tt,modal_token_id:Se.tokenId,modal_token_secret:Se.tokenSecret,modal_api_key:""})),le("Token command parsed. Both fields are filled.");return}x(tt=>({...tt,[C]:ce,modal_api_key:""})),le("")};b.useEffect(()=>{if(p.execution_target!=="remote"||p.remote_connection!=="api"||p.remote_provider!=="modal"||!p.modal_token_id.startsWith("ak-")||!p.modal_token_secret.startsWith("as-"))return;const C=++ct.current,ce=window.setTimeout(async()=>{J(!0),G("Finding your deployed GTSFM app on Modal…");try{const Se=await wt("/api/modal/discover",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token_id:p.modal_token_id,token_secret:p.modal_token_secret})});if(C!==ct.current)return;x(tt=>tt.remote_endpoint&&tt.remote_endpoint!==Oe.current?{...tt,modal_api_key:Se.api_key}:{...tt,remote_endpoint:Se.endpoint,modal_api_key:Se.api_key}),Oe.current=Se.endpoint,G(`Found ${Se.app_name} · ${Se.function_name}. Endpoint filled automatically.`)}catch(Se){C===ct.current&&G(Wl(Se))}finally{C===ct.current&&J(!1)}},450);return()=>window.clearTimeout(ce)},[p.execution_target,p.remote_connection,p.remote_provider,p.modal_token_id,p.modal_token_secret]),b.useEffect(()=>{p.splat_implementation==="gsplat"&&Et&&!Pt.iterative_splat&&F("splat_implementation","none")},[p.splat_implementation,Et,Pt.iterative_splat]);const _i=async(C,ce)=>{const Se=await wt("/api/remote/inspect",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({endpoint:C,api_key:ce,remote_provider:p.remote_provider})});k(Se);const tt=Se.hardware.devices.find(Ju=>Ju.supports_gaussian_splatting);return F("remote_hardware",tt?.id??Se.hardware.devices[0]?.id??""),Se},Si=async()=>{if(p.remote_connection!=="api"){G("SSH connection testing is coming soon. You can finish the VM details now.");return}if(!p.remote_endpoint||!_o(p)){G("Deploy the GTSFM Modal workspace first, or wait for an existing deployment to be discovered.");return}ue(!0),G("Connecting…");try{const C=await _i(p.remote_endpoint,_o(p));G(`${C.hardware.summary}. Modal connection is healthy and workspace options are up to date.`)}catch(C){G(Wl(C))}finally{ue(!1)}},Ku=async()=>{if(!p.modal_token_id.startsWith("ak-")||!p.modal_token_secret.startsWith("as-")){G("Enter both Modal token fields before deploying.");return}ct.current+=1,Ue(!0),k(null),G("");try{let C=await wt("/api/modal/deploy",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token_id:p.modal_token_id,token_secret:p.modal_token_secret,gpu:p.modal_gpu,cpu:Math.max(1,Number(p.num_workers)*Number(p.threads_per_worker)||1),memory_mb:Math.max(4096,Math.round(Io(p.worker_memory_limit)*Math.max(1,Number(p.num_workers)||1)*1024))})});for(ze(C);["queued","running","cancelling"].includes(C.status);)await new Promise(Se=>window.setTimeout(Se,1e3)),C=await wt(`/api/modal/deploy/${encodeURIComponent(C.id)}`),ze(C);if(C.status==="cancelled"){G("Modal workspace setup stopped.");return}if(C.status==="failed")throw new Error(C.error||"Modal deployment failed");Oe.current=C.endpoint,x(Se=>({...Se,remote_endpoint:C.endpoint,modal_api_key:C.api_key})),G("Workspace deployed. Loading its GPU and pipeline catalog…");const ce=await _i(C.endpoint,C.api_key);G(`${ce.hardware.summary}. Modal workspace is ready.`)}catch(C){const ce=Wl(C);G(/Request failed \(404\)/.test(ce)?"This GTSFM server was started before Modal deployment support was installed. Stop it with Ctrl-C, run `gtsfm run` again, then click Deploy.":ce)}finally{Ue(!1)}},xi=async()=>{if(!(!_e||!["queued","running"].includes(_e.status)))try{const C=await wt(`/api/modal/deploy/${encodeURIComponent(_e.id)}/cancel`,{method:"POST"});ze(C),G("Stopping Modal workspace setup…")}catch(C){G(Wl(C))}},na=C=>{const ce=f.find(tt=>tt.id===C);if(he(null),ie(""),!ce){x(tt=>({...tt,sample_id:"",dataset_dir:""}));return}const Se=ce.recommendations;Q(Se.loader_options??{}),x(tt=>({...tt,sample_id:ce.id,dataset_dir:"",images_dir:"",name:ce.id,loader:Se.loader,config_name:Se.config_name,max_resolution:Se.max_resolution??tt.max_resolution})),he({path:"",sample:ce,analysis:{image_count:ce.image_count,image_bytes:0,total_megapixels:0,average_megapixels:0,max_width:0,max_height:0}}),ie(ce.prepared?"Cached and ready":"Will download where the run executes")},pt=async C=>{C.preventDefault(),ye(!0),g("");try{if(p.execution_target==="remote"&&p.remote_connection==="ssh")throw new Error("SSH execution is not available yet. Choose API to run on Modal.");const ce={...p,api_key:p.execution_target==="remote"?_o(p):"",loader_options:L,hardware:p.execution_target==="remote"?p.remote_hardware:p.hardware,max_resolution:p.max_resolution?Number(p.max_resolution):null,num_workers:Number(p.num_workers),threads_per_worker:Number(p.threads_per_worker),gs_max_steps:Number(p.gs_max_steps),live_preview_interval:Number(p.live_preview_interval),max_frame_lookahead:p.max_frame_lookahead?Number(p.max_frame_lookahead):null,num_matched:p.num_matched?Number(p.num_matched):null,num_retry_cluster_connection:p.num_retry_cluster_connection?Number(p.num_retry_cluster_connection):null},Se=await wt("/api/jobs",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(ce)});m(Se),h("activity")}catch(ce){g(Wl(ce))}finally{ye(!1)}};return c.jsxs("form",{id:"runForm",onSubmit:pt,children:[c.jsxs("div",{className:"panel-intro",children:[c.jsx("span",{children:"NEW RECONSTRUCTION"}),M?c.jsxs("small",{className:"catalog-sync",children:[c.jsx(jl,{className:"spin",size:10})," Syncing workspace options…"]}):j?c.jsxs("button",{className:"catalog-sync failed",type:"button",onClick:y,children:[c.jsx(Xu,{size:10})," Options offline · Retry"]}):null,c.jsx("p",{children:"Configure the source, pipeline, and compute target."})]}),c.jsxs(So,{number:"01",title:"Input",subtitle:"Choose the images to reconstruct",children:[c.jsx(Ye,{label:"Run name",value:p.name,onChange:C=>F("name",C),autoComplete:"off"}),c.jsxs("div",{className:"segmented input-source",role:"group","aria-label":"Input source",children:[c.jsxs("button",{type:"button",className:`target-choice ${D==="upload"?"active":""}`,onClick:()=>{H("upload"),x(C=>({...C,sample_id:"",dataset_dir:w?.path??"",images_dir:K?.path??""}))},children:[c.jsx(yp,{size:13})," Upload your own"]}),c.jsxs("button",{type:"button",className:`target-choice ${D==="sample"?"active":""}`,onClick:()=>{H("sample"),x(C=>({...C,sample_id:ne?.sample.id??"",dataset_dir:ne?.path??"",images_dir:""}))},children:[c.jsx(mh,{size:13})," GTSFM samples"]})]}),D==="upload"?c.jsxs(c.Fragment,{children:[c.jsx(bh,{label:"Dataset folder",value:w,onError:g,onUploaded:C=>{X(C),F("dataset_dir",C?.path??""),C&&p.name==="my-scene"&&F("name",C.name.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"my-scene")}}),c.jsx(bh,{label:"Separate images folder",optional:!0,value:K,onError:g,onUploaded:C=>{ae(C),F("images_dir",C?.path??"")}})]}):c.jsxs("div",{className:"sample-picker",children:[c.jsx(it,{label:"Sample scene",value:p.sample_id,options:f,empty:o?"Loading GTSFM samples…":"Choose a GTSFM sample…",onChange:na,disabled:Le||o}),p.sample_id&&c.jsxs("div",{className:`sample-card ${ne?"ready":""}`,children:[c.jsx("span",{className:"sample-state",children:Le?c.jsx(jl,{className:"spin",size:14}):ne?c.jsx(El,{size:14}):c.jsx(mh,{size:14})}),c.jsxs("div",{children:[c.jsx("strong",{children:f.find(C=>C.id===p.sample_id)?.label}),c.jsx("small",{children:f.find(C=>C.id===p.sample_id)?.description}),c.jsxs("span",{children:[nl," · ",f.find(C=>C.id===p.sample_id)?.image_count," images · ",c.jsx("a",{href:f.find(C=>C.id===p.sample_id)?.source_url,target:"_blank",rel:"noreferrer",children:"View on GitHub ↗"})]})]})]}),c.jsx("p",{className:"field-help sample-help",children:"Dataset format, VGGT model, resolution, and available loader settings are applied automatically."})]}),c.jsx(it,{label:"Dataset format",value:p.loader,options:u.loaders,onChange:C=>{F("loader",C),Q({})}}),c.jsx(t1,{descriptors:u.loader_options[p.loader]??[],values:L,setValues:Q})]}),c.jsxs(So,{number:"02",title:"Models",subtitle:"VGGT is the default reconstruction model",children:[c.jsx(it,{label:"Reconstruction model",value:p.config_name,options:It,onChange:C=>F("config_name",C)}),c.jsx(it,{label:"Splat implementation",value:p.splat_implementation,options:Ea,onChange:C=>F("splat_implementation",C)}),c.jsx("p",{className:"field-help",children:bn?.description}),p.splat_implementation==="gsplat"&&c.jsxs("div",{className:"nested-options",children:[c.jsx(it,{label:"Optimizer preset",value:p.gaussian_splatting_config_name,options:V?.configuration?.gaussian_splatting_models??u.gaussian_splatting_models,onChange:C=>F("gaussian_splatting_config_name",C)}),c.jsxs("div",{className:"form-grid",children:[c.jsx(Ye,{label:"Training steps",type:"number",min:"1",step:"1",value:p.gs_max_steps,onChange:C=>F("gs_max_steps",C)}),c.jsx(Ye,{label:"Preview every",type:"number",min:"10",step:"10",value:p.live_preview_interval,onChange:C=>F("live_preview_interval",C)})]})]}),c.jsx(_h,{id:"runMvs",checked:p.run_mvs,disabled:!Pt.mvs,onCheckedChange:C=>F("run_mvs",C),children:"Also run dense MVS"})]}),c.jsxs(So,{number:"03",title:"Compute",subtitle:"Run here or on a remote VM",children:[c.jsxs("div",{className:"segmented",id:"computeTarget",role:"group","aria-label":"Execution target",children:[c.jsxs("button",{type:"button",className:`target-choice ${p.execution_target==="local"?"active":""}`,onClick:()=>F("execution_target","local"),children:[c.jsx(H0,{size:13})," This machine"]}),c.jsxs("button",{type:"button",className:`target-choice ${p.execution_target==="remote"?"active":""}`,onClick:()=>x(C=>({...C,execution_target:"remote",splat_implementation:C.splat_implementation==="none"?u.defaults.splat_implementation:C.splat_implementation})),children:[c.jsx(Ro,{size:13})," Remote VM"]})]}),p.execution_target==="local"?c.jsx(c.Fragment,{children:r?c.jsxs(c.Fragment,{children:[c.jsx(it,{label:"Hardware",value:p.hardware,options:r.devices,onChange:C=>F("hardware",C)}),c.jsx(l1,{device:Ma})]}):c.jsxs("div",{className:"hardware-card detecting",children:[c.jsx(jl,{className:"spin",size:13}),c.jsxs("div",{children:[c.jsx("strong",{children:"Detecting compute devices…"}),c.jsx("small",{children:"You can configure the rest of the run while this finishes."})]})]})}):c.jsxs("div",{className:"nested-options remote-vm-options",children:[c.jsx(it,{label:"Connection method",value:p.remote_connection,options:[{id:"api",label:"API"},{id:"ssh",label:"SSH"}],onChange:C=>{F("remote_connection",C),k(null),G("")}}),p.remote_connection==="api"?c.jsxs(c.Fragment,{children:[c.jsx(it,{label:"Service",value:p.remote_provider,options:bi,onChange:C=>{F("remote_provider",C),k(null)}}),p.remote_provider==="modal"&&c.jsxs("div",{className:"provider-panel",children:[c.jsxs("div",{className:"provider-heading",children:[c.jsx("span",{className:"provider-mark",children:"M"}),c.jsxs("div",{children:[c.jsx("strong",{children:"Modal"}),c.jsx("small",{children:"Connect with your Modal account token"})]}),c.jsx("span",{className:"provider-status",children:"AVAILABLE"})]}),c.jsx(it,{label:"Modal VM GPU",value:p.modal_gpu,options:gi,onChange:C=>F("modal_gpu",C)}),c.jsx(W0,{recommendation:Ve,selectedGpu:p.modal_gpu,onApply:()=>{Ve&&F("modal_gpu",Ve.gpu.id)}}),c.jsx(P0,{form:p,analysis:la,fallbackImageCount:ta?.image_count??0}),c.jsxs("p",{className:"field-help modal-command-help",children:["Enter the two values separately, or paste the complete ",c.jsx("code",{children:"modal token set --token-id … --token-secret …"})," command into either field."]}),c.jsxs("div",{className:"form-grid",children:[c.jsx(Ye,{label:"Token ID",value:p.modal_token_id,onChange:C=>aa("modal_token_id",C),autoComplete:"off",spellCheck:!1,placeholder:"ak-…"}),c.jsx(Ye,{label:"Token secret",type:"password",value:p.modal_token_secret,onChange:C=>aa("modal_token_secret",C),autoComplete:"new-password",spellCheck:!1,placeholder:"as-…"})]}),Z&&c.jsxs("div",{className:"credential-success",children:[c.jsx(El,{size:12})," ",Z]}),c.jsx(Ye,{label:"GTSFM endpoint",type:"url",value:p.remote_endpoint,onChange:C=>F("remote_endpoint",C),placeholder:P?"Discovering your Modal endpoint…":"Filled after credentials are verified"}),c.jsxs("button",{className:"modal-deploy-action full-width",type:"button",onClick:Ku,disabled:P||He||!p.modal_token_id||!p.modal_token_secret,children:[c.jsx(Ro,{size:13})," ",He?"Setup in progress…":p.remote_endpoint?"Update Modal workspace":"Set up & deploy Modal workspace"]}),_e&&c.jsx(Q0,{deployment:_e,onCancel:xi,onExpand:()=>Ke(!0)}),_e&&Ze&&c.jsx(X0,{deployment:_e,onCancel:xi,onClose:()=>Ke(!1)}),p.remote_endpoint&&p.modal_api_key&&c.jsxs("button",{className:"secondary-action full-width",type:"button",onClick:()=>Si(),disabled:P||He||me,children:[c.jsx(L0,{className:me?"spin":"",size:13})," ",me?"Checking Modal connection…":V?"Refresh Modal connection":"Check Modal connection"]}),c.jsx("div",{className:"field-help remote-message",children:Y}),V&&c.jsx(it,{label:"Remote hardware",value:p.remote_hardware,options:V.hardware.devices,onChange:C=>F("remote_hardware",C)})]})]}):c.jsxs("div",{className:"provider-panel",children:[c.jsxs("div",{className:"provider-heading",children:[c.jsx("span",{className:"provider-mark ssh",children:c.jsx(Fo,{size:14})}),c.jsxs("div",{children:[c.jsx("strong",{children:"Direct VM"}),c.jsx("small",{children:"Connect to a machine you control"})]}),c.jsx("span",{className:"provider-status soon",children:"COMING SOON!"})]}),c.jsxs("div",{className:"form-grid",children:[c.jsx(Ye,{label:"Host",value:p.ssh_host,onChange:C=>F("ssh_host",C),placeholder:"gpu-box.example.com"}),c.jsx(Ye,{label:"Port",type:"number",min:"1",max:"65535",value:p.ssh_port,onChange:C=>F("ssh_port",C)}),c.jsx(Ye,{label:"Username",value:p.ssh_username,onChange:C=>F("ssh_username",C),autoComplete:"username",placeholder:"ubuntu"}),c.jsx(it,{label:"Authentication",value:p.ssh_authentication,options:[{id:"agent",label:"SSH agent"},{id:"key",label:"Private key"}],onChange:C=>F("ssh_authentication",C)})]}),p.ssh_authentication==="key"&&c.jsx(Ye,{label:"Private key path",value:p.ssh_private_key,onChange:C=>F("ssh_private_key",C),placeholder:"/Users/you/.ssh/id_ed25519"}),c.jsx(Ye,{label:"Remote workspace",value:p.ssh_workspace,onChange:C=>F("ssh_workspace",C),placeholder:"~/gtsfm-workspace"}),c.jsx("p",{className:"field-help",children:"SSH setup is visible now; remote execution and file transfer are the next connector step."})]})]})]}),c.jsxs(Ag,{className:"advanced-options",open:R,onOpenChange:q,children:[c.jsxs(Ng,{className:"advanced-trigger",children:[c.jsxs("span",{children:[c.jsx(Y0,{size:13}),c.jsxs("span",{className:"advanced-trigger-copy",children:["Advanced settings",c.jsx("small",{children:De.label})]})]}),c.jsx(dp,{size:14})]}),c.jsxs(zg,{className:"advanced-content",children:[c.jsxs("div",{className:"machine-profile-summary",children:[c.jsxs("div",{children:[c.jsx("span",{children:"MACHINE PROFILE"}),c.jsx("strong",{children:De.label})]}),c.jsx("p",{children:De.description}),c.jsxs("div",{className:"machine-profile-specs",children:[c.jsxs("span",{children:[De.workers," worker",De.workers===1?"":"s"]}),c.jsxs("span",{children:[De.threadsPerWorker," thread",De.threadsPerWorker===1?"":"s"," / worker"]}),c.jsxs("span",{children:[De.memoryPerWorkerGiB," GB / worker"]})]})]}),c.jsxs("div",{className:"form-grid",children:[c.jsx(Ye,{label:"Max resolution",type:"number",min:"1",value:p.max_resolution,onChange:C=>F("max_resolution",C),placeholder:"Model default"}),c.jsx(Ye,{label:"Workers",type:"number",min:"1",value:p.num_workers,onChange:C=>F("num_workers",C),disabled:!De.allowWorkers,title:De.allowWorkers?void 0:"Fixed for the selected single-GPU machine"}),c.jsx(Ye,{label:"Threads / worker",type:"number",min:"1",value:p.threads_per_worker,onChange:C=>F("threads_per_worker",C),disabled:!De.allowThreads}),c.jsx(Ye,{label:"Memory / worker",value:p.worker_memory_limit,onChange:C=>F("worker_memory_limit",C),disabled:!De.allowMemory})]}),!De.allowWorkers&&c.jsx("p",{className:"advanced-machine-note",children:"Worker count is locked because the selected machine exposes one GPU. Choose a CPU machine to distribute work across multiple workers."}),c.jsx(it,{label:"Graph partitioner",value:p.graph_partitioner,options:u.graph_partitioners,empty:"Model default",onChange:C=>F("graph_partitioner",C)}),c.jsxs("div",{className:"form-grid",children:[c.jsx(it,{label:"Global descriptor",value:p.global_descriptor_config_name,options:u.global_descriptors,empty:"Model default",onChange:C=>F("global_descriptor_config_name",C)}),c.jsx(it,{label:"Image retriever",value:p.retriever_config_name,options:u.retrievers,empty:"Model default",onChange:C=>F("retriever_config_name",C)}),c.jsx(it,{label:"Correspondence",value:p.correspondence_generator_config_name,options:u.correspondence_generators,empty:"Model default",onChange:C=>F("correspondence_generator_config_name",C)}),c.jsx(it,{label:"Verifier",value:p.verifier_config_name,options:u.verifiers,empty:"Model default",onChange:C=>F("verifier_config_name",C)}),c.jsx(Ye,{label:"Frame lookahead",type:"number",min:"0",value:p.max_frame_lookahead,onChange:C=>F("max_frame_lookahead",C),placeholder:"Model default"}),c.jsx(Ye,{label:"Matches / image",type:"number",min:"0",value:p.num_matched,onChange:C=>F("num_matched",C),placeholder:"Model default"})]}),c.jsx(_h,{id:"shareIntrinsics",checked:p.share_intrinsics,disabled:!Pt.share_intrinsics,onCheckedChange:C=>F("share_intrinsics",C),children:"Share camera intrinsics"}),c.jsxs("div",{className:"form-grid",children:[c.jsx(it,{label:"Log level",value:p.log,options:u.log_levels,onChange:C=>F("log",C)}),c.jsx(Ye,{label:"Dashboard port",value:p.dashboard_port,onChange:C=>F("dashboard_port",C),placeholder:":8787",disabled:!De.allowLocalRuntime}),c.jsx(Ye,{label:"Input worker",value:p.input_worker,onChange:C=>F("input_worker",C),placeholder:"Optional worker address",disabled:!De.allowLocalRuntime}),c.jsx(Ye,{label:"Dask temp folder",value:p.dask_tmpdir,onChange:C=>F("dask_tmpdir",C),placeholder:"System default",disabled:!De.allowLocalRuntime}),c.jsx(Ye,{label:"Cluster config",value:p.cluster_config,onChange:C=>F("cluster_config",C),placeholder:"Optional YAML path",disabled:!De.allowLocalRuntime}),c.jsx(Ye,{label:"Cluster retries",type:"number",min:"0",value:p.num_retry_cluster_connection,onChange:C=>F("num_retry_cluster_connection",C),placeholder:"3",disabled:!De.allowLocalRuntime})]}),c.jsx(Wo,{label:"Hydra overrides",children:c.jsx("textarea",{rows:4,value:p.advanced_overrides,onChange:C=>F("advanced_overrides",C.target.value)})})]})]}),c.jsx("div",{className:"form-error",role:"alert",children:ge}),c.jsxs("button",{className:"primary-action",type:"submit",disabled:I||Le||He||D==="sample"&&!ne||p.execution_target==="remote"&&(!p.remote_endpoint||!p.modal_api_key||!V),children:[c.jsx("span",{children:I?"Starting…":Le?"Preparing sample…":He?"Finish workspace setup first":"Run reconstruction"}),I||Le||He?c.jsx(jl,{className:"spin",size:14}):c.jsx(gp,{size:14,fill:"currentColor"})]})]})}const Sp=u=>({queued:"Queued",running:"Running",completed:"Completed",failed:"Failed",cancelled:"Cancelled"})[u];function xp({jobId:u,compact:r=!1}){const f=`/api/jobs/${encodeURIComponent(u)}/splat?format=ply`;return c.jsxs("div",{className:`splat-download ${r?"compact":""}`,children:[c.jsx("span",{className:"splat-format-label",children:".PLY"}),c.jsxs("a",{href:f,download:!0,title:"Download PLY splat",children:[c.jsx(vp,{size:12}),!r&&c.jsx("span",{children:"Download"})]})]})}function n1({jobs:u,activeId:r,onSelect:f,onCancel:o,onRefresh:m}){return c.jsxs("div",{children:[c.jsxs("div",{className:"panel-title",children:[c.jsxs("div",{children:[c.jsx("h3",{children:"Activity"}),c.jsx("p",{children:"Running and recent jobs"})]}),c.jsx("button",{className:"icon-button",title:"Refresh",onClick:m,children:c.jsx(jl,{size:14})})]}),c.jsx("div",{className:"job-list",children:u.length?u.map(h=>c.jsxs("article",{className:`job-card ${h.id===r?"selected":""}`,children:[c.jsxs("div",{className:"job-card-top",children:[c.jsx("strong",{children:h.name}),c.jsx("span",{className:`job-status ${h.status}`,children:Sp(h.status)})]}),c.jsxs("small",{children:[hn(h.spec.config_name||"GTSFM")," · ",hn(h.spec.splat_implementation||"no_splats")]}),h.error&&c.jsx("p",{className:"job-error",children:h.error}),c.jsxs("div",{className:"job-actions",children:[c.jsx("button",{className:"text-button",onClick:()=>f(h.id),children:"Inspect"}),["queued","running"].includes(h.status)&&c.jsxs("button",{className:"text-button danger",onClick:()=>o(h.id),children:[c.jsx(Qu,{size:9,fill:"currentColor"})," Stop"]}),h.status==="completed"&&!h.remote&&c.jsx("a",{className:"text-button",href:"/?view=results",children:"View results"}),h.remote?.workspace_url&&c.jsx("a",{className:"text-button",href:h.remote.workspace_url,target:"_blank",rel:"noreferrer",children:"Remote results ↗"})]}),h.has_final_splat&&c.jsx(xp,{jobId:h.id,compact:!0})]},h.id)):c.jsxs("div",{className:"empty-state",children:[c.jsx(fp,{size:20}),c.jsx("strong",{children:"No runs yet"}),c.jsx("span",{children:"Configure your first reconstruction in New run."})]})})]})}function i1(){return c.jsxs("div",{children:[c.jsx("div",{className:"panel-title",children:c.jsxs("div",{children:[c.jsx("h3",{children:"Reconstructions"}),c.jsx("p",{children:"Open a scene in the 3D viewer"})]})}),c.jsxs("div",{id:"info",className:"info-summary",role:"status",children:[c.jsx("div",{className:"info-pill","data-role":"count",children:"—"}),c.jsxs("div",{className:"info-details",children:[c.jsx("div",{className:"info-title","data-role":"title",children:"Loading reconstructions…"}),c.jsx("div",{className:"info-path","data-role":"path",children:"Checking workspace…"})]})]}),c.jsx("input",{type:"text",id:"filter",placeholder:"Filter scenes…","aria-label":"Filter scenes"}),c.jsx("div",{id:"sceneList"})]})}function u1({job:u,live:r,logsOpen:f,setLogsOpen:o,visible:m,onCancel:h,onClose:S}){if(!u||!m)return null;const M=typeof r?.progress=="number"&&Number.isFinite(r.progress)?r.progress:u.status==="completed"?1:0,j=typeof r?.loss=="number"&&Number.isFinite(r.loss)?`loss ${r.loss.toFixed(4)}`:"",y=typeof r?.splat_count=="number"&&Number.isFinite(r.splat_count)?`${r.splat_count.toLocaleString()} splats`:"";return c.jsxs("div",{className:"run-status-bar","data-status":u.status,children:[c.jsxs("div",{className:"status-copy",children:[c.jsx("span",{className:"status-dot"}),c.jsxs("div",{children:[c.jsxs("strong",{children:[u.name," · ",Sp(u.status)]}),c.jsx("small",{children:u.error||(r?.stage==="gaussian_splatting"?"Optimizing Gaussian splats":"Running reconstruction pipeline")})]})]}),c.jsxs("div",{className:"status-metrics",children:[c.jsx("span",{children:r?.max_steps?`${Number(r.step).toLocaleString()} / ${Number(r.max_steps).toLocaleString()} steps`:""}),c.jsx("span",{children:j}),c.jsx("span",{children:y})]}),c.jsxs("div",{className:"status-actions",children:[u.has_final_splat&&c.jsx(xp,{jobId:u.id}),["queued","running"].includes(u.status)&&c.jsxs("button",{className:"secondary-action stop-process",type:"button",onClick:()=>h(u.id),children:[c.jsx(Qu,{size:10,fill:"currentColor"})," Stop"]}),c.jsxs("button",{className:"secondary-action",onClick:()=>o(!f),children:[c.jsx(Fo,{size:13})," Logs"]}),c.jsx("button",{className:"status-close",type:"button",title:"Close run status","aria-label":"Close run status",onClick:S,children:c.jsx(ja,{size:15})})]}),c.jsx(Hg,{className:"run-progress-track",value:M*100,children:c.jsx(qg,{className:"run-progress-fill",style:{transform:`translateX(-${100-M*100}%)`}})})]})}function c1({open:u,lines:r,onClose:f}){const o=b.useRef(null),m=b.useRef(null),[h,S]=b.useState(null),[M,j]=b.useState(!1),y=async()=>{await bp(r.join(` -`))&&(j(!0),m.current!==null&&window.clearTimeout(m.current),m.current=window.setTimeout(()=>j(!1),1e3))};b.useEffect(()=>()=>{m.current!==null&&window.clearTimeout(m.current)},[]);const p=H=>{if(H.target.closest("button"))return;const L=o.current,Q=L?.parentElement;if(!L||!Q)return;H.preventDefault(),H.currentTarget.setPointerCapture(H.pointerId);const V=L.getBoundingClientRect(),k=Q.getBoundingClientRect(),Y={pointerX:H.clientX,pointerY:H.clientY,left:V.left-k.left,top:V.top-k.top,width:V.width,height:V.height,maxLeft:k.width-V.width,maxTop:k.height-V.height};S({left:Y.left,top:Y.top,width:Y.width,height:Y.height});const G=le=>S({left:Math.max(0,Math.min(Y.maxLeft,Y.left+le.clientX-Y.pointerX)),top:Math.max(0,Math.min(Y.maxTop,Y.top+le.clientY-Y.pointerY)),width:Y.width,height:Y.height}),Z=()=>{window.removeEventListener("pointermove",G),window.removeEventListener("pointerup",Z),window.removeEventListener("pointercancel",Z)};window.addEventListener("pointermove",G),window.addEventListener("pointerup",Z,{once:!0}),window.addEventListener("pointercancel",Z,{once:!0})},x=H=>{const L=o.current,Q=L?.parentElement;if(!L||!Q)return;H.preventDefault(),H.stopPropagation(),H.currentTarget.setPointerCapture(H.pointerId);const V=L.getBoundingClientRect(),k=Q.getBoundingClientRect(),Y={pointerX:H.clientX,pointerY:H.clientY,left:V.left-k.left,top:V.top-k.top,right:V.right-k.left,bottom:V.bottom-k.top};S({left:Y.left,top:Y.top,width:V.width,height:V.height});const G=le=>{const P=Math.max(0,Math.min(Y.right-300,Y.left+le.clientX-Y.pointerX)),J=Math.max(0,Math.min(Y.bottom-150,Y.top+le.clientY-Y.pointerY));S({left:P,top:J,width:Y.right-P,height:Y.bottom-J})},Z=()=>{window.removeEventListener("pointermove",G),window.removeEventListener("pointerup",Z),window.removeEventListener("pointercancel",Z)};window.addEventListener("pointermove",G),window.addEventListener("pointerup",Z,{once:!0}),window.addEventListener("pointercancel",Z,{once:!0})};if(!u)return null;const D=h?{left:h.left,top:h.top,width:h.width,height:h.height,right:"auto",bottom:"auto"}:void 0;return c.jsxs("div",{ref:o,className:"log-drawer",role:"dialog","aria-label":"Run logs",style:D,children:[c.jsx("button",{className:"log-resize-handle",type:"button",title:"Resize logs","aria-label":"Resize logs from top left",onPointerDown:x}),c.jsxs("div",{className:"log-header",onPointerDown:p,children:[c.jsxs("strong",{children:[c.jsx(Fo,{size:12})," Run logs"]}),c.jsxs("div",{className:"log-header-actions",children:[c.jsxs("button",{className:"log-copy",type:"button",title:"Copy all logs","aria-label":"Copy all logs",onClick:y,children:[M?c.jsx(El,{size:12}):c.jsx(pp,{size:12}),c.jsx("span",{children:M?"Copied!":"Copy"})]}),c.jsx("button",{type:"button",title:"Minimize logs","aria-label":"Minimize logs",onClick:f,children:c.jsx(zo,{size:15})}),c.jsx("button",{type:"button",title:"Close logs","aria-label":"Close logs",onClick:f,children:c.jsx(ja,{size:14})})]})]}),c.jsx("pre",{id:"runLogs",children:r.join(` -`)})]})}function s1({setup:u,refreshing:r,onRefresh:f,onSetupChange:o,hasActiveJob:m}){const[h,S]=b.useState(!1),[M,j]=b.useState(!1),[y,p]=b.useState(null),[x,D]=b.useState({}),H=m?"with-active-job":"",L=async k=>{if(!(!k.action?.enabled||y)){p(k.id),D(Y=>({...Y,[k.id]:""}));try{const Y=await wt(`/api/setup/${encodeURIComponent(k.id)}/install`,{method:"POST"});o(Y.setup)}catch(Y){D(G=>({...G,[k.id]:Wl(Y)}))}finally{p(null)}}};if(M)return c.jsx("button",{className:`setup-reopen ${H}`,type:"button",title:"Show setup checks","aria-label":"Show setup checks",onClick:()=>j(!1),children:c.jsx(V0,{size:15})});const Q=u?.status??"warning",V=u?.counts.optional??0;return c.jsxs("section",{className:`setup-panel ${h?"collapsed":""} ${H}`,"aria-label":"Setup checks","aria-live":"polite",children:[c.jsxs("header",{className:"setup-panel-header",children:[c.jsx("span",{className:`setup-overall-icon ${Q}`,"aria-hidden":"true",children:Q==="ready"?c.jsx(G0,{size:16}):c.jsx(Xu,{size:16})}),c.jsxs("div",{className:"setup-panel-copy",children:[c.jsx("span",{children:"SETUP CHECKS"}),c.jsx("strong",{children:u?.summary??"Checking environment…"})]}),c.jsxs("div",{className:"setup-panel-actions",children:[c.jsx("button",{type:"button",title:"Refresh checks","aria-label":"Refresh setup checks",onClick:f,disabled:r,children:c.jsx(jl,{className:r?"spin":"",size:13})}),c.jsx("button",{type:"button",title:h?"Expand checks":"Collapse checks","aria-label":h?"Expand setup checks":"Collapse setup checks",onClick:()=>S(k=>!k),children:h?c.jsx(dp,{size:14}):c.jsx(B0,{size:14})}),c.jsx("button",{type:"button",title:"Close checks","aria-label":"Close setup checks",onClick:()=>j(!0),children:c.jsx(ja,{size:14})})]})]}),!h&&c.jsx("div",{className:"setup-panel-body",children:u?c.jsxs(c.Fragment,{children:[c.jsxs("div",{className:"setup-summary-line",children:[c.jsxs("span",{children:[u.counts.ready," passed"]}),V>0&&c.jsxs("span",{children:[V," optional unavailable"]})]}),c.jsx("ul",{children:u.items.map(k=>c.jsxs("li",{"data-state":k.state,children:[c.jsx("span",{className:"setup-check-mark","aria-hidden":"true",children:k.state==="ready"?c.jsx(El,{size:12}):k.state==="error"?c.jsx(ja,{size:12}):c.jsx("span",{})}),c.jsxs("div",{className:"setup-check-content",children:[c.jsxs("div",{className:"setup-check-title",children:[c.jsx("strong",{children:k.label}),c.jsxs("span",{className:"setup-check-tools",children:[!k.required&&c.jsx("em",{children:"optional"}),k.action&&c.jsxs("button",{className:"setup-install",type:"button",disabled:!k.action.enabled||!!y,title:k.action.reason||k.action.label,onClick:()=>L(k),children:[y===k.id?c.jsx(jl,{className:"spin",size:9}):k.action.enabled?c.jsx(vp,{size:9}):null,c.jsx("span",{children:y===k.id?"Working…":k.action.label})]})]})]}),c.jsx("small",{className:x[k.id]?"setup-action-error":void 0,children:x[k.id]||k.detail})]})]},k.id))})]}):c.jsxs("div",{className:"setup-loading",children:[c.jsx(jl,{className:"spin",size:13})," Inspecting this machine…"]})})]})}function o1({job:u,live:r}){const f=r?.dask,o=f?.memory_limit_bytes?Math.min(1,f.memory_bytes/f.memory_limit_bytes):0,m=r?.stage==="gaussian_splatting"?"Optimizing splats":u.status==="queued"?"Waiting to start":"Reconstructing scene";return c.jsxs("section",{className:"dask-stats","aria-label":"Live Dask status",children:[c.jsxs("div",{className:"dask-stats-heading",children:[c.jsxs("div",{children:[c.jsx("span",{children:"DASK LIVE"}),c.jsx("strong",{children:m})]}),f?.dashboard_url&&c.jsx("a",{href:f.dashboard_url,target:"_blank",rel:"noreferrer",children:"Open dashboard ↗"})]}),f?c.jsxs(c.Fragment,{children:[c.jsxs("div",{className:"dask-stat-grid",children:[c.jsxs("div",{children:[c.jsx("span",{children:"Workers"}),c.jsx("strong",{children:f.workers}),c.jsxs("small",{children:[f.threads," threads"]})]}),c.jsxs("div",{children:[c.jsx("span",{children:"Running"}),c.jsx("strong",{children:f.running_tasks}),c.jsxs("small",{children:[f.pending_tasks," pending"]})]}),c.jsxs("div",{children:[c.jsx("span",{children:"Finished"}),c.jsx("strong",{children:f.completed_tasks}),c.jsx("small",{children:f.failed_tasks?`${f.failed_tasks} failed`:"no errors"})]}),c.jsxs("div",{children:[c.jsx("span",{children:"CPU"}),c.jsxs("strong",{children:[Math.round(f.cpu_percent),"%"]}),c.jsx("small",{children:"across workers"})]})]}),c.jsxs("div",{className:"dask-memory",children:[c.jsxs("div",{children:[c.jsx("span",{children:"Memory"}),c.jsxs("strong",{children:[hi(f.memory_bytes)," / ",hi(f.memory_limit_bytes)]})]}),c.jsx("div",{className:"dask-memory-track",children:c.jsx("span",{style:{width:`${o*100}%`}})})]})]}):c.jsxs("div",{className:"dask-stats-waiting",children:[c.jsx("span",{className:"dask-pulse"})," Starting workers…"]})]})}function r1({activeJob:u,live:r,logsOpen:f,setLogsOpen:o,statusBarOpen:m,setStatusBarOpen:h,onCancelJob:S,setup:M,setupRefreshing:j,onRefreshSetup:y,onSetupChange:p}){const x=()=>{h(!1),o(!1)},D=!!(u&&!u.remote&&["queued","running"].includes(u.status));return c.jsxs("main",{id:"main-content",children:[c.jsx(u1,{job:u,live:r,logsOpen:f,setLogsOpen:o,visible:m,onCancel:S,onClose:x}),c.jsx(s1,{setup:M,refreshing:j,onRefresh:y,onSetupChange:p,hasActiveJob:!!(u&&m)}),c.jsxs("div",{id:"sceneStats",className:D?"dask-active":void 0,children:[c.jsxs("div",{className:"stat-group","data-mode":"scene",children:[c.jsxs("div",{className:"stat-pair",children:[c.jsx("span",{className:"label",children:"Cameras"}),c.jsx("span",{className:"value",id:"statCameras",children:"0"})]}),c.jsxs("div",{className:"stat-pair",children:[c.jsx("span",{className:"label",children:"Points"}),c.jsx("span",{className:"value",id:"statPoints",children:"0"})]}),c.jsxs("div",{className:"stat-wide",children:[c.jsx("span",{className:"label",children:"Image"}),c.jsx("span",{className:"value",id:"statImageName",children:"—"})]})]}),c.jsx("div",{className:"stat-group","data-mode":"splat",children:c.jsxs("div",{className:"stat-pair",children:[c.jsx("span",{className:"label",children:"Splats"}),c.jsx("span",{className:"value",id:"statSplats",children:"0"})]})}),D&&u&&c.jsx(o1,{job:u,live:r})]}),c.jsx("canvas",{id:"renderCanvas"}),c.jsxs("div",{id:"hud",children:[c.jsxs("label",{className:"background-control",children:["BG ",c.jsxs("select",{id:"backgroundSelect",defaultValue:"dark","aria-label":"Viewer background",children:[c.jsx("option",{value:"dark",children:"Dark"}),c.jsx("option",{value:"graphite",children:"Graphite"}),c.jsx("option",{value:"light-gray",children:"Light gray"}),c.jsx("option",{value:"white",children:"White"})]})]}),c.jsx("button",{id:"prevCamBtn",className:"hud-scene-only",title:"Previous camera",children:c.jsx(mp,{size:14})}),c.jsx("button",{id:"nextCamBtn",className:"hud-scene-only",title:"Next camera",children:c.jsx(hp,{size:14})}),c.jsx("button",{id:"toggleStats",children:"Hide stats"}),c.jsxs("label",{className:"hud-scene-only",children:[c.jsx("input",{type:"checkbox",id:"toggleCams",defaultChecked:!0})," Cameras"]}),c.jsxs("label",{className:"hud-scene-only",children:["Point size ",c.jsx("input",{type:"range",id:"ptSize",min:"1",max:"10",defaultValue:"2"})]}),c.jsx("button",{id:"toggleGround",type:"button","aria-pressed":"true",children:"Hide plane"}),c.jsxs("label",{className:"plane-height-control",children:["Plane Y ",c.jsx("input",{type:"range",id:"groundY",min:"-5",max:"5",step:"0.1",defaultValue:"0","aria-label":"Plane vertical position"}),c.jsx("output",{id:"groundYValue",htmlFor:"groundY",children:"0.0"})]})]}),c.jsx("a",{className:"viewport-github",href:"https://github.com/borglab/gtsfm",target:"_blank",rel:"noreferrer",title:"Open GTSFM on GitHub","aria-label":"Open GTSFM GitHub repository",children:c.jsx(q0,{size:16})}),c.jsx(c1,{open:f,lines:u?.log_tail||[],onClose:()=>o(!1)}),c.jsx("div",{id:"loadingOverlay",className:"loading-overlay",role:"status",children:c.jsxs("div",{className:"loading-box",children:[c.jsx("span",{id:"loadingMessage",children:"Loading…"}),c.jsx("div",{className:"loading-progress-track",children:c.jsx("div",{className:"loading-progress-fill",id:"loadingProgress"})})]})})]})}function f1(u){const r=u.devices.filter(S=>!S.status||S.status==="available");if(u.devices.find(S=>S.kind==="mps"))return{title:"Apple Metal (MPS) is not supported",description:"Apple Silicon and MPS can run reconstruction, but GTSFM Gaussian splatting does not currently support this backend. Use a Remote VM with an NVIDIA GPU to generate splats."};const o=u.devices.find(S=>S.kind==="rocm"||/\b(amd|radeon|rocm)\b/i.test(`${S.label} ${S.details}`));if(o)return{title:"AMD ROCm is not supported",description:`${o.label} was detected. AMD ROCm can run reconstruction, but GTSFM Gaussian splatting currently requires NVIDIA CUDA. Use a Remote VM with an NVIDIA GPU to generate splats.`};const m=u.devices.find(S=>S.kind==="nvidia"||S.kind==="cuda"||/\bnvidia\b/i.test(S.label));if(m)return{title:"NVIDIA GPU found, but CUDA is not ready",description:`${m.label} was detected, but this PyTorch environment cannot currently use it for Gaussian splatting. Install a CUDA-enabled PyTorch setup, or use a Remote VM with NVIDIA CUDA.`};const h=r.find(S=>S.kind!=="cpu");return h?{title:`${h.label} is not supported for splats`,description:"This accelerator can still be used where supported for reconstruction, but GTSFM Gaussian splatting currently requires NVIDIA CUDA. Use a compatible Remote VM to generate splats."}:{title:"No supported GPU was detected",description:"This machine can run CPU reconstruction, but GTSFM Gaussian splatting currently requires an NVIDIA CUDA GPU. Use a Remote VM to generate splats."}}function d1({hardware:u,onClose:r,onUseRemote:f}){const o=f1(u);return c.jsxs("section",{className:"hardware-warning",role:"alertdialog","aria-labelledby":"hardware-warning-title","aria-describedby":"hardware-warning-description",children:[c.jsx("div",{className:"hardware-warning-icon","aria-hidden":"true",children:c.jsx(Xu,{size:18})}),c.jsxs("div",{className:"hardware-warning-copy",children:[c.jsx("span",{children:"HARDWARE NOTICE"}),c.jsx("strong",{id:"hardware-warning-title",children:o.title}),c.jsx("p",{id:"hardware-warning-description",children:o.description}),c.jsxs("div",{className:"hardware-warning-actions",children:[c.jsxs("button",{type:"button",className:"warning-primary",onClick:f,children:[c.jsx(Ro,{size:12})," Use Remote VM"]}),c.jsx("button",{type:"button",onClick:r,children:"Continue without splats"})]})]}),c.jsx("button",{className:"hardware-warning-close",type:"button",title:"Dismiss hardware warning","aria-label":"Dismiss hardware warning",onClick:r,children:c.jsx(ja,{size:14})})]})}function m1(){const[u,r]=b.useState(!1),[f,o]=b.useState(new URLSearchParams(location.search).get("view")==="results"?"results":"run"),[m,h]=b.useState(K0),[S,M]=b.useState(!0),[j,y]=b.useState(""),[p,x]=b.useState(null),[D,H]=b.useState(null),[L,Q]=b.useState(!1),[V,k]=b.useState([]),[Y,G]=b.useState(!0),[Z,le]=b.useState([]),[P,J]=b.useState(null),[me,ue]=b.useState(null),[He,Ue]=b.useState(!1),[_e,ze]=b.useState(!0),[Ze,Ke]=b.useState(!1),[R,q]=b.useState(0),I=b.useRef(null),ye=b.useRef(null),ge=b.useCallback(async()=>{try{const ie=await wt("/api/jobs");le(ie.items||[]),J(ct=>ct||ie.items?.find(Oe=>["queued","running"].includes(Oe.status))?.id||null)}catch(ie){console.warn("Unable to refresh jobs",ie)}},[]),g=b.useCallback(async()=>{Q(!0);try{H(await wt("/api/setup"))}catch(ie){console.warn("Unable to inspect setup",ie)}finally{Q(!1)}},[]),w=b.useCallback(async()=>{M(!0),y("");try{h(await wt("/api/configuration"))}catch(ie){y(Wl(ie))}finally{M(!1)}},[]),X=b.useCallback(async()=>{try{x(await wt("/api/hardware"))}catch(ie){console.warn("Unable to inspect hardware",ie)}finally{g()}},[g]),K=b.useCallback(async()=>{try{const ie=await wt("/api/samples");k(ie.items)}catch(ie){console.warn("Unable to load sample catalog",ie)}finally{G(!1)}},[]);b.useEffect(()=>{w(),X(),K(),ge()},[w,X,K,ge]);const ae=Z.find(ie=>ie.id===P)??null;b.useEffect(()=>{P&&ze(!0)},[P]),b.useEffect(()=>{let ie=null,ct=null,Oe=!1;const F=()=>{ie=new WebSocket(ph("/api/events/jobs")),ie.onmessage=It=>{const Et=JSON.parse(It.data);le(Et.items||[]),J(Pt=>Pt||Et.items?.find(Ea=>["queued","running"].includes(Ea.status))?.id||null)},ie.onclose=()=>{Oe||(ct=window.setTimeout(F,1e3))}};return F(),()=>{Oe=!0,ct!==null&&clearTimeout(ct),ie?.close()}},[]),b.useEffect(()=>{if(!ae||ae.remote){ue(null);return}const ie=new WebSocket(ph(`/api/events/jobs/${encodeURIComponent(ae.id)}`));return ie.onmessage=async ct=>{const Oe=JSON.parse(ct.data);le(It=>It.map(Et=>Et.id===Oe.job.id?Oe.job:Et)),ue(Oe.live);const F=window.gtsfmViewer;Oe.live.preview_url&&Oe.live.preview_version!==I.current&&F&&!F.isBusy()&&(I.current=Oe.live.preview_version??null,await F.loadSplatsFile({splatsUrl:Oe.live.preview_url,label:`${Oe.job.name} · live`})),Oe.job.status==="completed"&&Oe.live.final_url&&ye.current!==Oe.job.id&&F&&!F.isBusy()&&(ye.current=Oe.job.id,await F.loadSplatsFile({splatsUrl:Oe.live.final_url,label:`${Oe.job.name} · final`}))},()=>ie.close()},[ae?.id]);const ne=async ie=>{await fetch(`/api/jobs/${encodeURIComponent(ie)}/cancel`,{method:"POST"}),await ge()},he=Z.filter(ie=>["queued","running"].includes(ie.status)).length,Le=p?.devices.some(ie=>ie.supports_gaussian_splatting&&(!ie.status||ie.status==="available"))??!1,qe=!!(p&&!Le&&!Ze),nl=()=>{Ke(!0),o("run"),q(ie=>ie+1)};return c.jsxs("div",{className:"app-shell",children:[qe&&p&&c.jsx(d1,{hardware:p,onClose:()=>Ke(!0),onUseRemote:nl}),c.jsxs("aside",{id:"sidebar",className:u?"sidebar-collapsed":"",children:[c.jsx($0,{collapsed:u,onToggle:()=>r(ie=>!ie)}),c.jsxs(z0,{className:"workspace-tabs",value:f,onValueChange:o,children:[c.jsxs(R0,{className:"studio-tabs","aria-label":"Workspace sections",children:[c.jsxs(go,{className:"studio-tab",value:"run",children:[c.jsx(gp,{size:12})," New run"]}),c.jsxs(go,{className:"studio-tab",value:"activity",children:[c.jsx(fp,{size:12})," Activity ",he>0&&c.jsx("span",{id:"activeJobCount",children:he})]}),c.jsxs(go,{className:"studio-tab",value:"results",children:[c.jsx(U0,{size:12})," Results"]})]}),c.jsx(bo,{className:"studio-panel",value:"run",forceMount:!0,children:c.jsx(a1,{schema:m,hardware:p,samples:V,samplesLoading:Y,onStarted:ie=>{ze(!0),J(ie.id),ge()},onTabChange:o,remotePromptKey:R,schemaLoading:S,schemaError:j,onRetrySchema:w})}),c.jsx(bo,{className:"studio-panel",value:"activity",forceMount:!0,children:c.jsx(n1,{jobs:Z,activeId:P,onSelect:ie=>{ze(!0),J(ie),I.current=null,ye.current=null},onCancel:ne,onRefresh:ge})}),c.jsx(bo,{className:"studio-panel",value:"results",forceMount:!0,children:c.jsx(i1,{})})]})]}),c.jsx(r1,{activeJob:ae,live:me,logsOpen:He,setLogsOpen:Ue,statusBarOpen:_e,setStatusBarOpen:ze,onCancelJob:ne,setup:D,setupRefreshing:L,onRefreshSetup:g,onSetupChange:H})]})}const jp=document.getElementById("root");if(!jp)throw new Error("GTSFM Studio root element is missing");Do.flushSync(()=>Jy.createRoot(jp).render(c.jsx(m1,{}))); +Defaulting to \`null\`.`}Gl(Jh,"getInvalidValueError");var Vy=qy,Xy=Yy,Qy=Object.defineProperty,Zy=(u,r)=>Qy(u,"name",{value:r,configurable:!0});function $h(u){const[r,f]=g.useState(void 0);return sa(()=>{if(u){f({width:u.offsetWidth,height:u.offsetHeight});const o=new ResizeObserver(m=>{if(!Array.isArray(m)||!m.length)return;const h=m[0];let S,E;if("borderBoxSize"in h){const j=h.borderBoxSize,y=Array.isArray(j)?j[0]:j;S=y.inlineSize,E=y.blockSize}else S=u.offsetWidth,E=u.offsetHeight;f({width:S,height:E})});return o.observe(u,{box:"border-box"}),()=>o.unobserve(u)}else f(void 0)},[u]),r}Zy($h,"useSize");var Ky=Object.defineProperty,oa=(u,r)=>Ky(u,"name",{value:r,configurable:!0}),Vo="Switch",[Jy,M1]=ra(Vo),[$y,Xo]=Jy(Vo);function Fh(u){const{__scopeSwitch:r,checked:f,children:o,defaultChecked:m,disabled:h,form:S,name:E,onCheckedChange:j,required:y,value:p="on",internal_do_not_use_render:M}=u,[O,Y]=Ci({prop:f,defaultProp:m??!1,onChange:j,caller:Vo}),[H,V]=g.useState(null),[X,k]=g.useState(null),Z=g.useRef(!1),[w,q]=g.useReducer(K=>K+1,0),$=H?!!S||!!H.closest("form"):!0,W={checked:O,setChecked:Y,disabled:h,control:H,setControl:V,name:E,form:S,value:p,hasConsumerStoppedPropagationRef:Z,userInteractionCount:w,onUserInteraction:q,required:y,defaultChecked:m,isFormControl:$,bubbleInput:X,setBubbleInput:k};return c.jsx($y,{scope:r,...W,children:Wh(M)?M(W):o})}oa(Fh,"SwitchProvider");var Fy="SwitchTrigger",Wy=g.forwardRef(oa(function({__scopeSwitch:r,onClick:f,...o},m){const{control:h,form:S,value:E,disabled:j,checked:y,required:p,setControl:M,setChecked:O,hasConsumerStoppedPropagationRef:Y,onUserInteraction:H,isFormControl:V,bubbleInput:X}=Xo(Fy,r),k=ll(m,M),Z=g.useRef(y);return g.useEffect(()=>{const w=S?h?.ownerDocument.getElementById(S):h?.form;if(w instanceof HTMLFormElement){const q=oa(()=>O(Z.current),"reset");return w.addEventListener("reset",q),()=>w.removeEventListener("reset",q)}},[h,S,O]),c.jsx(Et.button,{type:"button",role:"switch","aria-checked":y,"aria-required":p,"data-state":Qo(y),"data-disabled":j?"":void 0,disabled:j,value:E,...o,ref:k,onClick:Bt(f,w=>{H(),O(q=>!q),X&&V&&(Y.current=w.isPropagationStopped(),Y.current||w.stopPropagation())})})},"SwitchTrigger")),Iy=g.forwardRef(oa(function(r,f){const{__scopeSwitch:o,name:m,checked:h,defaultChecked:S,required:E,disabled:j,value:y,onCheckedChange:p,form:M,...O}=r;return c.jsx(Fh,{__scopeSwitch:o,checked:h,defaultChecked:S,disabled:j,required:E,onCheckedChange:p,name:m,form:M,value:y,internal_do_not_use_render:({isFormControl:Y})=>c.jsxs(c.Fragment,{children:[c.jsx(Wy,{...O,ref:f,__scopeSwitch:o}),Y&&c.jsx(l0,{__scopeSwitch:o})]})})},"Switch")),Py="SwitchThumb",e0=g.forwardRef(oa(function(r,f){const{__scopeSwitch:o,...m}=r,h=Xo(Py,o);return c.jsx(Et.span,{"data-state":Qo(h.checked),"data-disabled":h.disabled?"":void 0,...m,ref:f})},"SwitchThumb")),t0="SwitchBubbleInput",l0=g.forwardRef(oa(function({__scopeSwitch:r,onClick:f,...o},m){const{control:h,hasConsumerStoppedPropagationRef:S,userInteractionCount:E,checked:j,defaultChecked:y,required:p,disabled:M,name:O,value:Y,form:H,bubbleInput:V,setBubbleInput:X}=Xo(t0,r),k=ll(m,X),Z=$h(h),w=g.useRef(!1),q=g.useRef(j),$=g.useRef(E);g.useEffect(()=>{const K=V;if(!K)return;const ne=window.HTMLInputElement.prototype,Me=Object.getOwnPropertyDescriptor(ne,"checked").set,Ce=E!==$.current;$.current=E;const xe=q.current!==j;q.current=j;const ce=!(Ce&&S.current);if(xe&&Me){w.current=!Ce;const Ne=new Event("click",{bubbles:ce});Me.call(K,j),K.dispatchEvent(Ne),w.current=!1}},[V,j,S,E]);const W=g.useRef(j);return c.jsx(Et.input,{type:"checkbox","aria-hidden":!0,defaultChecked:y??W.current,required:p,disabled:M,name:O,value:Y,form:H,...o,tabIndex:-1,ref:k,onClick:Bt(f,K=>{w.current&&K.stopPropagation()}),style:{...o.style,...Z,position:"absolute",pointerEvents:"none",opacity:0,margin:0,transform:"translateX(-100%)"}})},"SwitchBubbleInput"));function Wh(u){return typeof u=="function"}oa(Wh,"isFunction");function Qo(u){return u?"checked":"unchecked"}oa(Qo,"getState");var a0=Object.defineProperty,ut=(u,r)=>a0(u,"name",{value:r,configurable:!0});function Ih(u){const r=u+"CollectionProvider",[f,o]=ra(r),[m,h]=f(r,{collectionRef:{current:null},itemMap:new Map}),S=ut(V=>{const{scope:X,children:k}=V,Z=g.useRef(null),w=g.useRef(new Map).current;return c.jsx(m,{scope:X,itemMap:w,collectionRef:Z,children:k})},"CollectionProvider");S.displayName=r;const E=u+"CollectionSlot",j=Mn(E),y=g.forwardRef((V,X)=>{const{scope:k,children:Z}=V,w=h(E,k),q=ll(X,w.collectionRef);return c.jsx(j,{ref:q,children:Z})});y.displayName=E;const p=u+"CollectionItemSlot",M="data-radix-collection-item",O=Mn(p),Y=g.forwardRef((V,X)=>{const{scope:k,children:Z,...w}=V,q=g.useRef(null),$=ll(X,q),W=h(p,k);return g.useEffect(()=>(W.itemMap.set(q,{ref:q,...w}),()=>{W.itemMap.delete(q)})),c.jsx(O,{[M]:"",ref:$,children:Z})});Y.displayName=p;function H(V){const X=h(u+"CollectionConsumer",V);return g.useCallback(()=>{const Z=X.collectionRef.current;if(!Z)return[];const w=Array.from(Z.querySelectorAll(`[${M}]`));return Array.from(X.itemMap.values()).sort((W,K)=>w.indexOf(W.ref.current)-w.indexOf(K.ref.current))},[X.collectionRef,X.itemMap])}return ut(H,"useCollection"),[{Provider:S,Slot:y,ItemSlot:Y},H,o]}ut(Ih,"createCollection");var ph=new WeakMap,tt,Ut,bo=(Ut=class extends Map{constructor(f){super(f);th(this,tt);fo(this,tt,[...super.keys()]),ph.set(this,!0)}set(f,o){return ph.get(this)&&(this.has(f)?pt(this,tt)[pt(this,tt).indexOf(f)]=f:pt(this,tt).push(f)),super.set(f,o),this}insert(f,o,m){const h=this.has(o),S=pt(this,tt).length,E=Zo(f);let j=E>=0?E:S+E;const y=j<0||j>=S?-1:j;if(y===this.size||h&&y===this.size-1||y===-1)return this.set(o,m),this;const p=this.size+(h?0:1);E<0&&j++;const M=[...pt(this,tt)];let O,Y=!1;for(let H=j;H=this.size&&(h=this.size-1),this.at(h)}keyFrom(f,o){const m=this.indexOf(f);if(m===-1)return;let h=m+o;return h<0&&(h=0),h>=this.size&&(h=this.size-1),this.keyAt(h)}find(f,o){let m=0;for(const h of this){if(Reflect.apply(f,o,[h,m,this]))return h;m++}}findIndex(f,o){let m=0;for(const h of this){if(Reflect.apply(f,o,[h,m,this]))return m;m++}return-1}filter(f,o){const m=[];let h=0;for(const S of this)Reflect.apply(f,o,[S,h,this])&&m.push(S),h++;return new Ut(m)}map(f,o){const m=[];let h=0;for(const S of this)m.push([S[0],Reflect.apply(f,o,[S,h,this])]),h++;return new Ut(m)}reduce(...f){const[o,m]=f;let h=0,S=m??this.at(0);for(const E of this)h===0&&f.length===1?S=E:S=Reflect.apply(o,this,[S,E,h,this]),h++;return S}reduceRight(...f){const[o,m]=f;let h=m??this.at(-1);for(let S=this.size-1;S>=0;S--){const E=this.at(S);S===this.size-1&&f.length===1?h=E:h=Reflect.apply(o,this,[h,E,S,this])}return h}toSorted(f){const o=[...this.entries()].sort(f);return new Ut(o)}toReversed(){const f=new Ut;for(let o=this.size-1;o>=0;o--){const m=this.keyAt(o),h=this.get(m);f.set(m,h)}return f}toSpliced(...f){const o=[...this.entries()];return o.splice(...f),new Ut(o)}slice(f,o){const m=new Ut;let h=this.size-1;if(f===void 0)return m;f<0&&(f=f+this.size),o!==void 0&&o>0&&(h=o-1);for(let S=f;S<=h;S++){const E=this.keyAt(S),j=this.get(E);m.set(E,j)}return m}every(f,o){let m=0;for(const h of this){if(!Reflect.apply(f,o,[h,m,this]))return!1;m++}return!0}some(f,o){let m=0;for(const h of this){if(Reflect.apply(f,o,[h,m,this]))return!0;m++}return!1}},tt=new WeakMap,ut(Ut,"OrderedDict"),Ut);function Xu(u,r){if("at"in Array.prototype)return Array.prototype.at.call(u,r);const f=Ph(u,r);return f===-1?void 0:u[f]}ut(Xu,"at");function Ph(u,r){const f=u.length,o=Zo(r),m=o>=0?o:f+o;return m<0||m>=f?-1:m}ut(Ph,"toSafeIndex");function Zo(u){return u!==u||u===0?0:Math.trunc(u)}ut(Zo,"toSafeInteger");function n0(u){const r=u+"CollectionProvider",[f,o]=ra(r),[m,h]=f(r,{collectionElement:null,collectionRef:{current:null},collectionRefObject:{current:null},itemMap:new bo,setItemMap:ut(()=>{},"setItemMap")}),S=ut(({state:w,...q})=>w?c.jsx(j,{...q,state:w}):c.jsx(E,{...q}),"CollectionProvider");S.displayName=r;const E=ut(w=>{const q=X();return c.jsx(j,{...w,state:q})},"CollectionInit");E.displayName=r+"Init";const j=ut(w=>{const{scope:q,children:$,state:W}=w,K=g.useRef(null),[ne,ee]=g.useState(null),Me=ll(K,ee),[Ce,xe]=W;return g.useEffect(()=>{if(!ne)return;const ce=lp(()=>{});return ce.observe(ne,{childList:!0,subtree:!0}),()=>{ce.disconnect()}},[ne]),c.jsx(m,{scope:q,itemMap:Ce,setItemMap:xe,collectionRef:Me,collectionRefObject:K,collectionElement:ne,children:$})},"CollectionProviderImpl");j.displayName=r+"Impl";const y=u+"CollectionSlot",p=Mn(y),M=g.forwardRef((w,q)=>{const{scope:$,children:W}=w,K=h(y,$),ne=ll(q,K.collectionRef);return c.jsx(p,{ref:ne,children:W})});M.displayName=y;const O=u+"CollectionItemSlot",Y="data-radix-collection-item",H=Mn(O),V=g.forwardRef((w,q)=>{const{scope:$,children:W,...K}=w,ne=g.useRef(null),[ee,Me]=g.useState(null),Ce=ll(q,ne,Me),xe=h(O,$),{setItemMap:ce}=xe,Ne=g.useRef(K);ep(Ne.current,K)||(Ne.current=K);const Ye=Ne.current;return g.useEffect(()=>{const R=Ye;return ce(L=>ee?L.has(ee)?L.set(ee,{...R,element:ee}).toSorted(Oo):(L.set(ee,{...R,element:ee}),L.toSorted(Oo)):L),()=>{ce(L=>!ee||!L.has(ee)?L:(L.delete(ee),new bo(L)))}},[ee,Ye,ce]),c.jsx(H,{[Y]:"",ref:Ce,children:W})});V.displayName=O;function X(){return g.useState(new bo)}ut(X,"useInitCollection");function k(w){const{itemMap:q}=h(u+"CollectionConsumer",w);return q}return ut(k,"useCollection"),[{Provider:S,Slot:M,ItemSlot:V},{createCollectionScope:o,useCollection:k,useInitCollection:X}]}ut(n0,"createCollection");function ep(u,r){if(u===r)return!0;if(typeof u!="object"||typeof r!="object"||u==null||r==null)return!1;const f=Object.keys(u),o=Object.keys(r);if(f.length!==o.length)return!1;for(const m of f)if(!Object.prototype.hasOwnProperty.call(r,m)||u[m]!==r[m])return!1;return!0}ut(ep,"shallowEqual");function tp(u,r){return!!(r.compareDocumentPosition(u)&Node.DOCUMENT_POSITION_PRECEDING)}ut(tp,"isElementPreceding");function Oo(u,r){return!u[1].element||!r[1].element?0:tp(u[1].element,r[1].element)?-1:1}ut(Oo,"sortByDocumentPosition");function lp(u){return new MutationObserver(f=>{for(const o of f)if(o.type==="childList"){u();return}})}ut(lp,"getChildListObserver");var i0=Object.defineProperty,u0=(u,r)=>i0(u,"name",{value:r,configurable:!0});function ap(u){const r=g.useRef(u);return g.useEffect(()=>{r.current=u}),g.useMemo(()=>((...f)=>r.current?.(...f)),[])}u0(ap,"useCallbackRef");var c0=Object.defineProperty,s0=(u,r)=>c0(u,"name",{value:r,configurable:!0}),o0=g.createContext(void 0);function Ko(u){const r=g.useContext(o0);return u||r||"ltr"}s0(Ko,"useDirection");var r0=Object.defineProperty,Jo=(u,r)=>r0(u,"name",{value:r,configurable:!0}),So=!1;function np(){const[u,r]=g.useState(So);return g.useEffect(()=>{So||(So=!0,r(!0))},[]),u}Jo(np,"useIsHydrated");var ip=En[" useSyncExternalStore ".trim().toString()];function up(){return()=>{}}Jo(up,"subscribe");function cp(){return ip(up,()=>!0,()=>!1)}Jo(cp,"useIsHydratedModern");var f0=typeof ip=="function"?cp:np,d0=Object.defineProperty,Ua=(u,r)=>d0(u,"name",{value:r,configurable:!0}),_o="rovingFocusGroup.onEntryFocus",m0={bubbles:!1,cancelable:!0},Ju="RovingFocusGroup",[Do,sp,h0]=Ih(Ju),[p0,op]=ra(Ju,[h0]),[v0,g0]=p0(Ju),y0=g.forwardRef(Ua(function(r,f){return c.jsx(Do.Provider,{scope:r.__scopeRovingFocusGroup,children:c.jsx(Do.Slot,{scope:r.__scopeRovingFocusGroup,children:c.jsx(b0,{...r,ref:f})})})},"RovingFocusGroup")),b0=g.forwardRef(Ua(function(r,f){const{__scopeRovingFocusGroup:o,orientation:m,loop:h=!1,dir:S,currentTabStopId:E,defaultCurrentTabStopId:j,onCurrentTabStopIdChange:y,onEntryFocus:p,preventScrollOnEntryFocus:M=!1,...O}=r,Y=g.useRef(null),H=ll(f,Y),V=Ko(S),[X,k]=Ci({prop:E,defaultProp:j??null,onChange:y,caller:Ju}),[Z,w]=g.useState(!1),q=ap(p),$=sp(o),W=g.useRef(!1),[K,ne]=g.useState(0);return g.useEffect(()=>{const ee=Y.current;if(ee)return ee.addEventListener(_o,q),()=>ee.removeEventListener(_o,q)},[q]),c.jsx(v0,{scope:o,orientation:m,dir:V,loop:h,currentTabStopId:X,onItemFocus:g.useCallback(ee=>k(ee),[k]),onItemShiftTab:g.useCallback(()=>w(!0),[]),onFocusableItemAdd:g.useCallback(()=>ne(ee=>ee+1),[]),onFocusableItemRemove:g.useCallback(()=>ne(ee=>ee-1),[]),children:c.jsx(Et.div,{tabIndex:Z||K===0?-1:0,"data-orientation":m,...O,ref:H,style:{outline:"none",...r.style},onMouseDown:Bt(r.onMouseDown,()=>{W.current=!0}),onFocus:Bt(r.onFocus,ee=>{const Me=!W.current;if(ee.target===ee.currentTarget&&Me&&!Z){const Ce=new CustomEvent(_o,m0);if(ee.currentTarget.dispatchEvent(Ce),!Ce.defaultPrevented){const xe=$().filter(L=>L.focusable),ce=xe.find(L=>L.active),Ne=xe.find(L=>L.id===X),R=[ce,Ne,...xe].filter(Boolean).map(L=>L.ref.current);$o(R,M)}}W.current=!1}),onBlur:Bt(r.onBlur,()=>w(!1))})})},"RovingFocusGroupImpl")),S0="RovingFocusGroupItem",_0=g.forwardRef(Ua(function(r,f){const{__scopeRovingFocusGroup:o,focusable:m=!0,active:h=!1,tabStopId:S,children:E,...j}=r,y=Zu(),p=S||y,M=g0(S0,o),O=M.currentTabStopId===p,Y=sp(o),{onFocusableItemAdd:H,onFocusableItemRemove:V,currentTabStopId:X}=M,k=f0();return sa(()=>{if(!(!k||!m))return H(),()=>V()},[k,m,H,V]),g.useEffect(()=>{if(!(k||!m))return H(),()=>V()},[k,m,H,V]),c.jsx(Do.ItemSlot,{scope:o,id:p,focusable:m,active:h,children:c.jsx(Et.span,{tabIndex:O?0:-1,"data-orientation":M.orientation,...j,ref:f,onMouseDown:Bt(r.onMouseDown,Z=>{m?M.onItemFocus(p):Z.preventDefault()}),onFocus:Bt(r.onFocus,()=>M.onItemFocus(p)),onKeyDown:Bt(r.onKeyDown,Z=>{if(Z.key==="Tab"&&Z.shiftKey){M.onItemShiftTab();return}if(Z.target!==Z.currentTarget)return;const w=fp(Z,M.orientation,M.dir);if(w!==void 0){if(Z.metaKey||Z.ctrlKey||Z.altKey||Z.shiftKey)return;Z.preventDefault();let $=Y().filter(W=>W.focusable).map(W=>W.ref.current);if(w==="last")$.reverse();else if(w==="prev"||w==="next"){w==="prev"&&$.reverse();const W=$.indexOf(Z.currentTarget);$=M.loop?dp($,W+1):$.slice(W+1)}setTimeout(()=>$o($))}}),children:typeof E=="function"?E({isCurrentTabStop:O,hasTabStop:X!=null}):E})})},"RovingFocusGroupItem")),x0={ArrowLeft:"prev",ArrowUp:"prev",ArrowRight:"next",ArrowDown:"next",PageUp:"first",Home:"first",PageDown:"last",End:"last"};function rp(u,r){return r!=="rtl"?u:u==="ArrowLeft"?"ArrowRight":u==="ArrowRight"?"ArrowLeft":u}Ua(rp,"getDirectionAwareKey");function fp(u,r,f){const o=rp(u.key,f);if(!(r==="vertical"&&["ArrowLeft","ArrowRight"].includes(o))&&!(r==="horizontal"&&["ArrowUp","ArrowDown"].includes(o)))return x0[o]}Ua(fp,"getFocusIntent");function $o(u,r=!1){const f=document.activeElement;for(const o of u)if(o===f||(o.focus({preventScroll:r}),document.activeElement!==f))return}Ua($o,"focusFirst");function dp(u,r){return u.map((f,o)=>u[(r+o)%u.length])}Ua(dp,"wrapArray");var j0=y0,M0=_0,C0=Object.defineProperty,An=(u,r)=>C0(u,"name",{value:r,configurable:!0}),Fo="Tabs",[E0,C1]=ra(Fo,[op]),mp=op(),[T0,Wo]=E0(Fo),A0=g.forwardRef(An(function(r,f){const{__scopeTabs:o,value:m,onValueChange:h,defaultValue:S,orientation:E="horizontal",dir:j,activationMode:y="automatic",...p}=r,M=Ko(j),[O,Y]=Ci({prop:m,onChange:h,defaultProp:S??"",caller:Fo});return c.jsx(T0,{scope:o,baseId:Zu(),value:O,onValueChange:Y,orientation:E,dir:M,activationMode:y,children:c.jsx(Et.div,{dir:M,"data-orientation":E,...p,ref:f})})},"Tabs")),z0="TabsList",N0=g.forwardRef(An(function(r,f){const{__scopeTabs:o,loop:m=!0,...h}=r,S=Wo(z0,o),E=mp(o);return c.jsx(j0,{asChild:!0,...E,orientation:S.orientation,dir:S.dir,loop:m,children:c.jsx(Et.div,{role:"tablist","aria-orientation":S.orientation,...h,ref:f})})},"TabsList")),R0="TabsTrigger",O0=g.forwardRef(An(function(r,f){const{__scopeTabs:o,value:m,disabled:h=!1,...S}=r,E=Wo(R0,o),j=mp(o),y=Io(E.baseId,m),p=Po(E.baseId,m),M=m===E.value;return c.jsx(M0,{asChild:!0,...j,focusable:!h,active:M,children:c.jsx(Et.button,{type:"button",role:"tab","aria-selected":M,"aria-controls":p,"data-state":M?"active":"inactive","data-disabled":h?"":void 0,disabled:h,id:y,...S,ref:f,onMouseDown:Bt(r.onMouseDown,O=>{!h&&O.button===0&&O.ctrlKey===!1?E.onValueChange(m):O.preventDefault()}),onKeyDown:Bt(r.onKeyDown,O=>{h||O.target!==O.currentTarget||[" ","Enter"].includes(O.key)&&E.onValueChange(m)}),onFocus:Bt(r.onFocus,()=>{const O=E.activationMode!=="manual";!M&&!h&&O&&E.onValueChange(m)})})})},"TabsTrigger")),D0="TabsContent",w0=g.forwardRef(An(function(r,f){const{__scopeTabs:o,value:m,forceMount:h,children:S,...E}=r,j=Wo(D0,o),y=Io(j.baseId,m),p=Po(j.baseId,m),M=m===j.value,O=g.useRef(M);return g.useEffect(()=>{const Y=requestAnimationFrame(()=>O.current=!1);return()=>cancelAnimationFrame(Y)},[]),c.jsx(qh,{present:h||M,children:({present:Y})=>c.jsx(Et.div,{"data-state":M?"active":"inactive","data-orientation":j.orientation,role:"tabpanel","aria-labelledby":y,hidden:!Y,id:p,tabIndex:0,...E,ref:f,style:{...r.style,animationDuration:O.current?"0s":void 0},children:Y&&S})})},"TabsContent"));function Io(u,r){return`${u}-trigger-${r}`}An(Io,"makeTriggerId");function Po(u,r){return`${u}-content-${r}`}An(Po,"makeContentId");var U0=A0,G0=N0,xo=O0,jo=w0;const B0=u=>u.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),hp=(...u)=>u.filter((r,f,o)=>!!r&&r.trim()!==""&&o.indexOf(r)===f).join(" ").trim();var H0={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};const k0=g.forwardRef(({color:u="currentColor",size:r=24,strokeWidth:f=2,absoluteStrokeWidth:o,className:m="",children:h,iconNode:S,...E},j)=>g.createElement("svg",{ref:j,...H0,width:r,height:r,stroke:u,strokeWidth:o?Number(f)*24/Number(r):f,className:hp("lucide",m),...E},[...S.map(([y,p])=>g.createElement(y,p)),...Array.isArray(h)?h:[h]]));const ke=(u,r)=>{const f=g.forwardRef(({className:o,...m},h)=>g.createElement(k0,{ref:h,iconNode:r,className:hp(`lucide-${B0(u)}`,o),...m}));return f.displayName=`${u}`,f};const pp=ke("Activity",[["path",{d:"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2",key:"169zse"}]]);const q0=ke("Box",[["path",{d:"M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z",key:"hh9hay"}],["path",{d:"m3.3 7 8.7 5 8.7-5",key:"g66t2b"}],["path",{d:"M12 22V12",key:"d0xqtd"}]]);const al=ke("Check",[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]]);const vp=ke("ChevronDown",[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]]);const gp=ke("ChevronLeft",[["path",{d:"m15 18-6-6 6-6",key:"1wnfg3"}]]);const yp=ke("ChevronRight",[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]]);const L0=ke("ChevronUp",[["path",{d:"m18 15-6-6-6 6",key:"153udz"}]]);const Ti=ke("CircleAlert",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]]);const Y0=ke("CircleCheck",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]]);const bp=ke("Copy",[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]]);const V0=ke("Cpu",[["rect",{width:"16",height:"16",x:"4",y:"4",rx:"2",key:"14l7u7"}],["rect",{width:"6",height:"6",x:"9",y:"9",rx:"1",key:"5aljv4"}],["path",{d:"M15 2v2",key:"13l42r"}],["path",{d:"M15 20v2",key:"15mkzm"}],["path",{d:"M2 15h2",key:"1gxd5l"}],["path",{d:"M2 9h2",key:"1bbxkp"}],["path",{d:"M20 15h2",key:"19e6y8"}],["path",{d:"M20 9h2",key:"19tzq7"}],["path",{d:"M9 2v2",key:"165o2o"}],["path",{d:"M9 20v2",key:"i2bqo8"}]]);const vh=ke("Database",[["ellipse",{cx:"12",cy:"5",rx:"9",ry:"3",key:"msslwz"}],["path",{d:"M3 5V19A9 3 0 0 0 21 19V5",key:"1wlel7"}],["path",{d:"M3 12A9 3 0 0 0 21 12",key:"mv7ke4"}]]);const Sp=ke("Download",[["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["polyline",{points:"7 10 12 15 17 10",key:"2ggqvy"}],["line",{x1:"12",x2:"12",y1:"15",y2:"3",key:"1vk2je"}]]);const _p=ke("FolderUp",[["path",{d:"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z",key:"1kt360"}],["path",{d:"M12 10v6",key:"1bos4e"}],["path",{d:"m9 13 3-3 3 3",key:"1pxg3c"}]]);const X0=ke("Github",[["path",{d:"M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4",key:"tonef"}],["path",{d:"M9 18c-4.51 2-5-2-7-2",key:"9comsn"}]]);const gh=ke("Maximize2",[["polyline",{points:"15 3 21 3 21 9",key:"mznyad"}],["polyline",{points:"9 21 3 21 3 15",key:"1avn1i"}],["line",{x1:"21",x2:"14",y1:"3",y2:"10",key:"ota7mn"}],["line",{x1:"3",x2:"10",y1:"21",y2:"14",key:"1atl0r"}]]);const wo=ke("Minus",[["path",{d:"M5 12h14",key:"1ays0h"}]]);const Q0=ke("MonitorCog",[["path",{d:"M12 17v4",key:"1riwvh"}],["path",{d:"m15.2 4.9-.9-.4",key:"12wd2u"}],["path",{d:"m15.2 7.1-.9.4",key:"1r2vl7"}],["path",{d:"m16.9 3.2-.4-.9",key:"3zbo91"}],["path",{d:"m16.9 8.8-.4.9",key:"1qr2dn"}],["path",{d:"m19.5 2.3-.4.9",key:"1rjrkq"}],["path",{d:"m19.5 9.7-.4-.9",key:"heryx5"}],["path",{d:"m21.7 4.5-.9.4",key:"17fqt1"}],["path",{d:"m21.7 7.5-.9-.4",key:"14zyni"}],["path",{d:"M22 13v2a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7",key:"1tnzv8"}],["path",{d:"M8 21h8",key:"1ev6f3"}],["circle",{cx:"18",cy:"6",r:"3",key:"1h7g24"}]]);const xp=ke("Play",[["polygon",{points:"6 3 20 12 6 21 6 3",key:"1oa8hb"}]]);const tl=ke("RefreshCw",[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]]);const Qu=ke("Server",[["rect",{width:"20",height:"8",x:"2",y:"2",rx:"2",ry:"2",key:"ngkwjq"}],["rect",{width:"20",height:"8",x:"2",y:"14",rx:"2",ry:"2",key:"iecqi9"}],["line",{x1:"6",x2:"6.01",y1:"6",y2:"6",key:"16zg32"}],["line",{x1:"6",x2:"6.01",y1:"18",y2:"18",key:"nzw8ys"}]]);const Z0=ke("SlidersHorizontal",[["line",{x1:"21",x2:"14",y1:"4",y2:"4",key:"obuewd"}],["line",{x1:"10",x2:"3",y1:"4",y2:"4",key:"1q6298"}],["line",{x1:"21",x2:"12",y1:"12",y2:"12",key:"1iu8h1"}],["line",{x1:"8",x2:"3",y1:"12",y2:"12",key:"ntss68"}],["line",{x1:"21",x2:"16",y1:"20",y2:"20",key:"14d8ph"}],["line",{x1:"12",x2:"3",y1:"20",y2:"20",key:"m0wm8r"}],["line",{x1:"14",x2:"14",y1:"2",y2:"6",key:"14e1ph"}],["line",{x1:"8",x2:"8",y1:"10",y2:"14",key:"1i6ji0"}],["line",{x1:"16",x2:"16",y1:"18",y2:"22",key:"1lctlv"}]]);const $u=ke("Square",[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}]]);const er=ke("Terminal",[["polyline",{points:"4 17 10 11 4 5",key:"akl6gq"}],["line",{x1:"12",x2:"20",y1:"19",y2:"19",key:"q2wloq"}]]);const K0=ke("Wrench",[["path",{d:"M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z",key:"cbrjhi"}]]);const Da=ke("X",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);async function jp(u){try{return await navigator.clipboard.writeText(u),!0}catch{const r=document.createElement("textarea");r.value=u,r.style.position="fixed",r.style.opacity="0",document.body.appendChild(r),r.focus(),r.select();try{return document.execCommand("copy")}catch{return!1}finally{r.remove()}}}function J0({deployment:u,onCancel:r,onClose:f}){const o=g.useRef(null),m=g.useRef(null),[h,S]=g.useState(!1),E=u.log_tail.join(` +`)||"Waiting for Modal build output…";g.useEffect(()=>{const y=p=>{p.key==="Escape"&&f()};return window.addEventListener("keydown",y),()=>window.removeEventListener("keydown",y)},[f]),g.useEffect(()=>{o.current&&(o.current.scrollTop=o.current.scrollHeight)},[u.log_tail.length]),g.useEffect(()=>()=>{m.current!==null&&window.clearTimeout(m.current)},[]);const j=async()=>{await jp(E)&&(S(!0),m.current!==null&&window.clearTimeout(m.current),m.current=window.setTimeout(()=>S(!1),1e3))};return Bo.createPortal(c.jsx("div",{className:"modal-log-backdrop",onMouseDown:y=>{y.target===y.currentTarget&&f()},children:c.jsxs("section",{className:"modal-log-dialog",role:"dialog","aria-modal":"true","aria-labelledby":"modal-log-title",children:[c.jsxs("header",{children:[c.jsxs("div",{children:[c.jsx("span",{children:"MODAL SETUP & DEPLOYMENT"}),c.jsx("strong",{id:"modal-log-title",children:u.stage})]}),c.jsxs("small",{children:[u.gpu,u.cpu?` · ${u.cpu} CPU`:"",u.memory_mb?` · ${ji(u.memory_mb*1024*1024)}`:""," · ",u.status]}),["queued","running"].includes(u.status)&&u.phase!=="verifying"&&c.jsxs("button",{className:"modal-dialog-stop",type:"button",onClick:r,title:"Stop Modal setup",children:[c.jsx($u,{size:11,fill:"currentColor"})," Stop"]}),c.jsxs("button",{type:"button",onClick:j,title:"Copy deployment logs",children:[h?c.jsx(al,{size:13}):c.jsx(bp,{size:13})," ",h?"Copied!":"Copy"]}),c.jsx("button",{type:"button",onClick:f,title:"Close deployment logs","aria-label":"Close deployment logs",children:c.jsx(Da,{size:15})})]}),c.jsx("pre",{ref:o,children:E})]})}),document.body)}const yh=[{id:"building",label:"Prepare CUDA image",detail:"Install and cache the GTSFM environment"},{id:"deploying",label:"Deploy workspace",detail:"Publish the FastAPI workspace on Modal"},{id:"verifying",label:"Start & verify workspace",detail:"Cold-start the GPU and confirm the workspace API is healthy"}];function $0({deployment:u,onCancel:r,onExpand:f}){const o=u.phase==="ready",m=u.phase==="verifying",h=o?"verifying":u.phase??"building",S=Math.max(0,yh.findIndex(j=>j.id===h)),E=u.image_source==="prebuilt"?"Pull the versioned GTSFM runtime; no package installation":"Install and cache the GTSFM environment";return c.jsxs("section",{className:`modal-deployment ${u.status}`,"aria-label":"Modal workspace progress",children:[c.jsxs("div",{className:"modal-deployment-heading",children:[c.jsxs("span",{children:[o?c.jsx(al,{size:12}):u.status==="failed"?c.jsx(Ti,{size:12}):u.status==="cancelled"?c.jsx(wo,{size:12}):c.jsx(tl,{size:12}),c.jsx("strong",{children:u.stage})]}),c.jsxs("span",{className:"modal-deployment-actions",children:[c.jsxs("small",{children:[u.image_source==="prebuilt"?"PREBUILT":"SOURCE"," · ",u.gpu]}),["queued","running"].includes(u.status)&&!m&&c.jsxs("button",{className:"modal-stop-action",type:"button",onClick:r,title:"Stop Modal setup",children:[c.jsx($u,{size:9,fill:"currentColor"})," Stop"]}),c.jsx("button",{type:"button",onClick:f,title:"View all setup logs","aria-label":"View all setup logs",children:c.jsx(gh,{size:12})})]})]}),c.jsx("ol",{className:"modal-deployment-steps",children:yh.map((j,y)=>{const p=o||y{const h=m.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),S=u.match(new RegExp(`(?:^|\\s)${h}(?:=|\\s+)(?:"([^"]+)"|'([^']+)'|([^\\s]+))`));return(S?.[1]??S?.[2]??S?.[3]??"").trim()},f=r("--token-id"),o=r("--token-secret");return f&&o?{tokenId:f,tokenSecret:o}:null}const Mo=u=>u.modal_api_key,Cn=u=>String(u??"").split("_").map(r=>["api","ba","colmap","gpu","gs","mvs","sift","vggt"].includes(r)?r.toUpperCase():r==="anysplat"?"AnySplat":r==="megaloc"?"MegaLoc":r.charAt(0).toUpperCase()+r.slice(1)).join(" "),wl=u=>u instanceof Error?u.message:String(u);async function Gt(u,r){const f=await fetch(u,r),o=await f.json();if(!f.ok)throw new Error(o.error||`Request failed (${f.status})`);return o}const bh=u=>`${location.protocol==="https:"?"wss:":"ws:"}//${location.host}${u}`;function e1({collapsed:u,onToggle:r}){return c.jsxs("header",{className:"studio-header","aria-label":"SfM Studio",children:[c.jsx("div",{className:"brand-primary",children:c.jsx("img",{className:"brand-logo",src:"/static/brand/sfm-logo.png",alt:"SfM"})}),c.jsx("img",{className:"brand-mark",src:"/static/brand/bee-favicon.png",alt:"","aria-hidden":"true"}),c.jsx("button",{className:"sidebar-toggle",type:"button",onClick:r,title:u?"Expand side panel":"Collapse side panel","aria-label":u?"Expand side panel":"Collapse side panel",children:u?c.jsx(yp,{size:16}):c.jsx(gp,{size:16})})]})}function tr({label:u,optional:r=!1,children:f}){return c.jsxs("label",{children:[u,r&&c.jsx("span",{className:"optional",children:"optional"}),f]})}function it({label:u,value:r,options:f,onChange:o,disabled:m=!1,empty:h=null,id:S}){return c.jsx(tr,{label:u,children:c.jsxs("select",{id:S,value:r??"",onChange:E=>o(E.target.value),disabled:m,children:[h!==null&&c.jsx("option",{value:"",children:h}),f.map(E=>{const j=typeof E=="string"?{id:E,label:Cn(E)}:E;return c.jsx("option",{value:j.id,disabled:!!(j.status&&j.status!=="available"),children:j.label},j.id)})]})})}function Qe({label:u,optional:r=!1,value:f,onChange:o,...m}){return c.jsx(tr,{label:u,optional:r,children:c.jsx("input",{value:f??"",onChange:h=>o(h.target.value),...m})})}const ji=u=>{const r=["B","KB","MB","GB","TB"];let f=u,o=0;for(;f>=1024&&o0?f.toFixed(1):Math.round(f)} ${r[o]}`},wa=[{id:"T4",label:"NVIDIA T4 · 16 GB · $0.59/hr",pricePerSecond:164e-6,relativeSpeed:.3,memoryGiB:16},{id:"L4",label:"NVIDIA L4 · 24 GB · $0.80/hr",pricePerSecond:222e-6,relativeSpeed:.5,memoryGiB:24},{id:"A10",label:"NVIDIA A10 · 24 GB · $1.10/hr",pricePerSecond:306e-6,relativeSpeed:.58,memoryGiB:24},{id:"L40S",label:"NVIDIA L40S · 48 GB · $1.95/hr",pricePerSecond:542e-6,relativeSpeed:1,memoryGiB:48},{id:"A100-40GB",label:"NVIDIA A100 · 40 GB · $2.10/hr",pricePerSecond:583e-6,relativeSpeed:1.18,memoryGiB:40},{id:"A100-80GB",label:"NVIDIA A100 · 80 GB · $2.50/hr",pricePerSecond:694e-6,relativeSpeed:1.3,memoryGiB:80},{id:"RTX-PRO-6000",label:"NVIDIA RTX PRO 6000 · 96 GB · $3.03/hr",pricePerSecond:842e-6,relativeSpeed:1.45,memoryGiB:96},{id:"H100",label:"NVIDIA H100 · 80 GB · $3.95/hr",pricePerSecond:.001097,relativeSpeed:1.8,memoryGiB:80},{id:"H200",label:"NVIDIA H200 · 141 GB · $4.54/hr",pricePerSecond:.001261,relativeSpeed:1.95,memoryGiB:141},{id:"B200",label:"NVIDIA B200 · 180 GB · $6.25/hr",pricePerSecond:.001736,relativeSpeed:2.35,memoryGiB:180},{id:"B300",label:"NVIDIA B300 · 288 GB · Coming Soon!",status:"coming-soon",pricePerSecond:.001972,relativeSpeed:2.65,memoryGiB:288}];function t1(u,r,f=0){const o=r?.image_count||f;if(!o)return null;const m=r?.average_megapixels&&r.average_megapixels>0?r.average_megapixels:8,h=Number(u.max_resolution),S=Number.isFinite(h)&&h>0?h**2*.75/1e6:m,E=Math.max(.25,Math.min(m,S)),j=o*Math.sqrt(E/8),y=u.config_name==="vggt"?5:u.config_name.includes("fast")?3:7,p=u.splat_implementation==="gsplat"?3:u.splat_implementation==="anysplat"?6:0,M=Math.ceil(5+j*.1+y+p+(u.run_mvs?4:0));let O="L4";M<=14&&u.splat_implementation==="none"?O="T4":M<=22?O="L4":M<=44?O="L40S":M<=72&&j<350?O="A100-80GB":M<=72?O="H100":M<=125?O="H200":O="B200";const Y=wa.find(V=>V.id===O)??wa[3],H=o<40?"small":o<140?"medium":o<350?"large":"very large";return{gpu:Y,imageCount:o,effectiveMegapixels:E,estimatedMemoryGiB:M,reason:`${H} ${o}-image workload at about ${E.toFixed(E<10?1:0)} MP per image`}}function l1({recommendation:u,selectedGpu:r,onApply:f}){if(!u)return c.jsxs("div",{className:"modal-gpu-recommendation empty",children:[c.jsx("strong",{children:"VM recommendation"}),c.jsx("p",{children:"Choose a sample or upload images to size the Modal GPU automatically."})]});const o=r===u.gpu.id;return c.jsxs("section",{className:`modal-gpu-recommendation ${o?"selected":"overridden"}`,"aria-label":"Recommended Modal VM size",children:[c.jsxs("div",{children:[c.jsx("span",{children:"RECOMMENDED VM"}),c.jsxs("strong",{children:[u.gpu.id," · ",u.gpu.memoryGiB," GB"]})]}),c.jsxs("p",{children:[u.reason,". Estimated peak GPU memory is approximately ",u.estimatedMemoryGiB," GiB, including working headroom."]}),o?c.jsxs("small",{children:[c.jsx(al,{size:11})," Selected automatically"]}):c.jsx("button",{type:"button",onClick:f,children:"Use recommended"})]})}const Sh=u=>u<60?`${Math.max(1,Math.round(u))} min`:`${(u/60).toFixed(u<120?1:0)} hr`,_h=u=>`$${u<10?u.toFixed(2):u.toFixed(1)}`;function lr(u){const r=u.trim().match(/^([\d.]+)\s*(gb|gib|mb|mib)?$/i);if(!r)return 32;const f=Number(r[1]);return/m/i.test(r[2]||"")?f/1024:f}const xh={T4:{cpu:4,memoryGiB:32},L4:{cpu:4,memoryGiB:32},A10:{cpu:6,memoryGiB:48},L40S:{cpu:8,memoryGiB:64},"A100-40GB":{cpu:8,memoryGiB:64},"A100-80GB":{cpu:12,memoryGiB:96},"RTX-PRO-6000":{cpu:16,memoryGiB:128},H100:{cpu:16,memoryGiB:128},H200:{cpu:20,memoryGiB:192},B200:{cpu:24,memoryGiB:256}};function a1(u,r,f){if(u.execution_target==="remote"){if(u.remote_connection==="api"&&u.remote_provider==="modal"){const p=xh[u.modal_gpu]??xh.L40S,M=wa.find(O=>O.id===u.modal_gpu);return{key:`modal:${u.modal_gpu}`,label:`Modal ${u.modal_gpu}`,description:`${M?.memoryGiB??48} GB GPU · CPU and RAM are provisioned when this workspace is deployed. One worker is fixed to the single GPU.`,workers:1,threadsPerWorker:p.cpu,memoryPerWorkerGiB:p.memoryGiB,allowWorkers:!1,allowThreads:!0,allowMemory:!0,allowLocalRuntime:!1}}return{key:`remote:${u.remote_connection}:${u.remote_provider}`,label:u.remote_connection==="ssh"?"Direct VM (coming soon)":`${Cn(u.remote_provider)} VM`,description:"Machine-level tuning is unavailable until this remote provider is connected.",workers:1,threadsPerWorker:1,memoryPerWorkerGiB:32,allowWorkers:!1,allowThreads:!1,allowMemory:!1,allowLocalRuntime:!1}}const o=r?.devices.find(p=>p.kind==="cpu"),m=Math.max(1,Number(o?.details.match(/(\d+)\s+logical cores/i)?.[1])||1),h=Math.max(4,lr(o?.memory||"32GB")),S=!!(f&&f.kind!=="cpu"),E=S?1:Math.min(4,Math.max(1,Math.floor(m/4))),j=S?Math.min(8,m):Math.max(1,Math.floor(m/E)),y=Math.max(4,Math.floor(h*.75/E));return{key:`local:${f?.id??"detecting"}:${m}:${Math.round(h)}`,label:f?.label??"Detecting this machine",description:S?"One worker is assigned to the selected accelerator. CPU threads and host-memory limits remain adjustable.":"Worker count, CPU threads, and memory are tuned from the detected local resources.",workers:E,threadsPerWorker:j,memoryPerWorkerGiB:y,allowWorkers:!S,allowThreads:!!f,allowMemory:!!f,allowLocalRuntime:!0}}function n1({form:u,analysis:r,fallbackImageCount:f}){const o=r?.image_count||f;if(!o)return c.jsxs("div",{className:"modal-estimate empty",children:[c.jsx("strong",{children:"Cost estimate"}),c.jsx("p",{children:"Choose a GTSFM sample or upload an image dataset to calculate an estimate."})]});const m=wa.find(ee=>ee.id===u.modal_gpu)??wa[3],h=r?.average_megapixels||8,S=Number(u.max_resolution),E=Number.isFinite(S)&&S>0?S**2*.75/1e6:h,j=Math.min(h,E),y=Math.max(.65,Math.min(2.5,Math.sqrt(j/2))),p=u.config_name.includes("fast")?.75:u.config_name==="vggt"?1:1.35,M=(2+o*.09*y+Math.pow(o,1.35)*.025)*p,O=Math.max(1,Number(u.gs_max_steps)||7e3),Y=u.splat_implementation==="gsplat"?O/1e3*(.45+Math.sqrt(o)*.08)*y:u.splat_implementation==="anysplat"?1.5+o*.04*y:0,H=u.run_mvs?1+o*.12*y:0,X=(M+Y+H)/m.relativeSpeed,k=Math.max(1,X*.7),Z=Math.max(k+1,X*1.8+2),w=Math.max(1,Number(u.num_workers)*Number(u.threads_per_worker)||1),q=Math.max(1,lr(u.worker_memory_limit)*Math.max(1,Number(u.num_workers)||1)),$=m.pricePerSecond+w*131e-7+q*222e-8,W=k*60*$,K=Z*60*$,ne=r?.image_count?`${r.image_count} images · ${r.total_megapixels.toLocaleString()} source MP · ${ji(r.image_bytes)}`:`${o} catalog images · resolution assumed`;return c.jsxs("section",{className:"modal-estimate","aria-label":"Estimated Modal compute cost",children:[c.jsxs("div",{className:"modal-estimate-heading",children:[c.jsxs("div",{children:[c.jsx("span",{children:"ESTIMATED MODAL COMPUTE"}),c.jsxs("strong",{children:[_h(W),"–",_h(K)]})]}),c.jsxs("em",{children:[Sh(k),"–",Sh(Z)]})]}),c.jsx("div",{className:"modal-estimate-bar",children:c.jsx("span",{style:{width:`${Math.min(100,Math.max(12,k/Z*100))}%`}})}),c.jsx("p",{children:ne}),c.jsxs("small",{children:[Cn(u.config_name)," · ",Cn(u.splat_implementation),u.splat_implementation==="gsplat"?` · ${O.toLocaleString()} steps`:""," · ",m.id]}),c.jsxs("small",{children:["Estimate includes GPU plus approximately ",w," CPU core",w===1?"":"s"," and ",q.toFixed(0)," GiB memory. Actual runtime and billing vary with scene complexity, caching, and utilization."]}),c.jsx("a",{href:"https://modal.com/pricing",target:"_blank",rel:"noreferrer",children:"Modal pricing · rates checked Aug 13, 2026 ↗"})]})}async function Mp(u,r=""){const f=r?`${r}/${u.name}`:u.name;if(u.isFile)return[{file:await new Promise((S,E)=>u.file(S,E)),relativePath:f}];if(!u.isDirectory)return[];const o=u.createReader(),m=[];for(;;){const h=await new Promise((S,E)=>o.readEntries(S,E));if(!h.length)break;m.push(...h)}return(await Promise.all(m.map(h=>Mp(h,f)))).flat()}async function i1(u){const r=Array.from(u.items).map(f=>f.webkitGetAsEntry?.()).filter(f=>!!f);return r.length?(await Promise.all(r.map(f=>Mp(f)))).flat():Array.from(u.files).map(f=>({file:f,relativePath:f.name}))}function jh({label:u,optional:r=!1,value:f,onUploaded:o,onError:m}){const h=g.useRef(null),[S,E]=g.useState(!1),[j,y]=g.useState(!1),p=async M=>{if(!M.length){m("Choose a folder containing at least one file.");return}y(!0),m("");try{const O=new FormData;O.append("manifest",JSON.stringify(M.map(H=>H.relativePath))),M.forEach(H=>O.append("files",H.file,H.file.name));const Y=await Gt("/api/uploads",{method:"POST",body:O});o(Y)}catch(O){m(wl(O))}finally{y(!1)}};return c.jsxs("div",{className:"folder-field",children:[c.jsxs("div",{className:"folder-label",children:[u,r&&c.jsx("span",{className:"optional",children:"optional"})]}),c.jsxs("button",{type:"button",className:`folder-drop ${S?"dragging":""} ${f?"has-folder":""}`,onClick:()=>h.current?.click(),onDragEnter:M=>{M.preventDefault(),E(!0)},onDragOver:M=>{M.preventDefault(),M.dataTransfer.dropEffect="copy"},onDragLeave:M=>{M.currentTarget.contains(M.relatedTarget)||E(!1)},onDrop:async M=>{M.preventDefault(),E(!1),await p(await i1(M.dataTransfer))},disabled:j,children:[c.jsx("span",{className:"folder-icon",children:f?c.jsx(al,{size:17}):c.jsx(_p,{size:18})}),c.jsx("span",{className:"folder-copy",children:j?c.jsxs(c.Fragment,{children:[c.jsx("strong",{children:"Importing folder…"}),c.jsx("small",{children:"Keeping the directory structure intact"})]}):f?c.jsxs(c.Fragment,{children:[c.jsx("strong",{children:f.name}),c.jsxs("small",{children:[f.file_count," file",f.file_count===1?"":"s"," · ",ji(f.bytes)," · Click to replace"]})]}):c.jsxs(c.Fragment,{children:[c.jsx("strong",{children:"Drop a folder here"}),c.jsx("small",{children:"or click to choose one"})]})})]}),c.jsx("input",{ref:h,className:"folder-input",type:"file",multiple:!0,webkitdirectory:"",directory:"",onChange:async M=>{const O=Array.from(M.target.files??[]);await p(O.map(Y=>({file:Y,relativePath:Y.webkitRelativePath||Y.name}))),M.target.value=""}}),f&&c.jsx("button",{type:"button",className:"folder-remove",onClick:()=>o(null),children:"Remove selection"})]})}function Mh({id:u,checked:r,onCheckedChange:f,disabled:o=!1,children:m}){return c.jsxs("div",{className:`toggle-row ${o?"disabled":""}`,children:[c.jsx(Iy,{id:u,className:"switch-root",checked:r,onCheckedChange:f,disabled:o,children:c.jsx(e0,{className:"switch-thumb"})}),c.jsx("label",{htmlFor:u,children:m})]})}function Co({number:u,title:r,subtitle:f,children:o}){return c.jsxs("section",{className:"form-section",children:[c.jsxs("div",{className:"section-heading",children:[c.jsx("span",{className:"step-number",children:u}),c.jsxs("div",{children:[c.jsx("strong",{children:r}),c.jsx("small",{children:f})]})]}),o]})}function u1({descriptors:u,values:r,setValues:f}){return u.length?c.jsxs("div",{className:"loader-options",children:[c.jsx("p",{className:"mini-heading",children:"Format-specific options"}),u.map(o=>o.type==="boolean"?c.jsx(it,{label:o.label,value:String(r[o.name]??o.default??!1),options:[{id:"true",label:"True"},{id:"false",label:"False"}],onChange:m=>f(h=>({...h,[o.name]:m==="true"}))},o.name):c.jsx(Qe,{label:o.label,optional:!o.required,required:o.required,type:["integer","number"].includes(o.type)?"number":"text",step:o.type==="number"?"any":void 0,value:r[o.name]??o.default??"",onChange:m=>f(h=>({...h,[o.name]:m}))},o.name))]}):null}function c1({device:u}){return u?c.jsxs("div",{className:"hardware-card",children:[c.jsx("strong",{children:u.label}),c.jsxs("small",{children:[u.details,u.memory?` · ${u.memory}`:""]}),c.jsx("span",{className:`capability ${u.supports_gaussian_splatting?"yes":"no"}`,children:u.supports_gaussian_splatting?"Splat ready":"Reconstruction"})]}):c.jsx("div",{className:"hardware-card",children:c.jsx("strong",{children:"Detecting hardware…"})})}function s1({schema:u,hardware:r,samples:f,samplesLoading:o,onStarted:m,onTabChange:h,remotePromptKey:S,schemaLoading:E,schemaError:j,onRetrySchema:y}){const[p,M]=g.useState(W0),[O,Y]=g.useState("upload"),[H,V]=g.useState({}),[X,k]=g.useState(null),[Z,w]=g.useState(""),[q,$]=g.useState(""),[W,K]=g.useState(!1),[ne,ee]=g.useState(!1),[Me,Ce]=g.useState(!1),[xe,ce]=g.useState(!1),[Ne,Ye]=g.useState(null),[R,L]=g.useState(!1),[le,Ee]=g.useState(!1),[je,_]=g.useState(!1),[G,Q]=g.useState(""),[J,ue]=g.useState(null),[se,Se]=g.useState(null),[Be,He]=g.useState(null),[Tt,Wt]=g.useState(!1),[ml,il]=g.useState(""),ct=g.useRef(0),ul=g.useRef(""),P=(x,fe)=>M(pe=>({...pe,[x]:fe}));g.useEffect(()=>{if(!r)return;const x=r.devices.find(fe=>fe.supports_gaussian_splatting);M(fe=>({...fe,hardware:x?.id??r.devices[0]?.id??"cpu",splat_implementation:fe.execution_target==="local"&&!x?"none":fe.splat_implementation}))},[r]),g.useEffect(()=>{S<1||(M(x=>({...x,execution_target:"remote",remote_connection:"api",remote_provider:"modal",splat_implementation:x.splat_implementation==="none"?u.defaults.splat_implementation:x.splat_implementation})),window.setTimeout(()=>document.getElementById("computeTarget")?.scrollIntoView({behavior:"smooth",block:"start"}),0))},[S,u]);const fa=X?.configuration?.models??u.models,hl=fa.find(x=>x.id===p.config_name),Ht=hl?.capabilities??{iterative_splat:!1,mvs:!1,share_intrinsics:!1},da=g.useMemo(()=>u.splat_implementations.map(x=>({...x,status:x.id==="gsplat"&&!Ht.iterative_splat?"disabled":"available"})),[u,Ht.iterative_splat]),ma=u.splat_implementations.find(x=>x.id===p.splat_implementation),F=r?.devices.find(x=>x.id===p.hardware),oe=a1(p,r,F),me=f.find(x=>x.id===p.sample_id),mt=O==="sample"?Be?.analysis:se?.analysis?.image_count?se.analysis:J?.analysis,Je=t1(p,mt,me?.image_count??0),cl=[O,p.sample_id,mt?.image_count??0,mt?.average_megapixels??0,mt?.total_megapixels??0,p.max_resolution,p.config_name,p.splat_implementation,p.run_mvs].join(":"),kt=wa.map(x=>({...x,label:x.id===Je?.gpu.id?`${x.label} · Recommended`:x.label})),pl=[{id:"modal",label:"Modal"},{id:"lambda",label:"Lambda Cloud — Coming Soon!",status:"coming-soon"},{id:"runpod",label:"RunPod — Coming Soon!",status:"coming-soon"},{id:"vast",label:"Vast.ai — Coming Soon!",status:"coming-soon"},{id:"aws",label:"AWS EC2 — Coming Soon!",status:"coming-soon"}],ha=x=>{const fe=wa.find(Ve=>Ve.id===x),pe={configuration:u,verified:!1,hardware:{summary:`Modal ${x} workspace`,devices:[{id:"cuda:0",kind:"cuda",label:`Modal ${x}`,details:"NVIDIA CUDA GPU · starts with the first reconstruction",memory:fe?`${fe.memoryGiB} GB`:void 0,supports_gaussian_splatting:!0}]}};return k(pe),P("remote_hardware","cuda:0"),pe};g.useEffect(()=>{Je&&p.modal_gpu!==Je.gpu.id&&(P("modal_gpu",Je.gpu.id),p.remote_endpoint&&(k(null),ce(!0),w("The dataset changed the recommended VM. Update the Modal workspace to apply it, then verify readiness.")))},[Je?.gpu.id,cl,p.modal_gpu,p.remote_endpoint]),g.useEffect(()=>{M(x=>({...x,num_workers:oe.workers,threads_per_worker:oe.threadsPerWorker,worker_memory_limit:`${oe.memoryPerWorkerGiB}GB`}))},[oe.key]),g.useEffect(()=>{!me||Be?.path!==""||il(p.execution_target==="remote"?"Will download directly on Modal":me.prepared?"Cached and ready":"Will download when the run starts")},[p.execution_target,me,Be?.path]);const Ai=(x,fe)=>{ct.current+=1,K(!1),ee(!1);const pe=P0(fe);if(k(null),ce(!1),w(""),pe){M(Ve=>({...Ve,modal_token_id:pe.tokenId,modal_token_secret:pe.tokenSecret,modal_api_key:""})),$("Token command parsed. Both fields are filled.");return}M(Ve=>({...Ve,[x]:fe,modal_api_key:""})),$("")},zi=x=>{P("modal_gpu",x),k(null),ce(!!p.remote_endpoint),w("VM selection changed. Update the Modal workspace to apply it, then verify readiness.")};g.useEffect(()=>{if(p.execution_target!=="remote"||p.remote_connection!=="api"||p.remote_provider!=="modal"||!p.modal_token_id.startsWith("ak-")||!p.modal_token_secret.startsWith("as-"))return;const x=++ct.current,fe=window.setTimeout(async()=>{K(!0),w("Finding your deployed GTSFM app on Modal…");try{const pe=await Gt("/api/modal/discover",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token_id:p.modal_token_id,token_secret:p.modal_token_secret})});if(x!==ct.current)return;M(Ve=>Ve.remote_endpoint&&Ve.remote_endpoint!==ul.current?{...Ve,modal_api_key:pe.api_key}:{...Ve,remote_endpoint:pe.endpoint,modal_api_key:pe.api_key}),ul.current=pe.endpoint,ha(p.modal_gpu),ce(!1),w(`Found ${pe.app_name} · ${pe.function_name}. Update it to this GTSFM version, or verify the existing workspace.`)}catch(pe){x===ct.current&&(ce(!0),w(wl(pe)))}finally{x===ct.current&&K(!1)}},450);return()=>window.clearTimeout(fe)},[p.execution_target,p.remote_connection,p.remote_provider,p.modal_token_id,p.modal_token_secret]),g.useEffect(()=>{p.splat_implementation==="gsplat"&&hl&&!Ht.iterative_splat&&P("splat_implementation","none")},[p.splat_implementation,hl,Ht.iterative_splat]);async function Bl(x,fe){const pe=await Gt("/api/remote/inspect",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({endpoint:x,api_key:fe,remote_provider:p.remote_provider})});k({...pe,verified:!0});const Ve=pe.hardware.devices.find(Ni=>Ni.supports_gaussian_splatting);return P("remote_hardware",Ve?.id??pe.hardware.devices[0]?.id??""),pe}const gt=async()=>{if(p.remote_connection!=="api"){w("SSH connection testing is coming soon. You can finish the VM details now.");return}if(!p.remote_endpoint||!Mo(p)){w("Deploy the GTSFM Modal workspace first, or wait for an existing deployment to be discovered.");return}ee(!0),ce(!1),k(x=>x?{...x,verified:!1}:null),w("Checking the lightweight Modal control service…");try{const x=await Bl(p.remote_endpoint,Mo(p));ce(!1),w(`${x.hardware.summary}. The control service is ready; the GPU stays off until you run a reconstruction.`)}catch(x){ce(!0),w(`Workspace check failed. Update the Modal workspace before running. ${wl(x)}`)}finally{ee(!1)}},sl=async()=>{if(!p.modal_token_id.startsWith("ak-")||!p.modal_token_secret.startsWith("as-")){w("Enter both Modal token fields before deploying.");return}ct.current+=1,Ce(!0),ce(!1),k(null),w("");try{let x=await Gt("/api/modal/deploy",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token_id:p.modal_token_id,token_secret:p.modal_token_secret,gpu:p.modal_gpu,cpu:Math.max(1,Number(p.num_workers)*Number(p.threads_per_worker)||1),memory_mb:Math.max(4096,Math.round(lr(p.worker_memory_limit)*Math.max(1,Number(p.num_workers)||1)*1024))})});for(Ye(x);["queued","running","cancelling"].includes(x.status);)await new Promise(fe=>window.setTimeout(fe,1e3)),x=await Gt(`/api/modal/deploy/${encodeURIComponent(x.id)}`),Ye(x);if(x.status==="cancelled"){w("Modal workspace setup stopped.");return}if(x.status==="failed")throw new Error(x.error||"Modal deployment failed");ul.current=x.endpoint,M(fe=>({...fe,remote_endpoint:x.endpoint,modal_api_key:x.api_key})),ha(x.gpu),Ye({...x,status:"running",phase:"verifying",stage:"Starting and verifying the Modal workspace",log_tail:[...x.log_tail,`Registered endpoint ${x.endpoint}`,"Checking the CPU control service; the GPU remains off until a run starts…"]}),ee(!0);try{await Bl(x.endpoint,x.api_key)}catch(fe){const pe=`Deployment finished, but the workspace health check failed: ${wl(fe)}`;throw k(Ve=>Ve?{...Ve,verified:!1}:null),ce(!0),Ye({...x,status:"failed",phase:"verifying",stage:"Modal workspace needs an update",error:pe,log_tail:[...x.log_tail,`Registered endpoint ${x.endpoint}`,pe]}),new Error(pe)}finally{ee(!1)}Ye({...x,phase:"ready",stage:"Modal workspace ready",log_tail:[...x.log_tail,`Registered endpoint ${x.endpoint}`,"Workspace health check passed. The Modal GPU is ready."]}),ce(!1),w(`Modal ${x.gpu} workspace passed its health check and is ready to run.`)}catch(x){const fe=wl(x);ce(!0),w(/Request failed \(404\)/.test(fe)?"This GTSFM server was started before Modal deployment support was installed. Stop it with Ctrl-C, run `gtsfm run` again, then click Deploy.":fe)}finally{Ce(!1)}},ht=async()=>{if(!(!Ne||!["queued","running"].includes(Ne.status)))try{const x=await Gt(`/api/modal/deploy/${encodeURIComponent(Ne.id)}/cancel`,{method:"POST"});Ye(x),w("Stopping Modal workspace setup…")}catch(x){w(wl(x))}},Fu=x=>{const fe=f.find(Ve=>Ve.id===x);if(He(null),il(""),!fe){M(Ve=>({...Ve,sample_id:"",dataset_dir:""}));return}const pe=fe.recommendations;V(pe.loader_options??{}),M(Ve=>({...Ve,sample_id:fe.id,dataset_dir:"",images_dir:"",name:fe.id,loader:pe.loader,config_name:pe.config_name,max_resolution:pe.max_resolution??Ve.max_resolution})),He({path:"",sample:fe,analysis:{image_count:fe.image_count,image_bytes:0,total_megapixels:0,average_megapixels:0,max_width:0,max_height:0}}),il(fe.prepared?"Cached and ready":"Will download where the run executes")},Wu=async x=>{x.preventDefault(),_(!0),Q("");try{if(p.execution_target==="remote"&&p.remote_connection==="ssh")throw new Error("SSH execution is not available yet. Choose API to run on Modal.");if(p.execution_target==="remote"&&p.remote_provider==="modal"&&!X?.verified)throw new Error("The Modal workspace must pass its health check before a reconstruction can start.");const fe={...p,api_key:p.execution_target==="remote"?Mo(p):"",loader_options:H,hardware:p.execution_target==="remote"?p.remote_hardware:p.hardware,max_resolution:p.max_resolution?Number(p.max_resolution):null,num_workers:Number(p.num_workers),threads_per_worker:Number(p.threads_per_worker),gs_max_steps:Number(p.gs_max_steps),live_preview_interval:Number(p.live_preview_interval),max_frame_lookahead:p.max_frame_lookahead?Number(p.max_frame_lookahead):null,num_matched:p.num_matched?Number(p.num_matched):null,num_retry_cluster_connection:p.num_retry_cluster_connection?Number(p.num_retry_cluster_connection):null},pe=await Gt("/api/jobs",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(fe)});m(pe),h("activity")}catch(fe){Q(wl(fe))}finally{_(!1)}},Iu=p.execution_target==="remote"&&p.remote_connection==="api"&&p.remote_provider==="modal",pa=X?.verified?"ready":Me||W||ne?"working":xe?"attention":p.remote_endpoint?"found":"idle",Ga=Z||{idle:"Enter Modal credentials, then deploy or discover a workspace.",found:"Choose Update to apply this GTSFM version, or verify the existing deployment.",working:"Preparing the lightweight control service. The GPU starts only when a reconstruction runs.",ready:"Health checks passed. Reconstruction can start.",attention:"Update or verify this workspace before starting a run."}[pa],Ba=Me?Ne?.phase==="verifying"?"Starting & verifying Modal workspace…":"Setting up Modal workspace…":W?"Finding Modal workspace…":ne?"Starting & verifying Modal workspace…":Iu&&!X?.verified?"Prepare Modal workspace first":"Run reconstruction";return c.jsxs("form",{id:"runForm",onSubmit:Wu,children:[c.jsxs("div",{className:"panel-intro",children:[c.jsx("span",{children:"NEW RECONSTRUCTION"}),E?c.jsxs("small",{className:"catalog-sync",children:[c.jsx(tl,{className:"spin",size:10})," Syncing workspace options…"]}):j?c.jsxs("button",{className:"catalog-sync failed",type:"button",onClick:y,children:[c.jsx(Ti,{size:10})," Options offline · Retry"]}):null,c.jsx("p",{children:"Configure the source, pipeline, and compute target."})]}),c.jsxs(Co,{number:"01",title:"Input",subtitle:"Choose the images to reconstruct",children:[c.jsx(Qe,{label:"Run name",value:p.name,onChange:x=>P("name",x),autoComplete:"off"}),c.jsxs("div",{className:"segmented input-source",role:"group","aria-label":"Input source",children:[c.jsxs("button",{type:"button",className:`target-choice ${O==="upload"?"active":""}`,onClick:()=>{Y("upload"),M(x=>({...x,sample_id:"",dataset_dir:J?.path??"",images_dir:se?.path??""}))},children:[c.jsx(_p,{size:13})," Upload your own"]}),c.jsxs("button",{type:"button",className:`target-choice ${O==="sample"?"active":""}`,onClick:()=>{Y("sample"),M(x=>({...x,sample_id:Be?.sample.id??"",dataset_dir:Be?.path??"",images_dir:""}))},children:[c.jsx(vh,{size:13})," GTSFM samples"]})]}),O==="upload"?c.jsxs(c.Fragment,{children:[c.jsx(jh,{label:"Dataset folder",value:J,onError:Q,onUploaded:x=>{ue(x),P("dataset_dir",x?.path??""),x&&p.name==="my-scene"&&P("name",x.name.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"my-scene")}}),c.jsx(jh,{label:"Separate images folder",optional:!0,value:se,onError:Q,onUploaded:x=>{Se(x),P("images_dir",x?.path??"")}})]}):c.jsxs("div",{className:"sample-picker",children:[c.jsx(it,{label:"Sample scene",value:p.sample_id,options:f,empty:o?"Loading GTSFM samples…":"Choose a GTSFM sample…",onChange:Fu,disabled:Tt||o}),p.sample_id&&c.jsxs("div",{className:`sample-card ${Be?"ready":""}`,children:[c.jsx("span",{className:"sample-state",children:Tt?c.jsx(tl,{className:"spin",size:14}):Be?c.jsx(al,{size:14}):c.jsx(vh,{size:14})}),c.jsxs("div",{children:[c.jsx("strong",{children:f.find(x=>x.id===p.sample_id)?.label}),c.jsx("small",{children:f.find(x=>x.id===p.sample_id)?.description}),c.jsxs("span",{children:[ml," · ",f.find(x=>x.id===p.sample_id)?.image_count," images · ",c.jsx("a",{href:f.find(x=>x.id===p.sample_id)?.source_url,target:"_blank",rel:"noreferrer",children:"View on GitHub ↗"})]})]})]}),c.jsx("p",{className:"field-help sample-help",children:"Dataset format, VGGT model, resolution, and available loader settings are applied automatically."})]}),c.jsx(it,{label:"Dataset format",value:p.loader,options:u.loaders,onChange:x=>{P("loader",x),V({})}}),c.jsx(u1,{descriptors:u.loader_options[p.loader]??[],values:H,setValues:V})]}),c.jsxs(Co,{number:"02",title:"Models",subtitle:"VGGT is the default reconstruction model",children:[c.jsx(it,{label:"Reconstruction model",value:p.config_name,options:fa,onChange:x=>P("config_name",x)}),c.jsx(it,{label:"Splat implementation",value:p.splat_implementation,options:da,onChange:x=>P("splat_implementation",x)}),c.jsx("p",{className:"field-help",children:ma?.description}),p.splat_implementation==="gsplat"&&c.jsxs("div",{className:"nested-options",children:[c.jsx(it,{label:"Optimizer preset",value:p.gaussian_splatting_config_name,options:X?.configuration?.gaussian_splatting_models??u.gaussian_splatting_models,onChange:x=>P("gaussian_splatting_config_name",x)}),c.jsxs("div",{className:"form-grid",children:[c.jsx(Qe,{label:"Training steps",type:"number",min:"1",step:"1",value:p.gs_max_steps,onChange:x=>P("gs_max_steps",x)}),c.jsx(Qe,{label:"Preview every",type:"number",min:"10",step:"10",value:p.live_preview_interval,onChange:x=>P("live_preview_interval",x)})]})]}),c.jsx(Mh,{id:"runMvs",checked:p.run_mvs,disabled:!Ht.mvs,onCheckedChange:x=>P("run_mvs",x),children:"Also run dense MVS"})]}),c.jsxs(Co,{number:"03",title:"Compute",subtitle:"Run here or on a remote VM",children:[c.jsxs("div",{className:"segmented",id:"computeTarget",role:"group","aria-label":"Execution target",children:[c.jsxs("button",{type:"button",className:`target-choice ${p.execution_target==="local"?"active":""}`,onClick:()=>P("execution_target","local"),children:[c.jsx(V0,{size:13})," This machine"]}),c.jsxs("button",{type:"button",className:`target-choice ${p.execution_target==="remote"?"active":""}`,onClick:()=>M(x=>({...x,execution_target:"remote",splat_implementation:x.splat_implementation==="none"?u.defaults.splat_implementation:x.splat_implementation})),children:[c.jsx(Qu,{size:13})," Remote VM"]})]}),p.execution_target==="local"?c.jsx(c.Fragment,{children:r?c.jsxs(c.Fragment,{children:[c.jsx(it,{label:"Hardware",value:p.hardware,options:r.devices,onChange:x=>P("hardware",x)}),c.jsx(c1,{device:F})]}):c.jsxs("div",{className:"hardware-card detecting",children:[c.jsx(tl,{className:"spin",size:13}),c.jsxs("div",{children:[c.jsx("strong",{children:"Detecting compute devices…"}),c.jsx("small",{children:"You can configure the rest of the run while this finishes."})]})]})}):c.jsxs("div",{className:"nested-options remote-vm-options",children:[c.jsx(it,{label:"Connection method",value:p.remote_connection,options:[{id:"api",label:"API"},{id:"ssh",label:"SSH"}],onChange:x=>{P("remote_connection",x),k(null),w("")}}),p.remote_connection==="api"?c.jsxs(c.Fragment,{children:[c.jsx(it,{label:"Service",value:p.remote_provider,options:pl,onChange:x=>{P("remote_provider",x),k(null)}}),p.remote_provider==="modal"&&c.jsxs("div",{className:"provider-panel",children:[c.jsxs("div",{className:"provider-heading",children:[c.jsx("span",{className:"provider-mark",children:"M"}),c.jsxs("div",{children:[c.jsx("strong",{children:"Modal"}),c.jsx("small",{children:"Connect with your Modal account token"})]}),c.jsx("span",{className:"provider-status",children:"AVAILABLE"})]}),c.jsx(it,{label:"Modal VM GPU",value:p.modal_gpu,options:kt,onChange:zi}),c.jsx(l1,{recommendation:Je,selectedGpu:p.modal_gpu,onApply:()=>{Je&&zi(Je.gpu.id)}}),c.jsx(n1,{form:p,analysis:mt,fallbackImageCount:me?.image_count??0}),c.jsxs("p",{className:"field-help modal-command-help",children:["Enter the two values separately, or paste the complete ",c.jsx("code",{children:"modal token set --token-id … --token-secret …"})," command into either field."]}),c.jsxs("div",{className:"form-grid",children:[c.jsx(Qe,{label:"Token ID",value:p.modal_token_id,onChange:x=>Ai("modal_token_id",x),autoComplete:"off",spellCheck:!1,placeholder:"ak-…"}),c.jsx(Qe,{label:"Token secret",type:"password",value:p.modal_token_secret,onChange:x=>Ai("modal_token_secret",x),autoComplete:"new-password",spellCheck:!1,placeholder:"as-…"})]}),q&&c.jsxs("div",{className:"credential-success",children:[c.jsx(al,{size:12})," ",q]}),c.jsx(Qe,{label:"GTSFM endpoint",type:"url",value:p.remote_endpoint,onChange:x=>{P("remote_endpoint",x),k(null),ce(!1),w("Endpoint changed. Start and verify this workspace before running.")},placeholder:W?"Discovering your Modal endpoint…":"Filled after credentials are verified"}),c.jsxs("button",{className:"modal-deploy-action full-width",type:"button",onClick:sl,disabled:W||Me||!p.modal_token_id||!p.modal_token_secret,children:[c.jsx(Qu,{size:13})," ",Me?"Setup in progress…":p.remote_endpoint?"Update Modal workspace":"Set up & deploy Modal workspace"]}),Ne&&c.jsx($0,{deployment:Ne,onCancel:ht,onExpand:()=>L(!0)}),Ne&&R&&c.jsx(J0,{deployment:Ne,onCancel:ht,onClose:()=>L(!1)}),p.remote_endpoint&&p.modal_api_key&&c.jsxs("button",{className:"secondary-action full-width",type:"button",onClick:()=>gt(),disabled:W||Me||ne,children:[ne?c.jsx(tl,{className:"spin",size:13}):X?.verified?c.jsx(al,{size:13}):c.jsx(Q0,{size:13})," ",ne?"Starting & checking workspace…":X?.verified?"Modal workspace ready":"Start & verify workspace"]}),c.jsx(F0,{state:pa,detail:Ga}),X&&c.jsx(it,{label:"Remote hardware",value:p.remote_hardware,options:X.hardware.devices,onChange:x=>P("remote_hardware",x)})]})]}):c.jsxs("div",{className:"provider-panel",children:[c.jsxs("div",{className:"provider-heading",children:[c.jsx("span",{className:"provider-mark ssh",children:c.jsx(er,{size:14})}),c.jsxs("div",{children:[c.jsx("strong",{children:"Direct VM"}),c.jsx("small",{children:"Connect to a machine you control"})]}),c.jsx("span",{className:"provider-status soon",children:"COMING SOON!"})]}),c.jsxs("div",{className:"form-grid",children:[c.jsx(Qe,{label:"Host",value:p.ssh_host,onChange:x=>P("ssh_host",x),placeholder:"gpu-box.example.com"}),c.jsx(Qe,{label:"Port",type:"number",min:"1",max:"65535",value:p.ssh_port,onChange:x=>P("ssh_port",x)}),c.jsx(Qe,{label:"Username",value:p.ssh_username,onChange:x=>P("ssh_username",x),autoComplete:"username",placeholder:"ubuntu"}),c.jsx(it,{label:"Authentication",value:p.ssh_authentication,options:[{id:"agent",label:"SSH agent"},{id:"key",label:"Private key"}],onChange:x=>P("ssh_authentication",x)})]}),p.ssh_authentication==="key"&&c.jsx(Qe,{label:"Private key path",value:p.ssh_private_key,onChange:x=>P("ssh_private_key",x),placeholder:"/Users/you/.ssh/id_ed25519"}),c.jsx(Qe,{label:"Remote workspace",value:p.ssh_workspace,onChange:x=>P("ssh_workspace",x),placeholder:"~/gtsfm-workspace"}),c.jsx("p",{className:"field-help",children:"SSH setup is visible now; remote execution and file transfer are the next connector step."})]})]})]}),c.jsxs(Dy,{className:"advanced-options",open:le,onOpenChange:Ee,children:[c.jsxs(wy,{className:"advanced-trigger",children:[c.jsxs("span",{children:[c.jsx(Z0,{size:13}),c.jsxs("span",{className:"advanced-trigger-copy",children:["Advanced settings",c.jsx("small",{children:oe.label})]})]}),c.jsx(vp,{size:14})]}),c.jsxs(Uy,{className:"advanced-content",children:[c.jsxs("div",{className:"machine-profile-summary",children:[c.jsxs("div",{children:[c.jsx("span",{children:"MACHINE PROFILE"}),c.jsx("strong",{children:oe.label})]}),c.jsx("p",{children:oe.description}),c.jsxs("div",{className:"machine-profile-specs",children:[c.jsxs("span",{children:[oe.workers," worker",oe.workers===1?"":"s"]}),c.jsxs("span",{children:[oe.threadsPerWorker," thread",oe.threadsPerWorker===1?"":"s"," / worker"]}),c.jsxs("span",{children:[oe.memoryPerWorkerGiB," GB / worker"]})]})]}),c.jsxs("div",{className:"form-grid",children:[c.jsx(Qe,{label:"Max resolution",type:"number",min:"1",value:p.max_resolution,onChange:x=>P("max_resolution",x),placeholder:"Model default"}),c.jsx(Qe,{label:"Workers",type:"number",min:"1",value:p.num_workers,onChange:x=>P("num_workers",x),disabled:!oe.allowWorkers,title:oe.allowWorkers?void 0:"Fixed for the selected single-GPU machine"}),c.jsx(Qe,{label:"Threads / worker",type:"number",min:"1",value:p.threads_per_worker,onChange:x=>P("threads_per_worker",x),disabled:!oe.allowThreads}),c.jsx(Qe,{label:"Memory / worker",value:p.worker_memory_limit,onChange:x=>P("worker_memory_limit",x),disabled:!oe.allowMemory})]}),!oe.allowWorkers&&c.jsx("p",{className:"advanced-machine-note",children:"Worker count is locked because the selected machine exposes one GPU. Choose a CPU machine to distribute work across multiple workers."}),c.jsx(it,{label:"Graph partitioner",value:p.graph_partitioner,options:u.graph_partitioners,empty:"Model default",onChange:x=>P("graph_partitioner",x)}),c.jsxs("div",{className:"form-grid",children:[c.jsx(it,{label:"Global descriptor",value:p.global_descriptor_config_name,options:u.global_descriptors,empty:"Model default",onChange:x=>P("global_descriptor_config_name",x)}),c.jsx(it,{label:"Image retriever",value:p.retriever_config_name,options:u.retrievers,empty:"Model default",onChange:x=>P("retriever_config_name",x)}),c.jsx(it,{label:"Correspondence",value:p.correspondence_generator_config_name,options:u.correspondence_generators,empty:"Model default",onChange:x=>P("correspondence_generator_config_name",x)}),c.jsx(it,{label:"Verifier",value:p.verifier_config_name,options:u.verifiers,empty:"Model default",onChange:x=>P("verifier_config_name",x)}),c.jsx(Qe,{label:"Frame lookahead",type:"number",min:"0",value:p.max_frame_lookahead,onChange:x=>P("max_frame_lookahead",x),placeholder:"Model default"}),c.jsx(Qe,{label:"Matches / image",type:"number",min:"0",value:p.num_matched,onChange:x=>P("num_matched",x),placeholder:"Model default"})]}),c.jsx(Mh,{id:"shareIntrinsics",checked:p.share_intrinsics,disabled:!Ht.share_intrinsics,onCheckedChange:x=>P("share_intrinsics",x),children:"Share camera intrinsics"}),c.jsxs("div",{className:"form-grid",children:[c.jsx(it,{label:"Log level",value:p.log,options:u.log_levels,onChange:x=>P("log",x)}),c.jsx(Qe,{label:"Dashboard port",value:p.dashboard_port,onChange:x=>P("dashboard_port",x),placeholder:":8787",disabled:!oe.allowLocalRuntime}),c.jsx(Qe,{label:"Input worker",value:p.input_worker,onChange:x=>P("input_worker",x),placeholder:"Optional worker address",disabled:!oe.allowLocalRuntime}),c.jsx(Qe,{label:"Dask temp folder",value:p.dask_tmpdir,onChange:x=>P("dask_tmpdir",x),placeholder:"System default",disabled:!oe.allowLocalRuntime}),c.jsx(Qe,{label:"Cluster config",value:p.cluster_config,onChange:x=>P("cluster_config",x),placeholder:"Optional YAML path",disabled:!oe.allowLocalRuntime}),c.jsx(Qe,{label:"Cluster retries",type:"number",min:"0",value:p.num_retry_cluster_connection,onChange:x=>P("num_retry_cluster_connection",x),placeholder:"3",disabled:!oe.allowLocalRuntime})]}),c.jsx(tr,{label:"Hydra overrides",children:c.jsx("textarea",{rows:4,value:p.advanced_overrides,onChange:x=>P("advanced_overrides",x.target.value)})})]})]}),c.jsx("div",{className:"form-error",role:"alert",children:G}),c.jsxs("button",{className:"primary-action",type:"submit",disabled:je||Tt||Me||W||ne||O==="sample"&&!Be||p.execution_target==="remote"&&(!p.remote_endpoint||!p.modal_api_key||!X?.verified),children:[c.jsx("span",{children:je?"Starting…":Tt?"Preparing sample…":Ba}),je||Tt||Me||W||ne?c.jsx(tl,{className:"spin",size:14}):c.jsx(xp,{size:14,fill:"currentColor"})]})]})}const Cp=u=>({queued:"Queued",running:"Running",completed:"Completed",failed:"Failed",cancelled:"Cancelled"})[u];function Ep({jobId:u,compact:r=!1}){const f=`/api/jobs/${encodeURIComponent(u)}/splat?format=ply`;return c.jsxs("div",{className:`splat-download ${r?"compact":""}`,children:[c.jsx("span",{className:"splat-format-label",children:".PLY"}),c.jsxs("a",{href:f,download:!0,title:"Download PLY splat",children:[c.jsx(Sp,{size:12}),!r&&c.jsx("span",{children:"Download"})]})]})}function o1({jobs:u,activeId:r,onSelect:f,onCancel:o,onRefresh:m}){return c.jsxs("div",{children:[c.jsxs("div",{className:"panel-title",children:[c.jsxs("div",{children:[c.jsx("h3",{children:"Activity"}),c.jsx("p",{children:"Running and recent jobs"})]}),c.jsx("button",{className:"icon-button",title:"Refresh",onClick:m,children:c.jsx(tl,{size:14})})]}),c.jsx("div",{className:"job-list",children:u.length?u.map(h=>c.jsxs("article",{className:`job-card ${h.id===r?"selected":""}`,children:[c.jsxs("div",{className:"job-card-top",children:[c.jsx("strong",{children:h.name}),c.jsx("span",{className:`job-status ${h.status}`,children:Cp(h.status)})]}),c.jsxs("small",{children:[Cn(h.spec.config_name||"GTSFM")," · ",Cn(h.spec.splat_implementation||"no_splats")]}),h.error&&c.jsx("p",{className:"job-error",children:h.error}),c.jsxs("div",{className:"job-actions",children:[c.jsx("button",{className:"text-button",onClick:()=>f(h.id),children:h.has_final_splat?"View splat":["queued","running"].includes(h.status)?"View progress":"View details"}),["queued","running"].includes(h.status)&&c.jsxs("button",{className:"text-button danger",onClick:()=>o(h.id),children:[c.jsx($u,{size:9,fill:"currentColor"})," Stop"]}),h.status==="completed"&&!h.remote&&c.jsx("a",{className:"text-button",href:"/?view=results",children:"View results"}),h.remote?.workspace_url&&c.jsx("a",{className:"text-button",href:h.remote.workspace_url,target:"_blank",rel:"noreferrer",children:"Remote results ↗"})]}),h.has_final_splat&&c.jsx(Ep,{jobId:h.id,compact:!0})]},h.id)):c.jsxs("div",{className:"empty-state",children:[c.jsx(pp,{size:20}),c.jsx("strong",{children:"No runs yet"}),c.jsx("span",{children:"Configure your first reconstruction in New run."})]})})]})}function r1(){return c.jsxs("div",{children:[c.jsx("div",{className:"panel-title",children:c.jsxs("div",{children:[c.jsx("h3",{children:"Reconstructions"}),c.jsx("p",{children:"Open a scene in the 3D viewer"})]})}),c.jsxs("div",{id:"info",className:"info-summary",role:"status",children:[c.jsx("div",{className:"info-pill","data-role":"count",children:"—"}),c.jsxs("div",{className:"info-details",children:[c.jsx("div",{className:"info-title","data-role":"title",children:"Loading reconstructions…"}),c.jsx("div",{className:"info-path","data-role":"path",children:"Checking workspace…"})]})]}),c.jsx("input",{type:"text",id:"filter",placeholder:"Filter scenes…","aria-label":"Filter scenes"}),c.jsx("div",{id:"sceneList"})]})}function f1({job:u,live:r,logsOpen:f,setLogsOpen:o,visible:m,onCancel:h,onClose:S}){const E=g.useRef(null),j=g.useRef(null),[y,p]=g.useState(null),[M,O]=g.useState(!1);g.useEffect(()=>{const q=E.current,$=q?.parentElement;if(!q||!$||typeof ResizeObserver>"u")return;const W=()=>p(ne=>{if(!ne)return null;const ee=$.getBoundingClientRect(),Me=Math.min(ne.width,ee.width),Ce=q.getBoundingClientRect().height;return{left:Math.max(0,Math.min(ee.width-Me,ne.left)),top:Math.max(0,Math.min(ee.height-Ce,ne.top)),width:Me}}),K=new ResizeObserver(W);return K.observe($),()=>K.disconnect()},[]);const Y=q=>{if(q.target.closest("button, a, input, select"))return;const $=E.current,W=$?.parentElement;if(!$||!W||q.button!==0)return;q.preventDefault(),q.currentTarget.setPointerCapture(q.pointerId);const K=$.getBoundingClientRect(),ne=W.getBoundingClientRect(),ee={pointerX:q.clientX,pointerY:q.clientY,left:K.left-ne.left,top:K.top-ne.top,width:K.width,maxLeft:Math.max(0,ne.width-K.width),maxTop:Math.max(0,ne.height-K.height)};j.current=ee,p({left:ee.left,top:ee.top,width:ee.width}),O(!0)},H=q=>{const $=j.current;$&&p({left:Math.max(0,Math.min($.maxLeft,$.left+q.clientX-$.pointerX)),top:Math.max(0,Math.min($.maxTop,$.top+q.clientY-$.pointerY)),width:$.width})},V=q=>{j.current&&(j.current=null,O(!1),q.currentTarget.hasPointerCapture(q.pointerId)&&q.currentTarget.releasePointerCapture(q.pointerId))};if(!u||!m)return null;const X=typeof r?.progress=="number"&&Number.isFinite(r.progress)?r.progress:u.status==="completed"?1:0,k=typeof r?.loss=="number"&&Number.isFinite(r.loss)?`loss ${r.loss.toFixed(4)}`:"",Z=typeof r?.splat_count=="number"&&Number.isFinite(r.splat_count)?`${r.splat_count.toLocaleString()} splats`:"",w=y?{left:y.left,top:y.top,width:y.width,right:"auto",bottom:"auto"}:void 0;return c.jsxs("div",{ref:E,className:`run-status-bar ${M?"is-dragging":""}`,"data-status":u.status,style:w,title:"Drag to move run status",onPointerDown:Y,onPointerMove:H,onPointerUp:V,onPointerCancel:V,children:[c.jsxs("div",{className:"status-copy status-drag-handle",onDoubleClick:()=>p(null),children:[c.jsx("span",{className:"status-dot"}),c.jsxs("div",{children:[c.jsxs("strong",{children:[u.name," · ",Cp(u.status)]}),c.jsx("small",{children:u.error||(r?.stage==="gaussian_splatting"?"Optimizing Gaussian splats":"Running reconstruction pipeline")})]})]}),c.jsxs("div",{className:"status-metrics",children:[c.jsx("span",{children:r?.max_steps?`${Number(r.step).toLocaleString()} / ${Number(r.max_steps).toLocaleString()} steps`:""}),c.jsx("span",{children:k}),c.jsx("span",{children:Z})]}),c.jsxs("div",{className:"status-actions",children:[u.has_final_splat&&c.jsx(Ep,{jobId:u.id}),["queued","running"].includes(u.status)&&c.jsxs("button",{className:"secondary-action stop-process",type:"button",onClick:()=>h(u.id),children:[c.jsx($u,{size:10,fill:"currentColor"})," Stop"]}),c.jsxs("button",{className:"secondary-action",onClick:()=>o(!f),children:[c.jsx(er,{size:13})," Logs"]}),c.jsx("button",{className:"status-close",type:"button",title:"Close run status","aria-label":"Close run status",onClick:S,children:c.jsx(Da,{size:15})})]}),c.jsx(Vy,{className:"run-progress-track",value:X*100,children:c.jsx(Xy,{className:"run-progress-fill",style:{transform:`translateX(-${100-X*100}%)`}})})]})}function d1({open:u,lines:r,onClose:f}){const o=g.useRef(null),m=g.useRef(null),[h,S]=g.useState(null),[E,j]=g.useState(!1),y=async()=>{await jp(r.join(` +`))&&(j(!0),m.current!==null&&window.clearTimeout(m.current),m.current=window.setTimeout(()=>j(!1),1e3))};g.useEffect(()=>()=>{m.current!==null&&window.clearTimeout(m.current)},[]);const p=H=>{if(H.target.closest("button"))return;const V=o.current,X=V?.parentElement;if(!V||!X)return;H.preventDefault(),H.currentTarget.setPointerCapture(H.pointerId);const k=V.getBoundingClientRect(),Z=X.getBoundingClientRect(),w={pointerX:H.clientX,pointerY:H.clientY,left:k.left-Z.left,top:k.top-Z.top,width:k.width,height:k.height,maxLeft:Z.width-k.width,maxTop:Z.height-k.height};S({left:w.left,top:w.top,width:w.width,height:w.height});const q=W=>S({left:Math.max(0,Math.min(w.maxLeft,w.left+W.clientX-w.pointerX)),top:Math.max(0,Math.min(w.maxTop,w.top+W.clientY-w.pointerY)),width:w.width,height:w.height}),$=()=>{window.removeEventListener("pointermove",q),window.removeEventListener("pointerup",$),window.removeEventListener("pointercancel",$)};window.addEventListener("pointermove",q),window.addEventListener("pointerup",$,{once:!0}),window.addEventListener("pointercancel",$,{once:!0})},M=H=>V=>{const X=o.current,k=X?.parentElement;if(!X||!k)return;V.preventDefault(),V.stopPropagation(),V.currentTarget.setPointerCapture(V.pointerId);const Z=X.getBoundingClientRect(),w=k.getBoundingClientRect(),q={pointerX:V.clientX,pointerY:V.clientY,left:Z.left-w.left,top:Z.top-w.top,right:Z.right-w.left,bottom:Z.bottom-w.top,containerWidth:w.width,containerHeight:w.height};S({left:q.left,top:q.top,width:Z.width,height:Z.height});const $=K=>{const ne=K.clientX-q.pointerX,ee=K.clientY-q.pointerY,Me=H.includes("w")?Math.max(0,Math.min(q.right-300,q.left+ne)):q.left,Ce=H.includes("e")?Math.min(q.containerWidth,Math.max(q.left+300,q.right+ne)):q.right,xe=H.includes("n")?Math.max(0,Math.min(q.bottom-150,q.top+ee)):q.top,ce=H.includes("s")?Math.min(q.containerHeight,Math.max(q.top+150,q.bottom+ee)):q.bottom;S({left:Me,top:xe,width:Ce-Me,height:ce-xe})},W=()=>{window.removeEventListener("pointermove",$),window.removeEventListener("pointerup",W),window.removeEventListener("pointercancel",W)};window.addEventListener("pointermove",$),window.addEventListener("pointerup",W,{once:!0}),window.addEventListener("pointercancel",W,{once:!0})};if(!u)return null;const O=h?Math.max(8,Math.min(16,9+(h.width-420)/140+(h.height-240)/120)):9,Y=h?{left:h.left,top:h.top,width:h.width,height:h.height,right:"auto",bottom:"auto","--log-font-size":`${O}px`}:void 0;return c.jsxs("div",{ref:o,className:"log-drawer",role:"dialog","aria-label":"Run logs",style:Y,children:[["nw","ne","sw","se"].map(H=>c.jsx("button",{className:`log-resize-handle ${H}`,type:"button",title:"Resize logs","aria-label":`Resize logs from ${H}`,onPointerDown:M(H)},H)),c.jsxs("div",{className:"log-header",onPointerDown:p,children:[c.jsxs("strong",{children:[c.jsx(er,{size:12})," Run logs"]}),c.jsxs("div",{className:"log-header-actions",children:[c.jsxs("button",{className:"log-copy",type:"button",title:"Copy all logs","aria-label":"Copy all logs",onClick:y,children:[E?c.jsx(al,{size:12}):c.jsx(bp,{size:12}),c.jsx("span",{children:E?"Copied!":"Copy"})]}),c.jsx("button",{type:"button",title:"Minimize logs","aria-label":"Minimize logs",onClick:f,children:c.jsx(wo,{size:15})}),c.jsx("button",{type:"button",title:"Close logs","aria-label":"Close logs",onClick:f,children:c.jsx(Da,{size:14})})]})]}),c.jsx("pre",{id:"runLogs",children:r.join(` +`)})]})}function m1({setup:u,refreshing:r,onRefresh:f,onSetupChange:o,hasActiveJob:m}){const[h,S]=g.useState(!1),[E,j]=g.useState(!1),[y,p]=g.useState(null),[M,O]=g.useState({}),Y=m?"with-active-job":"",H=async k=>{if(!(!k.action?.enabled||y)){p(k.id),O(Z=>({...Z,[k.id]:""}));try{const Z=await Gt(`/api/setup/${encodeURIComponent(k.id)}/install`,{method:"POST"});o(Z.setup)}catch(Z){O(w=>({...w,[k.id]:wl(Z)}))}finally{p(null)}}};if(E)return c.jsx("button",{className:`setup-reopen ${Y}`,type:"button",title:"Show setup checks","aria-label":"Show setup checks",onClick:()=>j(!1),children:c.jsx(K0,{size:15})});const V=u?.status??"warning",X=u?.counts.optional??0;return c.jsxs("section",{className:`setup-panel ${h?"collapsed":""} ${Y}`,"aria-label":"Setup checks","aria-live":"polite",children:[c.jsxs("header",{className:"setup-panel-header",children:[c.jsx("span",{className:`setup-overall-icon ${V}`,"aria-hidden":"true",children:V==="ready"?c.jsx(Y0,{size:16}):c.jsx(Ti,{size:16})}),c.jsxs("div",{className:"setup-panel-copy",children:[c.jsx("span",{children:"SETUP CHECKS"}),c.jsx("strong",{children:u?.summary??"Checking environment…"})]}),c.jsxs("div",{className:"setup-panel-actions",children:[c.jsx("button",{type:"button",title:"Refresh checks","aria-label":"Refresh setup checks",onClick:f,disabled:r,children:c.jsx(tl,{className:r?"spin":"",size:13})}),c.jsx("button",{type:"button",title:h?"Expand checks":"Collapse checks","aria-label":h?"Expand setup checks":"Collapse setup checks",onClick:()=>S(k=>!k),children:h?c.jsx(vp,{size:14}):c.jsx(L0,{size:14})}),c.jsx("button",{type:"button",title:"Close checks","aria-label":"Close setup checks",onClick:()=>j(!0),children:c.jsx(Da,{size:14})})]})]}),!h&&c.jsx("div",{className:"setup-panel-body",children:u?c.jsxs(c.Fragment,{children:[c.jsxs("div",{className:"setup-summary-line",children:[c.jsxs("span",{children:[u.counts.ready," passed"]}),X>0&&c.jsxs("span",{children:[X," optional unavailable"]})]}),c.jsx("ul",{children:u.items.map(k=>c.jsxs("li",{"data-state":k.state,children:[c.jsx("span",{className:"setup-check-mark","aria-hidden":"true",children:k.state==="ready"?c.jsx(al,{size:12}):k.state==="error"?c.jsx(Da,{size:12}):c.jsx("span",{})}),c.jsxs("div",{className:"setup-check-content",children:[c.jsxs("div",{className:"setup-check-title",children:[c.jsx("strong",{children:k.label}),c.jsxs("span",{className:"setup-check-tools",children:[!k.required&&c.jsx("em",{children:"optional"}),k.action&&c.jsxs("button",{className:"setup-install",type:"button",disabled:!k.action.enabled||!!y,title:k.action.reason||k.action.label,onClick:()=>H(k),children:[y===k.id?c.jsx(tl,{className:"spin",size:9}):k.action.enabled?c.jsx(Sp,{size:9}):null,c.jsx("span",{children:y===k.id?"Working…":k.action.label})]})]})]}),c.jsx("small",{className:M[k.id]?"setup-action-error":void 0,children:M[k.id]||k.detail})]})]},k.id))})]}):c.jsxs("div",{className:"setup-loading",children:[c.jsx(tl,{className:"spin",size:13})," Inspecting this machine…"]})})]})}function h1({job:u,live:r}){const f=r?.dask,o=f?.memory_limit_bytes?Math.min(1,f.memory_bytes/f.memory_limit_bytes):0,m=r?.stage==="gaussian_splatting"?"Optimizing splats":u.status==="queued"?"Waiting to start":"Reconstructing scene";return c.jsxs("section",{className:"dask-stats","aria-label":"Live Dask status",children:[c.jsxs("div",{className:"dask-stats-heading",children:[c.jsxs("div",{children:[c.jsx("span",{children:"DASK LIVE"}),c.jsx("strong",{children:m})]}),f?.dashboard_url&&c.jsx("a",{href:f.dashboard_url,target:"_blank",rel:"noreferrer",children:"Open dashboard ↗"})]}),f?c.jsxs(c.Fragment,{children:[c.jsxs("div",{className:"dask-stat-grid",children:[c.jsxs("div",{children:[c.jsx("span",{children:"Workers"}),c.jsx("strong",{children:f.workers}),c.jsxs("small",{children:[f.threads," threads"]})]}),c.jsxs("div",{children:[c.jsx("span",{children:"Running"}),c.jsx("strong",{children:f.running_tasks}),c.jsxs("small",{children:[f.pending_tasks," pending"]})]}),c.jsxs("div",{children:[c.jsx("span",{children:"Finished"}),c.jsx("strong",{children:f.completed_tasks}),c.jsx("small",{children:f.failed_tasks?`${f.failed_tasks} failed`:"no errors"})]}),c.jsxs("div",{children:[c.jsx("span",{children:"CPU"}),c.jsxs("strong",{children:[Math.round(f.cpu_percent),"%"]}),c.jsx("small",{children:"across workers"})]})]}),c.jsxs("div",{className:"dask-memory",children:[c.jsxs("div",{children:[c.jsx("span",{children:"Memory"}),c.jsxs("strong",{children:[ji(f.memory_bytes)," / ",ji(f.memory_limit_bytes)]})]}),c.jsx("div",{className:"dask-memory-track",children:c.jsx("span",{style:{width:`${o*100}%`}})})]})]}):c.jsxs("div",{className:"dask-stats-waiting",children:[c.jsx("span",{className:"dask-pulse"})," Starting workers…"]})]})}function p1(u,r){if(r?.stage==="gaussian_splatting"){const o=Number(r.step||0),m=Number(r.max_steps||0);return m>0?`GTSFM: Optimizing Gaussian splats · ${o.toLocaleString()} / ${m.toLocaleString()} steps`:"GTSFM: Initializing Gaussian optimization…"}return r?.message?r.message:u.status==="queued"?u.remote?"Waiting for the Modal GPU worker…":"Waiting for the reconstruction worker…":[...u.log_tail||[]].reverse().find(o=>/GTSFM|partition|VGGT|Gaussian|splat/i.test(o))?.replace(/^.*?\b(?:DEBUG|INFO|WARNING|ERROR|CRITICAL):\s*/,"")||"GTSFM: Preparing the reconstruction pipeline…"}function v1({activeJob:u,live:r,logsOpen:f,setLogsOpen:o,statusBarOpen:m,setStatusBarOpen:h,onCancelJob:S,setup:E,setupRefreshing:j,onRefreshSetup:y,onSetupChange:p}){const M=()=>{h(!1),o(!1)},O=!!(u&&["queued","running"].includes(u.status)),Y=!!(u&&(u.spec.splat_implementation||"none")!=="none"),H=!!(r?.preview_url||r?.final_url||u?.has_final_splat),V=!!(u&&Y&&["queued","running"].includes(u.status)&&!H);return c.jsxs("main",{id:"main-content",children:[c.jsx(f1,{job:u,live:r,logsOpen:f,setLogsOpen:o,visible:m,onCancel:S,onClose:M}),c.jsx(m1,{setup:E,refreshing:j,onRefresh:y,onSetupChange:p,hasActiveJob:!!(u&&m)}),c.jsxs("div",{id:"sceneStats",className:O?"dask-active":void 0,children:[c.jsxs("div",{className:"stat-group","data-mode":"scene",children:[c.jsxs("div",{className:"stat-pair",children:[c.jsx("span",{className:"label",children:"Cameras"}),c.jsx("span",{className:"value",id:"statCameras",children:"0"})]}),c.jsxs("div",{className:"stat-pair",children:[c.jsx("span",{className:"label",children:"Points"}),c.jsx("span",{className:"value",id:"statPoints",children:"0"})]}),c.jsxs("div",{className:"stat-wide",children:[c.jsx("span",{className:"label",children:"Image"}),c.jsx("span",{className:"value",id:"statImageName",children:"—"})]})]}),c.jsx("div",{className:"stat-group","data-mode":"splat",children:c.jsxs("div",{className:"stat-pair",children:[c.jsx("span",{className:"label",children:"Splats"}),c.jsx("span",{className:"value",id:"statSplats",children:"0"})]})}),O&&u&&c.jsx(h1,{job:u,live:r})]}),c.jsx("canvas",{id:"renderCanvas"}),c.jsxs("div",{id:"hud",children:[c.jsxs("label",{className:"background-control",children:["BG ",c.jsxs("select",{id:"backgroundSelect",defaultValue:"dark","aria-label":"Viewer background",children:[c.jsx("option",{value:"dark",children:"Dark"}),c.jsx("option",{value:"graphite",children:"Graphite"}),c.jsx("option",{value:"light-gray",children:"Light gray"}),c.jsx("option",{value:"white",children:"White"})]})]}),c.jsx("button",{id:"prevCamBtn",className:"hud-scene-only",title:"Previous camera",children:c.jsx(gp,{size:14})}),c.jsx("button",{id:"nextCamBtn",className:"hud-scene-only",title:"Next camera",children:c.jsx(yp,{size:14})}),c.jsx("button",{id:"toggleStats",children:"Hide stats"}),c.jsxs("label",{className:"hud-scene-only",children:[c.jsx("input",{type:"checkbox",id:"toggleCams",defaultChecked:!0})," Cameras"]}),c.jsxs("label",{className:"hud-scene-only",children:["Point size ",c.jsx("input",{type:"range",id:"ptSize",min:"1",max:"10",defaultValue:"2"})]}),c.jsx("button",{id:"toggleGround",type:"button","aria-pressed":"true",children:"Hide plane"}),c.jsxs("label",{className:"plane-height-control",children:["Plane Y ",c.jsx("input",{type:"range",id:"groundY",min:"-5",max:"5",step:"0.1",defaultValue:"0","aria-label":"Plane vertical position"}),c.jsx("output",{id:"groundYValue",htmlFor:"groundY",children:"0.0"})]})]}),c.jsx("a",{className:"viewport-github",href:"https://github.com/borglab/gtsfm",target:"_blank",rel:"noreferrer",title:"Open GTSFM on GitHub","aria-label":"Open GTSFM GitHub repository",children:c.jsx(X0,{size:16})}),c.jsx(d1,{open:f,lines:u?.log_tail||[],onClose:()=>o(!1)}),V&&u&&c.jsx("div",{className:"pipeline-wait-overlay",role:"status","aria-live":"polite",children:c.jsxs("div",{className:"pipeline-wait-content",children:[c.jsx("span",{children:"RECONSTRUCTION IN PROGRESS"}),c.jsx("strong",{children:p1(u,r)}),c.jsxs("div",{className:"pipeline-wait-dots","aria-hidden":"true",children:[c.jsx("i",{}),c.jsx("i",{}),c.jsx("i",{})]}),c.jsx("small",{children:"The first live Gaussian preview will appear here automatically."})]})}),c.jsx("div",{id:"loadingOverlay",className:"loading-overlay",role:"status",children:c.jsxs("div",{className:"loading-box",children:[c.jsx("span",{id:"loadingMessage",children:"Loading…"}),c.jsx("div",{className:"loading-progress-track",children:c.jsx("div",{className:"loading-progress-fill",id:"loadingProgress"})})]})})]})}function g1(u){const r=u.devices.filter(S=>!S.status||S.status==="available");if(u.devices.find(S=>S.kind==="mps"))return{title:"Apple Metal (MPS) is not supported",description:"Apple Silicon and MPS can run reconstruction, but GTSFM Gaussian splatting does not currently support this backend. Use a Remote VM with an NVIDIA GPU to generate splats."};const o=u.devices.find(S=>S.kind==="rocm"||/\b(amd|radeon|rocm)\b/i.test(`${S.label} ${S.details}`));if(o)return{title:"AMD ROCm is not supported",description:`${o.label} was detected. AMD ROCm can run reconstruction, but GTSFM Gaussian splatting currently requires NVIDIA CUDA. Use a Remote VM with an NVIDIA GPU to generate splats.`};const m=u.devices.find(S=>S.kind==="nvidia"||S.kind==="cuda"||/\bnvidia\b/i.test(S.label));if(m)return{title:"NVIDIA GPU found, but CUDA is not ready",description:`${m.label} was detected, but this PyTorch environment cannot currently use it for Gaussian splatting. Install a CUDA-enabled PyTorch setup, or use a Remote VM with NVIDIA CUDA.`};const h=r.find(S=>S.kind!=="cpu");return h?{title:`${h.label} is not supported for splats`,description:"This accelerator can still be used where supported for reconstruction, but GTSFM Gaussian splatting currently requires NVIDIA CUDA. Use a compatible Remote VM to generate splats."}:{title:"No supported GPU was detected",description:"This machine can run CPU reconstruction, but GTSFM Gaussian splatting currently requires an NVIDIA CUDA GPU. Use a Remote VM to generate splats."}}function y1({hardware:u,onClose:r,onUseRemote:f}){const o=g1(u);return c.jsxs("section",{className:"hardware-warning",role:"alertdialog","aria-labelledby":"hardware-warning-title","aria-describedby":"hardware-warning-description",children:[c.jsx("div",{className:"hardware-warning-icon","aria-hidden":"true",children:c.jsx(Ti,{size:18})}),c.jsxs("div",{className:"hardware-warning-copy",children:[c.jsx("span",{children:"HARDWARE NOTICE"}),c.jsx("strong",{id:"hardware-warning-title",children:o.title}),c.jsx("p",{id:"hardware-warning-description",children:o.description}),c.jsxs("div",{className:"hardware-warning-actions",children:[c.jsxs("button",{type:"button",className:"warning-primary",onClick:f,children:[c.jsx(Qu,{size:12})," Use Remote VM"]}),c.jsx("button",{type:"button",onClick:r,children:"Continue without splats"})]})]}),c.jsx("button",{className:"hardware-warning-close",type:"button",title:"Dismiss hardware warning","aria-label":"Dismiss hardware warning",onClick:r,children:c.jsx(Da,{size:14})})]})}const Tp="gtsfm-studio-sidebar-width",Uo=320,Ap=760;function _i(u){const r=Math.max(Uo,window.innerWidth-360);return Math.round(Math.min(Ap,r,Math.max(Uo,u)))}function b1(){try{const u=Number(window.localStorage.getItem(Tp));return _i(Number.isFinite(u)&&u>0?u:420)}catch{return 420}}function S1(){const[u,r]=g.useState(!1),[f,o]=g.useState(b1),[m,h]=g.useState(!1),S=g.useRef(null),[E,j]=g.useState(new URLSearchParams(location.search).get("view")==="results"?"results":"run"),[y,p]=g.useState(I0),[M,O]=g.useState(!0),[Y,H]=g.useState(""),[V,X]=g.useState(null),[k,Z]=g.useState(null),[w,q]=g.useState(!1),[$,W]=g.useState([]),[K,ne]=g.useState(!0),[ee,Me]=g.useState([]),[Ce,xe]=g.useState(null),[ce,Ne]=g.useState(null),[Ye,R]=g.useState(!1),[L,le]=g.useState(!0),[Ee,je]=g.useState(!1),[_,G]=g.useState(0),[Q,J]=g.useState(0),ue=g.useRef(null),se=g.useRef(null),Se=g.useCallback(()=>{S.current=null,h(!1),document.body.classList.remove("sidebar-is-resizing")},[]),Be=F=>{u||F.button!==0||(F.preventDefault(),S.current={pointerX:F.clientX,width:f},F.currentTarget.setPointerCapture(F.pointerId),h(!0),document.body.classList.add("sidebar-is-resizing"))},He=F=>{const oe=S.current;oe&&o(_i(oe.width+F.clientX-oe.pointerX))},Tt=F=>{if(F.key==="ArrowLeft"||F.key==="ArrowRight"){F.preventDefault();const oe=F.key==="ArrowRight"?1:-1;o(me=>_i(me+oe*(F.shiftKey?40:10)))}else F.key==="Home"&&(F.preventDefault(),o(420))};g.useEffect(()=>()=>document.body.classList.remove("sidebar-is-resizing"),[]),g.useEffect(()=>{try{window.localStorage.setItem(Tp,String(f))}catch{}},[f]),g.useEffect(()=>{const F=()=>o(oe=>_i(oe));return window.addEventListener("resize",F),()=>window.removeEventListener("resize",F)},[]);const Wt=g.useCallback(async()=>{try{const F=await Gt("/api/jobs");Me(F.items||[]),xe(oe=>oe||F.items?.find(me=>["queued","running"].includes(me.status))?.id||null)}catch(F){console.warn("Unable to refresh jobs",F)}},[]),ml=g.useCallback(async()=>{q(!0);try{Z(await Gt("/api/setup"))}catch(F){console.warn("Unable to inspect setup",F)}finally{q(!1)}},[]),il=g.useCallback(async()=>{O(!0),H("");try{p(await Gt("/api/configuration"))}catch(F){H(wl(F))}finally{O(!1)}},[]),ct=g.useCallback(async()=>{try{X(await Gt("/api/hardware"))}catch(F){console.warn("Unable to inspect hardware",F)}finally{ml()}},[ml]),ul=g.useCallback(async()=>{try{const F=await Gt("/api/samples");W(F.items)}catch(F){console.warn("Unable to load sample catalog",F)}finally{ne(!1)}},[]);g.useEffect(()=>{il(),ct(),ul(),Wt()},[il,ct,ul,Wt]);const P=ee.find(F=>F.id===Ce)??null;g.useEffect(()=>{Ce&&le(!0)},[Ce]),g.useEffect(()=>{let F=null,oe=null,me=!1;const mt=()=>{F=new WebSocket(bh("/api/events/jobs")),F.onmessage=Je=>{const cl=JSON.parse(Je.data);Me(cl.items||[]),xe(kt=>kt||cl.items?.find(pl=>["queued","running"].includes(pl.status))?.id||null)},F.onclose=()=>{me||(oe=window.setTimeout(mt,1e3))}};return mt(),()=>{me=!0,oe!==null&&clearTimeout(oe),F?.close()}},[]),g.useEffect(()=>{if(!P){Ne(null);return}Ne(null);const F=new WebSocket(bh(`/api/events/jobs/${encodeURIComponent(P.id)}`));return F.onmessage=oe=>{const me=JSON.parse(oe.data);Me(mt=>mt.map(Je=>Je.id===me.job.id?me.job:Je)),Ne(me.live)},()=>F.close()},[P?.id]),g.useEffect(()=>{if(!P||!ce)return;const F=P.status==="completed"&&ce.final_url?`${P.id}:${ce.final_url}`:null,oe=ce.preview_url?`${P.id}:${String(ce.preview_version??ce.preview_url)}`:null,me=F?{kind:"final",key:F,url:ce.final_url,label:`${P.name} · final`}:oe?{kind:"preview",key:oe,url:ce.preview_url,label:`${P.name} · live`}:null;if(!me||me.kind==="final"&&se.current===me.key||me.kind==="preview"&&ue.current===me.key)return;let mt=!1,Je=null,cl=0;const kt=async()=>{if(mt)return;const pl=window.gtsfmViewer;if(!pl||pl.isBusy()){Je=window.setTimeout(()=>{kt()},250);return}const ha=await pl.loadSplatsFile({splatsUrl:me.url,label:me.label});if(!mt){if(ha===!1){cl+=1,cl<3&&(Je=window.setTimeout(()=>{kt()},1200));return}me.kind==="final"?se.current=me.key:ue.current=me.key}};return kt(),()=>{mt=!0,Je!==null&&window.clearTimeout(Je)}},[P?.id,P?.status,ce?.final_url,ce?.preview_url,ce?.preview_version,Q]);const fa=async F=>{await fetch(`/api/jobs/${encodeURIComponent(F)}/cancel`,{method:"POST"}),await Wt()},hl=ee.filter(F=>["queued","running"].includes(F.status)).length,Ht=V?.devices.some(F=>F.supports_gaussian_splatting&&(!F.status||F.status==="available"))??!1,da=!!(V&&!Ht&&!Ee),ma=()=>{je(!0),j("run"),G(F=>F+1)};return c.jsxs("div",{className:"app-shell",children:[da&&V&&c.jsx(y1,{hardware:V,onClose:()=>je(!0),onUseRemote:ma}),c.jsxs("aside",{id:"sidebar",className:`${u?"sidebar-collapsed":""} ${m?"sidebar-resizing":""}`,style:{"--sidebar-width":`${f}px`},children:[c.jsx(e1,{collapsed:u,onToggle:()=>r(F=>!F)}),c.jsxs(U0,{className:"workspace-tabs",value:E,onValueChange:j,children:[c.jsxs(G0,{className:"studio-tabs","aria-label":"Workspace sections",children:[c.jsxs(xo,{className:"studio-tab",value:"run",children:[c.jsx(xp,{size:12})," New run"]}),c.jsxs(xo,{className:"studio-tab",value:"activity",children:[c.jsx(pp,{size:12})," Activity ",hl>0&&c.jsx("span",{id:"activeJobCount",children:hl})]}),c.jsxs(xo,{className:"studio-tab",value:"results",children:[c.jsx(q0,{size:12})," Results"]})]}),c.jsx(jo,{className:"studio-panel",value:"run",forceMount:!0,children:c.jsx(s1,{schema:y,hardware:V,samples:$,samplesLoading:K,onStarted:F=>{le(!0),xe(F.id),Wt()},onTabChange:j,remotePromptKey:_,schemaLoading:M,schemaError:Y,onRetrySchema:il})}),c.jsx(jo,{className:"studio-panel",value:"activity",forceMount:!0,children:c.jsx(o1,{jobs:ee,activeId:Ce,onSelect:F=>{le(!0),xe(F),ue.current=null,se.current=null,J(oe=>oe+1)},onCancel:fa,onRefresh:Wt})}),c.jsx(jo,{className:"studio-panel",value:"results",forceMount:!0,children:c.jsx(r1,{})})]}),c.jsx("div",{className:"sidebar-resize-handle",role:"separator","aria-label":"Resize side panel","aria-orientation":"vertical","aria-valuemin":Uo,"aria-valuemax":Ap,"aria-valuenow":f,tabIndex:u?-1:0,title:"Drag to resize side panel",onPointerDown:Be,onPointerMove:He,onPointerUp:Se,onPointerCancel:Se,onDoubleClick:()=>o(_i(420)),onKeyDown:Tt})]}),c.jsx(v1,{activeJob:P,live:ce,logsOpen:Ye,setLogsOpen:R,statusBarOpen:L,setStatusBarOpen:le,onCancelJob:fa,setup:k,setupRefreshing:w,onRefreshSetup:ml,onSetupChange:Z})]})}const zp=document.getElementById("root");if(!zp)throw new Error("GTSFM Studio root element is missing");Bo.flushSync(()=>Pg.createRoot(zp).render(c.jsx(S1,{})));