diff --git a/.agents/skills/building/references/desktop.md b/.agents/skills/building/references/desktop.md index b6084aa898c..be037676100 100644 --- a/.agents/skills/building/references/desktop.md +++ b/.agents/skills/building/references/desktop.md @@ -1,6 +1,6 @@ # Desktop worktrees -There are separate Tauri and GPUI Cargo workspaces and toolchains. Never assume one cache key or one native runtime verifies both. +There are two Cargo workspaces with their own toolchains and lockfiles: the root workspace (`apps/cli` and `crates/*`) and the desktop app's standalone workspace (`apps/desktop-gpui`). Never assume one cache key or one native runtime verifies both. `warm --session --source ` snapshots prepared native dependencies into the Git-common cache, then creates a private copy-on-write clone in the worktree. `--rust` also warms `target/debug` and `apps/desktop-gpui/target/debug`. It excludes profiles, user media, release artifacts, and arbitrary contents of `target`. @@ -16,6 +16,6 @@ Native runtime isolation is separate from build isolation. Cap has single-instan Use `run --native` and `check --native` for expensive Rust compilation as well. This queues native work across sessions instead of launching twenty large builds at once. Complete compile checks before holding the lease with a long-lived native runtime. Source editing and independent web work can continue while a native job waits. -For v1, prefer a dedicated native runner/OS user with synthetic recordings and test credentials. Before any local native launch, explicitly verify its app identifier, data directory, recording library, frontend port, authentication callback, and existing process ownership. Do not launch it against the user's normal Cap profile. Native profile provisioning and parallel local Tauri/GPUI launch are not automated by this helper. +For v1, prefer a dedicated native runner/OS user with synthetic recordings and test credentials. Before any local native launch, explicitly verify its app identifier, data directory, recording library, frontend port, authentication callback, and existing process ownership. Do not launch it against the user's normal Cap profile. Native profile provisioning and parallel local desktop app launches are not automated by this helper. Use the platform's actual Cap CLI to capture native demos. Linux Daytona evidence cannot close macOS ScreenCaptureKit, Windows capture, hardware GPU, microphone/camera, permissions, or updater gates. Retain a platform matrix in the PR and keep it draft when required native verification is missing. diff --git a/.config/hakari.toml b/.config/hakari.toml index 03c9ecf86a0..dd302cb0e26 100644 --- a/.config/hakari.toml +++ b/.config/hakari.toml @@ -18,8 +18,8 @@ resolver = "2" # https://doc.rust-lang.org/rustc/platform-support.html # Every target desktop-release.yml ships. Leaving a target out here leaves its # platform-specific deps (windows-sys, libc, ...) un-unified, so the sidecar -# `cargo build -p cap` and Tauri's `cargo build -p cap-desktop` resolve -# different feature sets and recompile ~500 shared crates in the same job. +# `cargo build -p cap` and the desktop app's build of the same crates resolve +# different feature sets and recompile hundreds of shared crates in one job. platforms = [ "x86_64-unknown-linux-gnu", "x86_64-apple-darwin", @@ -37,11 +37,11 @@ platforms = [ [traversal-excludes] workspace-members = ["cap-muxer", "cap-muxer-protocol", "cap-verify-expect"] -# hakari unifies dev-dependencies as well, so left alone it pins tauri with its -# `test` feature and tokio `test-util` into every release binary and pulls the -# Tauri/WebKit stack into the standalone GPUI workspace. Only crates whose -# feature drift actually cascades through the sidecar and desktop builds stay -# in the hack; everything else keeps its natural per-binary resolution. +# hakari unifies dev-dependencies as well, so left alone it pins tokio +# `test-util` into every release binary and drags dev-only stacks into the +# standalone GPUI workspace. Only crates whose feature drift actually cascades +# through the sidecar and desktop builds stay in the hack; everything else +# keeps its natural per-binary resolution. [final-excludes] third-party = [ { name = "softbuffer" }, @@ -79,8 +79,6 @@ third-party = [ { name = "smallvec" }, { name = "swift-rs" }, { name = "syn" }, - { name = "tauri" }, - { name = "tauri-build" }, { name = "tokio" }, { name = "tokio-util" }, { name = "toml" }, diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4527fba5879..a8aae26f56d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,8 +22,7 @@ jobs: runs-on: blacksmith-8vcpu-ubuntu-2404 outputs: rust: ${{ steps.filter.outputs.rust }} - gpui: ${{ steps.filter.outputs.rust == 'true' || steps.filter.outputs.gpui == 'true' || steps.desktop-resources.outputs.desktop-resources == 'true' }} - tauri-plugins: ${{ steps.filter.outputs.tauri-plugins }} + gpui: ${{ steps.filter.outputs.rust == 'true' || steps.filter.outputs.gpui == 'true' }} gpui-patches: ${{ steps.filter.outputs.gpui-patches }} steps: - name: Checkout @@ -49,10 +48,7 @@ jobs: gpui: - '.gitattributes' - 'apps/desktop-gpui/**' - - 'apps/desktop/src/assets/**' - - 'apps/desktop/src-tauri/src/recording_start_sound.rs' - 'apps/media-server/src/__tests__/fixtures/**' - - 'packages/ui-solid/icons/**' - 'scripts/build-desktop-binaries*' - 'scripts/build-gpui-binary.sh' - 'scripts/build-linux-packages.mjs' @@ -62,33 +58,11 @@ jobs: - 'scripts/finalize-macos-*' - 'scripts/linux-bundle-config*' - 'scripts/prepare-gpui-dependency*' - - 'scripts/run-gpui-build*' - 'scripts/sync-desktop-versions.mjs' - - 'scripts/verify-gpui-release-inputs.mjs' - 'scripts/verify-windows-stack.mjs' gpui-patches: - 'apps/desktop-gpui/patches/**' - 'scripts/prepare-gpui-dependency.sh' - tauri-plugins: - - 'Cargo.lock' - - 'bun.lock' - - 'scripts/check-tauri-plugin-versions*' - - 'apps/desktop/package.json' - - # Cap ships as the GPUI app, which embeds icons, sounds, assets and test - # data from apps/desktop. Only the Tauri app's own sources are skipped. - - name: Check for GPUI resources in apps/desktop - uses: dorny/paths-filter@v3 - id: desktop-resources - with: - predicate-quantifier: every - filters: | - desktop-resources: - - 'apps/desktop/**' - - '!apps/desktop/src/**' - - '!apps/desktop/src-tauri/src/**' - - '!apps/desktop/src-tauri/tests/**' - - '!apps/desktop/src-tauri/gen/**' typecheck: name: Typecheck @@ -106,8 +80,7 @@ jobs: - name: Test workspace tooling run: | - node --test scripts/bun-scripts.test.mjs scripts/check-tauri-plugin-versions.test.mjs - bun run --cwd apps/desktop vitest run scripts/prepare.test.js + node --test scripts/bun-scripts.test.mjs - name: Test Loops profile sync run: | @@ -272,10 +245,8 @@ jobs: shell: bash run: cargo test --locked -p cap-utils -p cap-cli-install --lib - # cap-desktop is the Tauri app, which no longer ships; Cap is the GPUI app - # plus the cap-muxer and cap-cli sidecars built from this workspace. - name: Run Clippy - run: cargo clippy --workspace --exclude cap-desktop --all-features --locked -- -D warnings + run: cargo clippy --workspace --all-features --locked -- -D warnings lint-biome: name: Lint (Biome) @@ -500,18 +471,3 @@ jobs: else cargo +1.95.0 test -p gpui_windows --lib directx_atlas fi - - tauri-plugins: - name: Verify Tauri plugin versions - runs-on: blacksmith-8vcpu-ubuntu-2404 - needs: changes - if: needs.changes.outputs.tauri-plugins == 'true' - steps: - - name: Checkout - uses: actions/checkout@v4 - - - uses: ./.github/actions/setup-js - - - name: Run verify - shell: bash - run: node scripts/check-tauri-plugin-versions.js diff --git a/.github/workflows/desktop-release.yml b/.github/workflows/desktop-release.yml index f4c6d54a14a..7b93d117f9e 100644 --- a/.github/workflows/desktop-release.yml +++ b/.github/workflows/desktop-release.yml @@ -116,7 +116,7 @@ jobs: releasePublished = !release.draft; if (releasePublished) - throw new Error(`Release '${tag}' is already published: ${releaseUrl}. Bump apps/desktop/src-tauri/Cargo.toml before publishing a new build.`); + throw new Error(`Release '${tag}' is already published: ${releaseUrl}. Bump apps/desktop-gpui/Cargo.toml before publishing a new build.`); else core.notice(`Draft release '${tag}' already exists. Continuing build and upload.`); } @@ -287,20 +287,25 @@ jobs: shell: bash env: BUILD_VERSION: ${{ inputs.version }} + # promote-nightly can rebuild a commit from before the Tauri app was + # removed, where apps/desktop/src-tauri/Cargo.toml was the version + # source, so that manifest is stamped too when it exists. run: | node -e ' const fs = require("fs"); - const path = "apps/desktop/src-tauri/Cargo.toml"; const version = process.env.BUILD_VERSION; - let toml = fs.readFileSync(path, "utf8"); - const re = /^version = ".*"$/m; - if (!re.test(toml)) { - console.error("package.version line not found in " + path); - process.exit(1); + const manifests = ["apps/desktop-gpui/Cargo.toml", "apps/desktop/src-tauri/Cargo.toml"]; + for (const path of manifests.filter((path, index) => index === 0 || fs.existsSync(path))) { + let toml = fs.readFileSync(path, "utf8"); + const re = /^version = ".*"$/m; + if (!re.test(toml)) { + console.error("package.version line not found in " + path); + process.exit(1); + } + toml = toml.replace(re, "version = \"" + version + "\""); + fs.writeFileSync(path, toml); + console.log("Stamped " + path + " with " + version); } - toml = toml.replace(re, "version = \"" + version + "\""); - fs.writeFileSync(path, toml); - console.log("Stamped " + path + " with " + version); ' node scripts/sync-desktop-versions.mjs @@ -359,7 +364,7 @@ jobs: free -h # The same link used to exhaust commit on the 16GB Windows runner - # ("rustc-LLVM ERROR: out of memory" while linking cap-desktop), so + # ("rustc-LLVM ERROR: out of memory" while linking the desktop app), so # raise the pagefile on the roomy D: disk, the Windows analog of the # Linux swapfile above. Kept for headroom after the move to thin LTO. - name: Increase pagefile size (Windows) @@ -890,8 +895,12 @@ jobs: - name: Re-sign Windows installer for the updater if: ${{ runner.os == 'Windows' }} shell: bash - working-directory: apps/desktop run: | + # Commits from before the Tauri app was removed (promote-nightly) + # keep the Tauri CLI in apps/desktop. + tauri_dir=apps/desktop-gpui + [[ -f "$tauri_dir/package.json" ]] || tauri_dir=apps/desktop + cd "$tauri_dir" BUNDLE_DIR="../../$CAP_BUNDLE/nsis" for exe in "$BUNDLE_DIR"/*.exe; do echo "Re-signing $(basename "$exe") for the updater..." diff --git a/.github/workflows/promote-nightly.yml b/.github/workflows/promote-nightly.yml index 99e1674eecb..3b056b06032 100644 --- a/.github/workflows/promote-nightly.yml +++ b/.github/workflows/promote-nightly.yml @@ -7,7 +7,7 @@ name: "promote-nightly" # GitHub release, draft CrabNebula release on the default channel, published # manually as usual. # -# After promoting, bump apps/desktop/src-tauri/Cargo.toml on main past the +# After promoting, bump apps/desktop-gpui/Cargo.toml on main past the # promoted version so future nightlies and stable releases version correctly. on: diff --git a/.github/workflows/publish-nightly.yml b/.github/workflows/publish-nightly.yml index e877af3d027..f4c89ba9ce2 100644 --- a/.github/workflows/publish-nightly.yml +++ b/.github/workflows/publish-nightly.yml @@ -58,7 +58,7 @@ jobs: uses: SebRollen/toml-action@v1.0.2 id: read_version with: - file: apps/desktop/src-tauri/Cargo.toml + file: apps/desktop-gpui/Cargo.toml field: "package.version" - name: Compute nightly version diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 77054493473..90c4c4d5b97 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -25,7 +25,7 @@ jobs: uses: SebRollen/toml-action@v1.0.2 id: read_version with: - file: apps/desktop/src-tauri/Cargo.toml + file: apps/desktop-gpui/Cargo.toml field: "package.version" release: diff --git a/AGENTS.md b/AGENTS.md index 716d927eaa3..3d71adc66a3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,7 +6,7 @@ These rules are enforced by CI (`cargo clippy -D warnings`, Biome). Fixing them ### Zero-tolerance rules - **Default to no code comments. Add a comment only after solving a bug or working through a complex issue, and only when it captures non-obvious context that a future investigator or reviewer genuinely needs** — e.g. why the fix looks the way it does, the upstream/platform bug being worked around, a non-obvious invariant or trade-off chosen after investigation, or a link to the PR/issue that explains the decision. Bad cases that remain banned: narrating what the code does, restating types, JSDoc that paraphrases parameter names, "TODO: refactor" or "this should be cleaner" notes, and any comment that just describes the change you are currently making. When in doubt, prefer better naming/types over a comment. Applies to every language: Rust, TS, JS, Python, shell, SQL, TOML, etc. -- **Never hand-edit generated files**: `**/tauri.ts`, `apps/desktop/src-tauri/gen/**`, `packages/ui-solid/src/auto-imports.d.ts`, Drizzle migration SQL under `packages/database/migrations/`. These are regenerated (e.g. `tauri.ts` only on debug desktop runs) but stay committed because CI typecheck and fresh clones depend on them; commit binding changes alongside the Rust change that produced them. For database schema changes, run `bun run db:generate` and commit the generated SQL, snapshot, and journal changes alongside the schema change. Generating and committing these artifacts is required; modifying generated output by hand is prohibited. Note: `apps/desktop/src/utils/queries.ts` is hand-written, not generated — edit it normally. +- **Never hand-edit generated files**: Drizzle migration SQL under `packages/database/migrations/` and the hakari-managed section of `crates/workspace-hack/Cargo.toml`. These stay committed because CI and fresh clones depend on them. For database schema changes, run `bun run db:generate` and commit the generated SQL, snapshot, and journal changes alongside the schema change. Generating and committing these artifacts is required; modifying generated output by hand is prohibited. - **Never start additional dev servers** (`bun run dev`, `bun run dev:web`, `bun run dev:desktop`, Docker services). Assume they are already running. The `/building` workflow may start a session-owned web server in its isolated worktree on an allocated port through its environment wrapper, or services inside its owned sandbox. This exception does not permit restarting shared services or launching a native app against the user's existing profile. ### Post-edit checks (run before you say "done") @@ -41,7 +41,7 @@ Additionally, `unused_must_use = "deny"` applies to all Rust code: every `Result - **Quotes: double.** `"foo"`, never `'foo'`, for JS/TS string literals. - **`organizeImports: on`** — imports are sorted/grouped automatically; don't leave unused imports or hand-sort against the grain. - **Recommended lint ruleset is on**, with `suspicious.noShadowRestrictedNames` disabled. Everything else (unused vars, `noExplicitAny`, dead code, etc.) applies. -- Desktop code under `apps/desktop/**` has a11y rules disabled; they are enforced everywhere else (`apps/web`, `packages/ui`, etc.). +- a11y rules are enforced everywhere (`apps/web`, `packages/ui`, etc.). - CSS overrides: `noUnknownAtRules`, `noUnknownTypeSelector`, `noDescendingSpecificity` are off for `**/*.css`. ### TypeScript — strictness @@ -50,8 +50,8 @@ Additionally, `unused_must_use = "deny"` applies to all Rust code: every `Result ## Project Structure & Modules - Turborepo monorepo: - - `apps/desktop-gpui` (GPUI, ships as Cap), `apps/desktop` (Tauri v2 + SolidStart; last shipped in 0.6.0, kept for the dev harness), `apps/web` (Next.js), `apps/cli` (Rust CLI). - - `packages/*` shared libs (e.g., `database`, `ui`, `ui-solid`, `utils`, `web-*`). + - `apps/desktop-gpui` (the Cap desktop app: native Rust + GPUI, its own Cargo workspace), `apps/web` (Next.js), `apps/cli` (Rust CLI). + - `packages/*` shared libs (e.g., `database`, `ui`, `utils`, `web-*`). - `crates/*` Rust media/recording/rendering/camera crates. - `scripts/*`, `infra/`, and `packages/local-docker/` for tooling and local services. - Marketing and lifecycle emails (copy, Loops journeys and campaigns, the email catalogue and voice guide) and their Loops tooling live in the private repo [CapSoftware/cap-marketing](https://github.com/CapSoftware/cap-marketing). View and edit them there. This repo keeps only the runtime profile sync in `packages/database/loops/` (with its tests and runners in `scripts/loops/`) and the transactional emails in `packages/database/emails/`. @@ -59,7 +59,7 @@ Additionally, `unused_must_use = "deny"` applies to all Rust code: every `Result ## Build, Test, Develop - Install: `bun install`; setup: `bun run env-setup` then `bun run cap-setup`. - Dev: `bun run dev` (web+desktop). Desktop only: `bun run dev:desktop`. Web only: `bun run dev:web` or `cd apps/web && bun run dev`. -- Build: `bun run build` (Turbo). Desktop release: `bun run gpui:build ` (Cap ships as the GPUI app only). +- Build: `bun run build` (Turbo). Desktop release: `bun run gpui:build ` on the target platform. - DB: `bun run db:generate` → `bun run db:push` → `bun run db:studio`. - Docker: `bun run docker:up | docker:stop | docker:clean`. - Quality: `bun run lint`, `bun run format`, `bun run typecheck`. Rust: `cargo build -p `, `cargo test -p `. @@ -67,13 +67,13 @@ Additionally, `unused_must_use = "deny"` applies to all Rust code: every `Result ## Coding Style & Naming - TypeScript / JS / JSON / CSS: **tab indent** and **double-quoted** strings, enforced by Biome (see `biome.json`). Do not configure per-file overrides. - Rust: `rustfmt` default style + the denied clippy lints in the Pre-Generation Invariants above. -- Naming: files kebab‑case (`user-menu.tsx`); React/Solid components PascalCase; hooks `useX`; Rust modules snake_case; crates kebab‑case. -- Runtime: Node 24, Bun 1.4.4, Rust 1.88+, Docker for MySQL/MinIO. +- Naming: files kebab‑case (`user-menu.tsx`); React components PascalCase; hooks `useX`; Rust modules snake_case; crates kebab‑case. +- Runtime: Node 24, Bun 1.4.4, Rust 1.88 for the root workspace (`apps/desktop-gpui` pins its own toolchain), Docker for MySQL/MinIO. (See **Pre-Generation Invariants** at the top of this file for the comments policy and the denied clippy/Biome patterns. Those are the source of truth — do not duplicate or weaken them here.) ## Testing -- TS/JS: Vitest where present (e.g., desktop). Name tests `*.test.ts(x)` near sources. +- TS/JS: Vitest where present (e.g., web). Name tests `*.test.ts(x)` near sources. - Rust: `cargo test` per crate; tests in `src` or `tests`. - Prefer unit tests for logic and light smoke tests for flows; no strict coverage yet. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dc95aa6f77c..8605f39699b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,7 +27,7 @@ There are many ways to contribute to Cap. You can: Before anything else, make sure you have the following installed: - Node Version 24+ -- Rust 1.88.0+ +- Rust via [rustup](https://rustup.rs) (the workspace pins 1.88.0; the desktop app pins its own toolchain, which rustup installs on first build) - Bun 1.4.4 - Docker ([OrbStack](https://orbstack.dev/) recommended) @@ -50,15 +50,24 @@ To run only one of them, use `bun run dev:desktop` or `bun run dev:web` respecti ### `@cap/desktop` (desktop app) -When running `@cap/desktop` from a terminal on macOS, +The desktop app lives in `apps/desktop-gpui`. It is native Rust with a [GPUI](https://www.gpui.rs/) interface, +and [its README](apps/desktop-gpui/README.md) covers how it is built, packaged, and updated. + +`bun run dev:desktop` checks out Cap's patched gpui next to this repository (`../zed-cap`) on first run, +then starts the app. On macOS it rebuilds on save and relaunches the app where you left it (`apps/desktop-gpui/dev.sh`); +on Windows and Linux it builds and runs the app once. The first build takes around ten minutes. + +When running the desktop app from a terminal on macOS, you will need to grant permissions (screen recording, microphone, etc.) to the terminal, not the Cap app. -For example, if you run `bun run dev:desktop` in the macOS `Terminal.app`, -you will need to grant permissions to it instead of `Cap - Development.app`. +For example, if you run `bun run dev:desktop` in the macOS `Terminal.app`, grant the permissions to `Terminal.app`. #### Where are my recordings stored? -You can find your recordings at `~/Library/Application Support/so.cap.desktop.dev/recordings` on macOS, -and `%programfiles%/so.cap.desktop.dev/recordings` on Windows. +Development builds use the same data directory as an installed Cap: +`~/Library/Application Support/so.cap.desktop/recordings` on macOS, +`%APPDATA%\so.cap.desktop\recordings` on Windows, +and `~/.local/share/so.cap.desktop/recordings` on Linux. +Set `CAP_GPUI_APP_DATA_DIR` to keep a development build's recordings and settings separate. ### `@cap/web` (cap.so website) diff --git a/Cargo.lock b/Cargo.lock index 827ec1693a9..9b5243fb43e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -403,30 +403,6 @@ name = "arbitrary" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" -dependencies = [ - "derive_arbitrary", -] - -[[package]] -name = "arboard" -version = "3.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0348a1c054491f4bfe6ab86a7b6ab1e44e45d899005de92f58b3df180b36ddaf" -dependencies = [ - "clipboard-win", - "image 0.25.8", - "log", - "objc2 0.6.2", - "objc2-app-kit 0.3.1", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-foundation 0.3.1", - "parking_lot", - "percent-encoding", - "windows-sys 0.60.2", - "wl-clipboard-rs", - "x11rb", -] [[package]] name = "arg_enum_proc_macro" @@ -476,14 +452,10 @@ dependencies = [ "futures-channel", "futures-util", "rand 0.9.2", - "raw-window-handle", "serde", "serde_repr", "tokio", "url", - "wayland-backend", - "wayland-client", - "wayland-protocols", "zbus", ] @@ -601,28 +573,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "async-stream" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - [[package]] name = "async-task" version = "4.7.1" @@ -640,29 +590,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "atk" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" -dependencies = [ - "atk-sys", - "glib", - "libc", -] - -[[package]] -name = "atk-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps 6.2.2", -] - [[package]] name = "atomic-waker" version = "1.1.2" @@ -705,7 +632,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ "async-trait", - "axum-core 0.4.5", + "axum-core", "base64 0.22.1", "bytes", "futures-util", @@ -715,7 +642,7 @@ dependencies = [ "hyper", "hyper-util", "itoa", - "matchit 0.7.3", + "matchit", "memchr", "mime", "percent-encoding", @@ -728,44 +655,7 @@ dependencies = [ "sha1", "sync_wrapper", "tokio", - "tokio-tungstenite 0.24.0", - "tower", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "axum" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" -dependencies = [ - "axum-core 0.5.6", - "axum-macros", - "base64 0.22.1", - "bytes", - "form_urlencoded", - "futures-util", - "http 1.3.1", - "http-body", - "http-body-util", - "hyper", - "hyper-util", - "itoa", - "matchit 0.8.4", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "serde_core", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", - "sha1", - "sync_wrapper", - "tokio", - "tokio-tungstenite 0.29.0", + "tokio-tungstenite", "tower", "tower-layer", "tower-service", @@ -793,36 +683,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "axum-core" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" -dependencies = [ - "bytes", - "futures-core", - "http 1.3.1", - "http-body", - "http-body-util", - "mime", - "pin-project-lite", - "sync_wrapper", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "axum-macros" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aa268c23bfbbd2c4363b9cd302a4f504fb2a9dfe7e3451d66f35dd392e20aca" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - [[package]] name = "backtrace" version = "0.3.75" @@ -838,12 +698,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "base64" version = "0.21.7" @@ -911,29 +765,6 @@ dependencies = [ "which", ] -[[package]] -name = "bindgen" -version = "0.69.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" -dependencies = [ - "bitflags 2.13.1", - "cexpr", - "clang-sys", - "itertools 0.12.1", - "lazy_static", - "lazycell", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash 1.1.0", - "shlex", - "syn 2.0.106", - "which", -] - [[package]] name = "bindgen" version = "0.70.1" @@ -1184,9 +1015,6 @@ name = "bytes" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" -dependencies = [ - "serde", -] [[package]] name = "bytestring" @@ -1197,31 +1025,6 @@ dependencies = [ "bytes", ] -[[package]] -name = "cairo-rs" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" -dependencies = [ - "bitflags 2.13.1", - "cairo-sys-rs", - "glib", - "libc", - "once_cell", - "thiserror 1.0.69", -] - -[[package]] -name = "cairo-sys-rs" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" -dependencies = [ - "glib-sys", - "libc", - "system-deps 6.2.2", -] - [[package]] name = "calloop" version = "0.13.0" @@ -1277,7 +1080,7 @@ dependencies = [ "cidre", "clap", "clap_complete", - "cpal 0.15.3 (git+https://github.com/CapSoftware/cpal?rev=6013cb5f8bd3)", + "cpal", "dirs 6.0.0", "ffmpeg-next", "flume", @@ -1327,7 +1130,7 @@ dependencies = [ "cap-enc-ffmpeg", "cap-rnnoise", "cidre", - "cpal 0.15.3 (git+https://github.com/CapSoftware/cpal?rev=6013cb5f8bd3)", + "cpal", "ffmpeg-next", "libc", "serde", @@ -1474,7 +1277,7 @@ dependencies = [ name = "cap-cpal-ffmpeg" version = "0.1.0" dependencies = [ - "cpal 0.15.3 (git+https://github.com/CapSoftware/cpal?rev=6013cb5f8bd3)", + "cpal", "ffmpeg-next", "workspace-hack", ] @@ -1513,141 +1316,11 @@ dependencies = [ "workspace-hack", ] -[[package]] -name = "cap-desktop" -version = "0.6.2" -dependencies = [ - "aho-corasick", - "anyhow", - "ashpd", - "async-stream", - "axum 0.8.9", - "base64 0.22.1", - "block2 0.6.1", - "bytemuck", - "bytes", - "cap-audio", - "cap-automation", - "cap-camera", - "cap-camera-effects", - "cap-camera-ffmpeg", - "cap-cli-install", - "cap-editor", - "cap-enc-ffmpeg", - "cap-export", - "cap-fail", - "cap-flags", - "cap-media", - "cap-media-info", - "cap-project", - "cap-recording", - "cap-rendering", - "cap-timestamp", - "cap-utils", - "chrono", - "cidre", - "clipboard-rs", - "cocoa", - "core-foundation 0.10.1", - "core-graphics 0.24.0", - "cpal 0.15.3 (git+https://github.com/CapSoftware/cpal?rev=6013cb5f8bd3)", - "device_query", - "dirs 6.0.0", - "dotenvy_macro", - "ffmpeg-next", - "flume", - "futures", - "futures-intrusive", - "gdkwayland-sys", - "global-hotkey", - "gtk", - "image 0.25.8", - "kameo", - "keyed_priority_queue", - "lazy_static", - "libappindicator", - "log", - "lz4_flex", - "md5", - "nix 0.29.0", - "notify-rust", - "objc", - "objc2 0.6.2", - "objc2-app-kit 0.3.1", - "objc2-foundation 0.3.1", - "opentelemetry", - "opentelemetry-otlp", - "opentelemetry_sdk", - "parakeet-rs", - "png 0.17.16", - "pollster", - "rand 0.8.5", - "regex", - "relative-path", - "reqwest", - "rodio", - "sanitize-filename", - "scap-direct3d", - "scap-screencapturekit", - "scap-targets", - "semver", - "sentry", - "serde", - "serde_json", - "specta", - "specta-typescript", - "swift-rs", - "sysinfo 0.35.2", - "tauri", - "tauri-build", - "tauri-nspanel", - "tauri-plugin-clipboard-manager", - "tauri-plugin-deep-link", - "tauri-plugin-dialog", - "tauri-plugin-fs", - "tauri-plugin-global-shortcut", - "tauri-plugin-http", - "tauri-plugin-notification", - "tauri-plugin-oauth", - "tauri-plugin-opener", - "tauri-plugin-os", - "tauri-plugin-positioner", - "tauri-plugin-process", - "tauri-plugin-sentry", - "tauri-plugin-shell", - "tauri-plugin-single-instance", - "tauri-plugin-store", - "tauri-plugin-updater", - "tauri-plugin-window-state", - "tauri-specta", - "tempfile", - "thiserror 1.0.69", - "tokio", - "tokio-stream", - "tokio-tungstenite 0.24.0", - "tokio-util", - "tracing", - "tracing-appender", - "tracing-futures", - "tracing-opentelemetry", - "tracing-subscriber", - "uuid", - "wayland-sys", - "webview2-com", - "wgpu", - "whisper-rs", - "windows 0.60.0", - "windows-core 0.61.2", - "windows-sys 0.59.0", - "winreg", - "workspace-hack", -] - [[package]] name = "cap-editor" version = "0.1.0" dependencies = [ - "axum 0.7.9", + "axum", "cap-audio", "cap-enc-ffmpeg", "cap-media", @@ -1655,7 +1328,7 @@ dependencies = [ "cap-project", "cap-rendering", "cap-utils", - "cpal 0.15.3 (git+https://github.com/CapSoftware/cpal?rev=6013cb5f8bd3)", + "cpal", "ffmpeg-next", "flume", "futures", @@ -1834,7 +1507,7 @@ dependencies = [ name = "cap-media-info" version = "0.1.0" dependencies = [ - "cpal 0.15.3 (git+https://github.com/CapSoftware/cpal?rev=6013cb5f8bd3)", + "cpal", "ffmpeg-next", "thiserror 1.0.69", "workspace-hack", @@ -1941,7 +1614,7 @@ dependencies = [ "core-foundation 0.10.1", "core-graphics 0.24.0", "coreaudio-rs", - "cpal 0.15.3 (git+https://github.com/CapSoftware/cpal?rev=6013cb5f8bd3)", + "cpal", "device_query", "dhat", "either", @@ -2104,7 +1777,7 @@ dependencies = [ "cidre", "clap", "colored", - "cpal 0.15.3 (git+https://github.com/CapSoftware/cpal?rev=6013cb5f8bd3)", + "cpal", "ffmpeg-next", "flume", "indicatif", @@ -2131,7 +1804,7 @@ name = "cap-timestamp" version = "0.1.0" dependencies = [ "cidre", - "cpal 0.15.3 (git+https://github.com/CapSoftware/cpal?rev=6013cb5f8bd3)", + "cpal", "windows 0.60.0", "workspace-hack", ] @@ -2145,7 +1818,7 @@ dependencies = [ "flume", "futures", "libc", - "nix 0.29.0", + "nix", "serde", "serde_json", "tempfile", @@ -2178,7 +1851,7 @@ dependencies = [ "cap-timestamp", "cap-verify-expect", "cidre", - "cpal 0.15.3 (git+https://github.com/CapSoftware/cpal?rev=6013cb5f8bd3)", + "cpal", "ffmpeg-next", "flume", "futures", @@ -2210,7 +1883,7 @@ dependencies = [ "anyhow", "cap-verify", "cidre", - "cpal 0.15.3 (git+https://github.com/CapSoftware/cpal?rev=6013cb5f8bd3)", + "cpal", "futures", "objc2-foundation 0.3.1", "scap-screencapturekit", @@ -2264,25 +1937,6 @@ dependencies = [ "thiserror 2.0.16", ] -[[package]] -name = "cargo_toml" -version = "0.22.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" -dependencies = [ - "serde", - "toml 0.9.7", -] - -[[package]] -name = "castaway" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" -dependencies = [ - "rustversion", -] - [[package]] name = "cbc" version = "0.1.2" @@ -2356,12 +2010,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" -[[package]] -name = "cfg_aliases" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" - [[package]] name = "cfg_aliases" version = "0.2.1" @@ -2464,7 +2112,7 @@ version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn 2.0.106", @@ -2477,48 +2125,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] -name = "claxon" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bfbf56724aa9eca8afa4fcfadeb479e722935bb2a0900c2d37e0cc477af0688" - -[[package]] -name = "clipboard-rs" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afede46921767868c5c7f8f55202bdd8bec0bab6bc9605174200f45924f93c62" -dependencies = [ - "clipboard-win", - "image 0.25.8", - "objc2 0.6.2", - "objc2-app-kit 0.3.1", - "objc2-foundation 0.3.1", - "windows 0.59.0", - "x11rb", -] - -[[package]] -name = "clipboard-win" -version = "5.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4" -dependencies = [ - "error-code", - "windows-win", -] - -[[package]] -name = "cmake" -version = "0.1.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" -dependencies = [ - "cc", -] - -[[package]] -name = "cocoa" -version = "0.26.1" +name = "cocoa" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad36507aeb7e16159dfe68db81ccc27571c3ccd4b76fb2fb72fc59e7a4b1b64c" dependencies = [ @@ -2587,21 +2195,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "compact_str" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a" -dependencies = [ - "castaway", - "cfg-if", - "itoa", - "rustversion", - "ryu", - "serde", - "static_assertions", -] - [[package]] name = "concurrent-queue" version = "2.5.0" @@ -2624,26 +2217,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "const-random" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" -dependencies = [ - "const-random-macro", -] - -[[package]] -name = "const-random-macro" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" -dependencies = [ - "getrandom 0.2.16", - "once_cell", - "tiny-keccak", -] - [[package]] name = "constant_time_eq" version = "0.4.2" @@ -2875,29 +2448,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "cpal" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779" -dependencies = [ - "alsa", - "core-foundation-sys", - "coreaudio-rs", - "dasp_sample", - "jni 0.21.1", - "js-sys", - "libc", - "mach2", - "ndk 0.8.0", - "ndk-context", - "oboe", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "windows 0.54.0", -] - [[package]] name = "cpal" version = "0.15.3" @@ -2938,30 +2488,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crash-context" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "031ed29858d90cfdf27fe49fae28028a1f20466db97962fa2f4ea34809aeebf3" -dependencies = [ - "cfg-if", - "libc", - "mach2", -] - -[[package]] -name = "crash-handler" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2066907075af649bcb8bcb1b9b986329b243677e6918b2d920aa64b0aac5ace3" -dependencies = [ - "cfg-if", - "crash-context", - "libc", - "mach2", - "parking_lot", -] - [[package]] name = "crc32fast" version = "1.5.0" @@ -3167,15 +2693,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "dary_heap" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06d2e3287df1c007e74221c49ca10a95d557349e54b3a75dc2fb14712c751f04" -dependencies = [ - "serde", -] - [[package]] name = "dasp_sample" version = "0.11.0" @@ -3224,48 +2741,6 @@ dependencies = [ "serde", ] -[[package]] -name = "derive_arbitrary" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "derive_builder" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" -dependencies = [ - "derive_builder_macro", -] - -[[package]] -name = "derive_builder_core" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" -dependencies = [ - "darling 0.20.11", - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "derive_builder_macro" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" -dependencies = [ - "derive_builder_core", - "syn 2.0.106", -] - [[package]] name = "derive_more" version = "0.99.20" @@ -3445,38 +2920,6 @@ dependencies = [ "libloading 0.8.8", ] -[[package]] -name = "dlopen2" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b54f373ccf864bf587a89e880fb7610f8d73f3045f13580948ccbcaff26febff" -dependencies = [ - "dlopen2_derive", - "libc", - "once_cell", - "winapi", -] - -[[package]] -name = "dlopen2_derive" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "788160fb30de9cdd857af31c6a2675904b16ece8fc2737b2c7127ba368c9d0f4" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "dlv-list" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" -dependencies = [ - "const-random", -] - [[package]] name = "document-features" version = "0.2.11" @@ -3486,24 +2929,6 @@ dependencies = [ "litrs", ] -[[package]] -name = "dotenvy" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" - -[[package]] -name = "dotenvy_macro" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0235d912a8c749f4e0c9f18ca253b4c28cfefc1d2518096016d6e3230b6424" -dependencies = [ - "dotenvy", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "downcast-rs" version = "1.2.1" @@ -3603,26 +3028,6 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" -[[package]] -name = "embed-resource" -version = "3.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6d81016d6c977deefb2ef8d8290da019e27cc26167e102185da528e6c0ab38" -dependencies = [ - "cc", - "memchr", - "rustc_version", - "toml 0.9.7", - "vswhom", - "winreg", -] - -[[package]] -name = "embed_plist" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" - [[package]] name = "encode_unicode" version = "1.0.0" @@ -3712,18 +3117,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "error-code" -version = "3.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" - -[[package]] -name = "esaxx-rs" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d817e038c30374a4bcb22f94d0a8a0e216958d4c3dcde369b1439fec4bdda6e6" - [[package]] name = "etagere" version = "0.2.15" @@ -3779,16 +3172,6 @@ dependencies = [ "zune-inflate", ] -[[package]] -name = "eyre" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" -dependencies = [ - "indenter", - "once_cell", -] - [[package]] name = "fastrand" version = "2.3.0" @@ -3857,16 +3240,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "field-offset" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" -dependencies = [ - "memoffset", - "rustc_version", -] - [[package]] name = "filetime" version = "0.2.26" @@ -3897,12 +3270,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - [[package]] name = "flate2" version = "1.1.2" @@ -4047,12 +3414,6 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42da99970737c0150e3c5cd1cdc510735a2511739f5c3aa3c6bfc9f31441488d" -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - [[package]] name = "futf" version = "0.1.5" @@ -4195,170 +3556,71 @@ dependencies = [ ] [[package]] -name = "gdk" -version = "0.18.2" +name = "generic-array" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ - "cairo-rs", - "gdk-pixbuf", - "gdk-sys", - "gio", - "glib", - "libc", - "pango", + "typenum", + "version_check", ] [[package]] -name = "gdk-pixbuf" -version = "0.18.5" +name = "gethostname" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" +checksum = "fc257fdb4038301ce4b9cd1b3b51704509692bb3ff716a410cbd07925d9dae55" dependencies = [ - "gdk-pixbuf-sys", - "gio", - "glib", - "libc", - "once_cell", + "rustix 1.1.2", + "windows-targets 0.52.6", ] [[package]] -name = "gdk-pixbuf-sys" -version = "0.18.0" +name = "getrandom" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", + "cfg-if", "libc", - "system-deps 6.2.2", + "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] -name = "gdk-sys" -version = "0.18.2" +name = "getrandom" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gio-sys", - "glib-sys", - "gobject-sys", + "cfg-if", + "js-sys", "libc", - "pango-sys", - "pkg-config", - "system-deps 6.2.2", + "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] -name = "gdkwayland-sys" -version = "0.18.2" +name = "getrandom" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ - "gdk-sys", - "glib-sys", - "gobject-sys", + "cfg-if", + "js-sys", "libc", - "pkg-config", - "system-deps 6.2.2", + "r-efi", + "wasi 0.14.7+wasi-0.2.4", + "wasm-bindgen", ] [[package]] -name = "gdkx11" -version = "0.18.2" +name = "gif" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3caa00e14351bebbc8183b3c36690327eb77c49abc2268dd4bd36b856db3fbfe" +checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b" dependencies = [ - "gdk", - "gdkx11-sys", - "gio", - "glib", - "libc", - "x11", -] - -[[package]] -name = "gdkx11-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d" -dependencies = [ - "gdk-sys", - "glib-sys", - "libc", - "system-deps 6.2.2", - "x11", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "gethostname" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc257fdb4038301ce4b9cd1b3b51704509692bb3ff716a410cbd07925d9dae55" -dependencies = [ - "rustix 1.1.2", - "windows-targets 0.52.6", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "r-efi", - "wasi 0.14.7+wasi-0.2.4", - "wasm-bindgen", -] - -[[package]] -name = "gif" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b" -dependencies = [ - "color_quant", - "weezl", + "color_quant", + "weezl", ] [[package]] @@ -4406,38 +3668,6 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" -[[package]] -name = "gio" -version = "0.18.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "gio-sys", - "glib", - "libc", - "once_cell", - "pin-project-lite", - "smallvec", - "thiserror 1.0.69", -] - -[[package]] -name = "gio-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps 6.2.2", - "winapi", -] - [[package]] name = "gl_generator" version = "0.14.0" @@ -4449,77 +3679,12 @@ dependencies = [ "xml-rs", ] -[[package]] -name = "glib" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" -dependencies = [ - "bitflags 2.13.1", - "futures-channel", - "futures-core", - "futures-executor", - "futures-task", - "futures-util", - "gio-sys", - "glib-macros", - "glib-sys", - "gobject-sys", - "libc", - "memchr", - "once_cell", - "smallvec", - "thiserror 1.0.69", -] - -[[package]] -name = "glib-macros" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" -dependencies = [ - "heck 0.4.1", - "proc-macro-crate 2.0.2", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "glib-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" -dependencies = [ - "libc", - "system-deps 6.2.2", -] - [[package]] name = "glob" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" -[[package]] -name = "global-hotkey" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9247516746aa8e53411a0db9b62b0e24efbcf6a76e0ba73e5a91b512ddabed7" -dependencies = [ - "crossbeam-channel", - "keyboard-types", - "objc2 0.6.2", - "objc2-app-kit 0.3.1", - "once_cell", - "serde", - "thiserror 2.0.16", - "windows-sys 0.59.0", - "x11rb", - "xkeysym", -] - [[package]] name = "glow" version = "0.16.0" @@ -4554,28 +3719,6 @@ dependencies = [ "wgpu", ] -[[package]] -name = "gobject-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" -dependencies = [ - "glib-sys", - "libc", - "system-deps 6.2.2", -] - -[[package]] -name = "goblin" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47" -dependencies = [ - "log", - "plain", - "scroll", -] - [[package]] name = "gpu-alloc" version = "0.6.0" @@ -4627,58 +3770,6 @@ dependencies = [ "bitflags 2.13.1", ] -[[package]] -name = "gtk" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" -dependencies = [ - "atk", - "cairo-rs", - "field-offset", - "futures-channel", - "gdk", - "gdk-pixbuf", - "gio", - "glib", - "gtk-sys", - "gtk3-macros", - "libc", - "pango", - "pkg-config", -] - -[[package]] -name = "gtk-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" -dependencies = [ - "atk-sys", - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "system-deps 6.2.2", -] - -[[package]] -name = "gtk3-macros" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.106", -] - [[package]] name = "guardian" version = "1.3.0" @@ -4721,12 +3812,6 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - [[package]] name = "hashbrown" version = "0.15.5" @@ -4738,12 +3823,6 @@ dependencies = [ "foldhash", ] -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "heck" version = "0.5.0" @@ -4812,12 +3891,6 @@ dependencies = [ "windows-link 0.1.3", ] -[[package]] -name = "hound" -version = "3.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62adaabb884c94955b19907d60019f4e145d091c75345379e70d1ee696f7854f" - [[package]] name = "html5ever" version = "0.29.1" @@ -4875,12 +3948,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "http-range" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" - [[package]] name = "httparse" version = "1.10.1" @@ -4999,16 +4066,6 @@ dependencies = [ "cc", ] -[[package]] -name = "ico" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc50b891e4acf8fe0e71ef88ec43ad82ee07b3810ad09de10f1d01f072ed4b98" -dependencies = [ - "byteorder", - "png 0.17.16", -] - [[package]] name = "icu_collections" version = "2.0.0" @@ -5223,12 +4280,6 @@ dependencies = [ "quote", ] -[[package]] -name = "indenter" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" - [[package]] name = "indexmap" version = "1.9.3" @@ -5403,44 +4454,12 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" -[[package]] -name = "javascriptcore-rs" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" -dependencies = [ - "bitflags 1.3.2", - "glib", - "javascriptcore-rs-sys", -] - -[[package]] -name = "javascriptcore-rs-sys" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps 6.2.2", -] - [[package]] name = "jni" version = "0.21.1" @@ -5585,33 +4604,13 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3f384b32bf6426ae93a8b37da62c85073b676a31a82a86d608ad86453878de0" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn 2.0.106", "uuid", ] -[[package]] -name = "keyboard-types" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" -dependencies = [ - "bitflags 2.13.1", - "serde", - "unicode-segmentation", -] - -[[package]] -name = "keyed_priority_queue" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee7893dab2e44ae5f9d0173f26ff4aa327c10b01b06a72b52dd9405b628640d" -dependencies = [ - "indexmap 2.11.4", -] - [[package]] name = "keyring" version = "4.1.5" @@ -5713,43 +4712,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" [[package]] -name = "lewton" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "777b48df9aaab155475a83a7df3070395ea1ac6902f5cd062b8f2b028075c030" -dependencies = [ - "byteorder", - "ogg", - "tinyvec", -] - -[[package]] -name = "libappindicator" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" -dependencies = [ - "glib", - "gtk", - "gtk-sys", - "libappindicator-sys", - "log", -] - -[[package]] -name = "libappindicator-sys" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" -dependencies = [ - "gtk-sys", - "libloading 0.7.4", - "once_cell", -] - -[[package]] -name = "libc" -version = "0.2.175" +name = "libc" +version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" @@ -5763,16 +4727,6 @@ dependencies = [ "cc", ] -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if", - "winapi", -] - [[package]] name = "libloading" version = "0.8.8" @@ -5956,15 +4910,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" -[[package]] -name = "lz4_flex" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08ab2867e3eeeca90e844d1940eab391c9dc5228783db2ed999acbc0a9ed375a" -dependencies = [ - "twox-hash", -] - [[package]] name = "lzma-rust2" version = "0.15.7" @@ -5977,18 +4922,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" -[[package]] -name = "mac-notification-sys" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "119c8490084af61b44c9eda9d626475847a186737c0378c85e32d77c33a01cd4" -dependencies = [ - "cc", - "objc2 0.6.2", - "objc2-foundation 0.3.1", - "time", -] - [[package]] name = "mach2" version = "0.4.3" @@ -6008,22 +4941,6 @@ dependencies = [ "core-foundation-sys", ] -[[package]] -name = "macro_rules_attribute" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65049d7923698040cd0b1ddcced9b0eb14dd22c5f86ae59c3740eab64a676520" -dependencies = [ - "macro_rules_attribute-proc_macro", - "paste", -] - -[[package]] -name = "macro_rules_attribute-proc_macro" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670fdfda89751bc4a84ac13eaa63e205cf0fd22b4c9a5fbfa085b63c1f1d3a30" - [[package]] name = "malloc_buf" version = "0.0.6" @@ -6079,12 +4996,6 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" -[[package]] -name = "matchit" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" - [[package]] name = "matrixmultiply" version = "0.3.10" @@ -6105,12 +5016,6 @@ dependencies = [ "rayon", ] -[[package]] -name = "md5" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" - [[package]] name = "memchr" version = "2.7.5" @@ -6181,87 +5086,12 @@ dependencies = [ "unicase", ] -[[package]] -name = "minidump-common" -version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c4d14bcca0fd3ed165a03000480aaa364c6860c34e900cb2dafdf3b95340e77" -dependencies = [ - "bitflags 2.13.1", - "debugid", - "num-derive", - "num-traits", - "range-map", - "scroll", - "smart-default", -] - -[[package]] -name = "minidump-writer" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abcd9c8a1e6e1e9d56ce3627851f39a17ea83e17c96bc510f29d7e43d78a7d" -dependencies = [ - "bitflags 2.13.1", - "byteorder", - "cfg-if", - "crash-context", - "goblin", - "libc", - "log", - "mach2", - "memmap2", - "memoffset", - "minidump-common", - "nix 0.28.0", - "procfs-core", - "scroll", - "tempfile", - "thiserror 1.0.69", -] - -[[package]] -name = "minidumper" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4ebc9d1f8847ec1d078f78b35ed598e0ebefa1f242d5f83cd8d7f03960a7d1" -dependencies = [ - "cfg-if", - "crash-context", - "libc", - "log", - "minidump-writer", - "parking_lot", - "polling", - "scroll", - "thiserror 1.0.69", - "uds", -] - -[[package]] -name = "minidumper-child" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4f23f835dbe67e44ddf884d3802ff549ca5948bf60e9fd70e9a13c96324d1" -dependencies = [ - "crash-handler", - "minidumper", - "thiserror 1.0.69", - "uuid", -] - [[package]] name = "minimal-lexical" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "minisign-verify" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e856fdd13623a2f5f2f54676a4ee49502a96a80ef4a62bcedd23d52427c44d43" - [[package]] name = "miniz_oxide" version = "0.8.9" @@ -6302,28 +5132,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "monostate" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3341a273f6c9d5bef1908f17b7267bbab0e95c9bf69a0d4dcf8e9e1b2c76ef67" -dependencies = [ - "monostate-impl", - "serde", - "serde_core", -] - -[[package]] -name = "monostate-impl" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4db6d5580af57bf992f59068d4ea26fd518574ff48d7639b255a36f9de6e7e9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - [[package]] name = "moxcms" version = "0.7.5" @@ -6348,27 +5156,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "muda" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c1738382f66ed56b3b9c8119e794a2e23148ac8ea214eda86622d4cb9d415a" -dependencies = [ - "crossbeam-channel", - "dpi", - "gtk", - "keyboard-types", - "objc2 0.6.2", - "objc2-app-kit 0.3.1", - "objc2-core-foundation", - "objc2-foundation 0.3.1", - "once_cell", - "png 0.17.16", - "serde", - "thiserror 2.0.16", - "windows-sys 0.60.2", -] - [[package]] name = "naga" version = "25.0.1" @@ -6378,7 +5165,7 @@ dependencies = [ "arrayvec", "bit-set", "bitflags 2.13.1", - "cfg_aliases 0.2.1", + "cfg_aliases", "codespan-reporting", "half", "hashbrown 0.15.5", @@ -6524,18 +5311,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "nix" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" -dependencies = [ - "bitflags 2.13.1", - "cfg-if", - "cfg_aliases 0.1.1", - "libc", -] - [[package]] name = "nix" version = "0.29.0" @@ -6544,7 +5319,7 @@ checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ "bitflags 2.13.1", "cfg-if", - "cfg_aliases 0.2.1", + "cfg_aliases", "libc", ] @@ -6579,20 +5354,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" -[[package]] -name = "notify-rust" -version = "4.11.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6442248665a5aa2514e794af3b39661a8e73033b1cc5e59899e1276117ee4400" -dependencies = [ - "futures-lite", - "log", - "mac-notification-sys", - "serde", - "tauri-winrt-notification", - "zbus", -] - [[package]] name = "ntapi" version = "0.4.2" @@ -6728,7 +5489,7 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" dependencies = [ - "proc-macro-crate 3.4.0", + "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.106", @@ -6750,17 +5511,6 @@ dependencies = [ "objc_exception", ] -[[package]] -name = "objc-foundation" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" -dependencies = [ - "block", - "objc", - "objc_id", -] - [[package]] name = "objc-sys" version = "0.3.5" @@ -7080,16 +5830,6 @@ dependencies = [ "objc2-core-foundation", ] -[[package]] -name = "objc2-javascript-core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9052cb1bb50a4c161d934befcf879526fb87ae9a68858f241e693ca46225cf5a" -dependencies = [ - "objc2 0.6.2", - "objc2-core-foundation", -] - [[package]] name = "objc2-link-presentation" version = "0.2.2" @@ -7114,18 +5854,6 @@ dependencies = [ "objc2-foundation 0.2.2", ] -[[package]] -name = "objc2-osa-kit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26bb88504b5a050dbba515d2414607bf5e57dd56b107bc5f0351197a3e7bdc5d" -dependencies = [ - "bitflags 2.13.1", - "objc2 0.6.2", - "objc2-app-kit 0.3.1", - "objc2-foundation 0.3.1", -] - [[package]] name = "objc2-quartz-core" version = "0.2.2" @@ -7150,17 +5878,6 @@ dependencies = [ "objc2-foundation 0.3.1", ] -[[package]] -name = "objc2-security" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1f8e0ef3ab66b08c42644dcb34dba6ec0a574bbd8adbb8bdbdc7a2779731a44" -dependencies = [ - "bitflags 2.13.1", - "objc2 0.6.2", - "objc2-core-foundation", -] - [[package]] name = "objc2-symbols" version = "0.2.2" @@ -7192,18 +5909,6 @@ dependencies = [ "objc2-user-notifications", ] -[[package]] -name = "objc2-ui-kit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b1312ad7bc8a0e92adae17aa10f90aae1fb618832f9b993b022b591027daed" -dependencies = [ - "bitflags 2.13.1", - "objc2 0.6.2", - "objc2-core-foundation", - "objc2-foundation 0.3.1", -] - [[package]] name = "objc2-uniform-type-identifiers" version = "0.2.2" @@ -7228,22 +5933,6 @@ dependencies = [ "objc2-foundation 0.2.2", ] -[[package]] -name = "objc2-web-kit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91672909de8b1ce1c2252e95bbee8c1649c9ad9d14b9248b3d7b4c47903c47ad" -dependencies = [ - "bitflags 2.13.1", - "block2 0.6.1", - "objc2 0.6.2", - "objc2-app-kit 0.3.1", - "objc2-core-foundation", - "objc2-foundation 0.3.1", - "objc2-javascript-core", - "objc2-security", -] - [[package]] name = "objc_exception" version = "0.1.2" @@ -7253,15 +5942,6 @@ dependencies = [ "cc", ] -[[package]] -name = "objc_id" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" -dependencies = [ - "objc", -] - [[package]] name = "object" version = "0.36.7" @@ -7294,15 +5974,6 @@ dependencies = [ "cc", ] -[[package]] -name = "ogg" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6951b4e8bf21c8193da321bcce9c9dd2e13c858fe078bf9054a288b419ae5d6e" -dependencies = [ - "byteorder", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -7315,28 +5986,6 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" -[[package]] -name = "onig" -version = "6.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0" -dependencies = [ - "bitflags 2.13.1", - "libc", - "once_cell", - "onig_sys", -] - -[[package]] -name = "onig_sys" -version = "69.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f86c6eef3d6df15f23bcfb6af487cbd2fed4e5581d58d5bf1f5f8b7f6727dc" -dependencies = [ - "cc", - "pkg-config", -] - [[package]] name = "open" version = "5.4.0" @@ -7393,82 +6042,8 @@ dependencies = [ ] [[package]] -name = "opentelemetry" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84bcd6ae87133e903af7ef497404dda70c60d0ea14895fc8a5e6722754fc2a0" -dependencies = [ - "futures-core", - "futures-sink", - "js-sys", - "pin-project-lite", - "thiserror 2.0.16", - "tracing", -] - -[[package]] -name = "opentelemetry-http" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a6d09a73194e6b66df7c8f1b680f156d916a1a942abf2de06823dd02b7855d" -dependencies = [ - "async-trait", - "bytes", - "http 1.3.1", - "opentelemetry", - "reqwest", -] - -[[package]] -name = "opentelemetry-otlp" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2366db2dca4d2ad033cad11e6ee42844fd727007af5ad04a1730f4cb8163bf" -dependencies = [ - "http 1.3.1", - "opentelemetry", - "opentelemetry-http", - "opentelemetry-proto", - "opentelemetry_sdk", - "prost", - "reqwest", - "thiserror 2.0.16", - "tracing", -] - -[[package]] -name = "opentelemetry-proto" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7175df06de5eaee9909d4805a3d07e28bb752c34cab57fa9cff549da596b30f" -dependencies = [ - "opentelemetry", - "opentelemetry_sdk", - "prost", - "tonic", - "tonic-prost", -] - -[[package]] -name = "opentelemetry_sdk" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ae4f5991976fd48df6d843de219ca6d31b01daaab2dad5af2badeded372bd" -dependencies = [ - "futures-channel", - "futures-executor", - "futures-util", - "opentelemetry", - "percent-encoding", - "rand 0.9.2", - "thiserror 2.0.16", - "tokio", - "tokio-stream", -] - -[[package]] -name = "option-ext" -version = "0.2.0" +name = "option-ext" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" @@ -7506,16 +6081,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "ordered-multimap" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" -dependencies = [ - "dlv-list", - "hashbrown 0.14.5", -] - [[package]] name = "ordered-stream" version = "0.2.0" @@ -7563,30 +6128,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "os_pipe" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db335f4760b14ead6290116f2427bf33a14d4f0617d49f78a246de10c1831224" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "osakit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "732c71caeaa72c065bb69d7ea08717bd3f4863a4f451402fc9513e29dbd5261b" -dependencies = [ - "objc2 0.6.2", - "objc2-foundation 0.3.1", - "objc2-osa-kit", - "serde", - "serde_json", - "thiserror 2.0.16", -] - [[package]] name = "owned_ttf_parser" version = "0.25.1" @@ -7596,47 +6137,6 @@ dependencies = [ "ttf-parser 0.25.1", ] -[[package]] -name = "pango" -version = "0.18.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" -dependencies = [ - "gio", - "glib", - "libc", - "once_cell", - "pango-sys", -] - -[[package]] -name = "pango-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps 6.2.2", -] - -[[package]] -name = "parakeet-rs" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac2c29bb70e3b63ddfa9af7cbb66f87a200550a5f6a5ac82fabf527b270c6615" -dependencies = [ - "eyre", - "hound", - "ndarray 0.17.2", - "ort", - "realfft", - "serde", - "serde_json", - "tokenizers", -] - [[package]] name = "parking" version = "2.2.1" @@ -7710,16 +6210,6 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" -[[package]] -name = "petgraph" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" -dependencies = [ - "fixedbitset", - "indexmap 2.11.4", -] - [[package]] name = "phf" version = "0.8.0" @@ -7934,12 +6424,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" -[[package]] -name = "plain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" - [[package]] name = "plist" version = "1.8.0" @@ -8079,26 +6563,6 @@ dependencies = [ "num-integer", ] -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit 0.19.15", -] - -[[package]] -name = "proc-macro-crate" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" -dependencies = [ - "toml_datetime 0.6.3", - "toml_edit 0.20.2", -] - [[package]] name = "proc-macro-crate" version = "3.4.0" @@ -8108,30 +6572,6 @@ dependencies = [ "toml_edit 0.23.10+spec-1.0.0", ] -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro-hack" version = "0.5.20+deprecated" @@ -8147,16 +6587,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "procfs-core" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" -dependencies = [ - "bitflags 2.13.1", - "hex", -] - [[package]] name = "profiling" version = "1.0.17" @@ -8176,29 +6606,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "prost" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-derive" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425" -dependencies = [ - "anyhow", - "itertools 0.14.0", - "proc-macro2", - "quote", - "syn 2.0.106", -] - [[package]] name = "psl-types" version = "2.0.11" @@ -8264,7 +6671,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ "bytes", - "cfg_aliases 0.2.1", + "cfg_aliases", "pin-project-lite", "quinn-proto", "quinn-udp", @@ -8304,7 +6711,7 @@ version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" dependencies = [ - "cfg_aliases 0.2.1", + "cfg_aliases", "libc", "once_cell", "socket2 0.6.0", @@ -8443,15 +6850,6 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d6831663a5098ea164f89cff59c6284e95f4e3c76ce9848d4529f5ccca9bde" -[[package]] -name = "range-map" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12a5a2d6c7039059af621472a4389be1215a816df61aa4d531cfe85264aee95f" -dependencies = [ - "num-traits", -] - [[package]] name = "rangemap" version = "1.6.0" @@ -8530,17 +6928,6 @@ dependencies = [ "rayon-core", ] -[[package]] -name = "rayon-cond" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2964d0cf57a3e7a06e8183d14a8b527195c706b7983549cd5462d5aa3747438f" -dependencies = [ - "either", - "itertools 0.14.0", - "rayon", -] - [[package]] name = "rayon-core" version = "1.13.0" @@ -8592,15 +6979,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be105c72a1e6a5a1198acee3d5b506a15676b74a02ecd78060042a447f408d94" -[[package]] -name = "realfft" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f821338fddb99d089116342c46e9f1fbf3828dba077674613e734e01d6ea8677" -dependencies = [ - "rustfft", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -8803,31 +7181,6 @@ dependencies = [ "rand 0.9.2", ] -[[package]] -name = "rfd" -version = "0.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2bee61e6cffa4635c72d7d81a84294e28f0930db0ddcb0f66d10244674ebed" -dependencies = [ - "ashpd", - "block2 0.6.1", - "dispatch2", - "glib-sys", - "gobject-sys", - "gtk-sys", - "js-sys", - "log", - "objc2 0.6.2", - "objc2-app-kit 0.3.1", - "objc2-core-foundation", - "objc2-foundation 0.3.1", - "raw-window-handle", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "windows-sys 0.59.0", -] - [[package]] name = "rgb" version = "0.8.52" @@ -8897,20 +7250,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "rodio" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6006a627c1a38d37f3d3a85c6575418cfe34a5392d60a686d0071e1c8d427acb" -dependencies = [ - "claxon", - "cpal 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)", - "hound", - "lewton", - "symphonia", - "thiserror 1.0.69", -] - [[package]] name = "roxmltree" version = "0.20.0" @@ -8938,16 +7277,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "rust-ini" -version = "0.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "796e8d2b6696392a43bea58116b667fb4c29727dc5abd27d6acf338bb4f688c7" -dependencies = [ - "cfg-if", - "ordered-multimap", -] - [[package]] name = "rustc-demangle" version = "0.1.26" @@ -9115,20 +7444,11 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "sanitize-filename" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc984f4f9ceb736a7bb755c3e3bd17dc56370af2600c9780dcc48c66453da34d" -dependencies = [ - "regex", -] - [[package]] name = "scap-cpal" version = "0.1.0" dependencies = [ - "cpal 0.15.3 (git+https://github.com/CapSoftware/cpal?rev=6013cb5f8bd3)", + "cpal", "thiserror 1.0.69", "tracing", "workspace-hack", @@ -9153,7 +7473,7 @@ name = "scap-ffmpeg" version = "0.1.0" dependencies = [ "cidre", - "cpal 0.15.3 (git+https://github.com/CapSoftware/cpal?rev=6013cb5f8bd3)", + "cpal", "ffmpeg-next", "futures", "scap-cpal", @@ -9307,26 +7627,6 @@ dependencies = [ "objc", ] -[[package]] -name = "scroll" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" -dependencies = [ - "scroll_derive", -] - -[[package]] -name = "scroll_derive" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - [[package]] name = "sctk-adwaita" version = "0.10.1" @@ -9541,17 +7841,6 @@ dependencies = [ "sentry-core", ] -[[package]] -name = "sentry-rust-minidump" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63964525bf74b16233dbcfb307e11485ebd8ff8f87f6ae212b07ca7937cd2db1" -dependencies = [ - "minidumper-child", - "sentry", - "thiserror 2.0.16", -] - [[package]] name = "sentry-tracing" version = "0.42.0" @@ -9732,28 +8021,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "serialize-to-javascript" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f3666a07a197cdb77cdf306c32be9b7f598d7060d50cfd4d5aa04bfd92f6c5" -dependencies = [ - "serde", - "serde_json", - "serialize-to-javascript-impl", -] - -[[package]] -name = "serialize-to-javascript-impl" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - [[package]] name = "servo_arc" version = "0.2.0" @@ -9801,34 +8068,12 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "shared_child" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e362d9935bc50f019969e2f9ecd66786612daae13e8f277be7bfb66e8bed3f7" -dependencies = [ - "libc", - "sigchld", - "windows-sys 0.60.2", -] - [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "sigchld" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47106eded3c154e70176fc83df9737335c94ce22f821c32d17ed1db1f83badb1" -dependencies = [ - "libc", - "os_pipe", - "signal-hook", -] - [[package]] name = "signal-hook" version = "0.3.18" @@ -9920,7 +8165,7 @@ dependencies = [ "bindgen 0.71.1", "cc", "flate2", - "heck 0.5.0", + "heck", "lazy_static", "regex", "serde_json", @@ -9970,17 +8215,6 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -[[package]] -name = "smart-default" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eb01866308440fc64d6c44d9e86c5cc17adfe33c4d6eed55da9145044d0ffc1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - [[package]] name = "smithay-client-toolkit" version = "0.19.2" @@ -10054,7 +8288,7 @@ checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08" dependencies = [ "as-raw-xcb-connection", "bytemuck", - "cfg_aliases 0.2.1", + "cfg_aliases", "core-graphics 0.24.0", "drm", "fastrand", @@ -10078,32 +8312,6 @@ dependencies = [ "x11rb", ] -[[package]] -name = "soup3" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" -dependencies = [ - "futures-channel", - "gio", - "glib", - "libc", - "soup3-sys", -] - -[[package]] -name = "soup3-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" -dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps 6.2.2", -] - [[package]] name = "specta" version = "2.0.0-rc.20" @@ -10130,27 +8338,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "specta-serde" -version = "0.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12260cbb21abb2e83a0375b1521867910e3aed8a7afa782206150ce552cd2e5a" -dependencies = [ - "specta", - "thiserror 1.0.69", -] - -[[package]] -name = "specta-typescript" -version = "0.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4472229365ceb6395487e3a60d921ad8e21f9ad06eaecc396f098902c9adc" -dependencies = [ - "specta", - "specta-serde", - "thiserror 1.0.69", -] - [[package]] name = "spin" version = "0.9.8" @@ -10169,18 +8356,6 @@ dependencies = [ "bitflags 2.13.1", ] -[[package]] -name = "spm_precompiled" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5851699c4033c63636f7ea4cf7b7c1f1bf06d0cc03cfb42e711de5a5c46cf326" -dependencies = [ - "base64 0.13.1", - "nom 7.1.3", - "serde", - "unicode-segmentation", -] - [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -10263,7 +8438,7 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "rustversion", @@ -10276,7 +8451,7 @@ version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn 2.0.106", @@ -10326,55 +8501,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "symphonia" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "815c942ae7ee74737bb00f965fa5b5a2ac2ce7b6c01c0cc169bbeaf7abd5f5a9" -dependencies = [ - "lazy_static", - "symphonia-bundle-mp3", - "symphonia-core", - "symphonia-metadata", -] - -[[package]] -name = "symphonia-bundle-mp3" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c01c2aae70f0f1fb096b6f0ff112a930b1fb3626178fba3ae68b09dce71706d4" -dependencies = [ - "lazy_static", - "log", - "symphonia-core", - "symphonia-metadata", -] - -[[package]] -name = "symphonia-core" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "798306779e3dc7d5231bd5691f5a813496dc79d3f56bf82e25789f2094e022c3" -dependencies = [ - "arrayvec", - "bitflags 1.3.2", - "bytemuck", - "lazy_static", - "log", -] - -[[package]] -name = "symphonia-metadata" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc622b9841a10089c5b18e99eb904f4341615d5aa55bbf4eedde1be721a4023c" -dependencies = [ - "encoding_rs", - "lazy_static", - "log", - "symphonia-core", -] - [[package]] name = "syn" version = "1.0.109" @@ -10482,7 +8608,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" dependencies = [ "cfg-expr 0.15.8", - "heck 0.5.0", + "heck", "pkg-config", "toml 0.8.2", "version-compare", @@ -10495,61 +8621,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396a35feb67335377e0251fcbc1092fc85c484bd4e3a7a54319399da127796e7" dependencies = [ "cfg-expr 0.20.8", - "heck 0.5.0", + "heck", "pkg-config", "toml 1.1.0+spec-1.1.0", "version-compare", ] -[[package]] -name = "tao" -version = "0.34.3" -dependencies = [ - "bitflags 2.13.1", - "block2 0.6.1", - "core-foundation 0.10.1", - "core-graphics 0.24.0", - "crossbeam-channel", - "dispatch", - "dlopen2", - "dpi", - "gdkwayland-sys", - "gdkx11-sys", - "gtk", - "jni 0.21.1", - "lazy_static", - "libc", - "log", - "ndk 0.9.0", - "ndk-context", - "ndk-sys 0.6.0+11769913", - "objc2 0.6.2", - "objc2-app-kit 0.3.1", - "objc2-foundation 0.3.1", - "once_cell", - "parking_lot", - "raw-window-handle", - "scopeguard", - "tao-macros", - "unicode-segmentation", - "url", - "windows 0.61.3", - "windows-core 0.61.2", - "windows-version", - "x11-dl", -] - -[[package]] -name = "tao-macros" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - [[package]] name = "tar" version = "0.4.44" @@ -10574,663 +8651,81 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" [[package]] -name = "tauri" -version = "2.8.5" +name = "tauri-utils" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d1d3b3dc4c101ac989fd7db77e045cc6d91a25349cd410455cb5c57d510c1c" +checksum = "41a3852fdf9a4f8fbeaa63dc3e9a85284dd6ef7200751f0bd66ceee30c93f212" dependencies = [ "anyhow", - "bytes", - "cookie", - "dirs 6.0.0", + "brotli", + "cargo_metadata", + "ctor 0.2.9", "dunce", - "embed_plist", - "getrandom 0.3.3", "glob", - "gtk", - "heck 0.5.0", + "html5ever", "http 1.3.1", - "http-range", - "image 0.25.8", - "jni 0.21.1", - "libc", + "infer", + "json-patch", + "kuchikiki", "log", - "mime", - "muda", - "objc2 0.6.2", - "objc2-app-kit 0.3.1", - "objc2-foundation 0.3.1", - "objc2-ui-kit 0.3.1", - "objc2-web-kit", - "percent-encoding", - "plist", - "raw-window-handle", - "reqwest", + "memchr", + "phf 0.11.3", + "proc-macro2", + "quote", + "regex", + "schemars 0.8.22", + "semver", "serde", + "serde-untagged", "serde_json", - "serde_repr", - "serialize-to-javascript", - "specta", + "serde_with", "swift-rs", - "tauri-build", - "tauri-macros", - "tauri-runtime", - "tauri-runtime-wry", - "tauri-utils", "thiserror 2.0.16", - "tokio", - "tray-icon", + "toml 0.9.7", "url", "urlpattern", - "webkit2gtk", - "webview2-com", - "window-vibrancy", - "windows 0.61.3", + "uuid", + "walkdir", ] [[package]] -name = "tauri-build" -version = "2.4.1" +name = "tempfile" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c432ccc9ff661803dab74c6cd78de11026a578a9307610bbc39d3c55be7943f" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ - "anyhow", - "cargo_toml", - "dirs 6.0.0", - "glob", - "heck 0.5.0", - "json-patch", - "schemars 0.8.22", - "semver", - "serde", - "serde_json", - "tauri-utils", - "tauri-winres", - "toml 0.9.7", - "walkdir", + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix 1.1.2", + "windows-sys 0.61.2", ] [[package]] -name = "tauri-codegen" -version = "2.4.0" +name = "tendril" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab3a62cf2e6253936a8b267c2e95839674e7439f104fa96ad0025e149d54d8a" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" dependencies = [ - "base64 0.22.1", - "brotli", - "ico", - "json-patch", - "plist", - "png 0.17.16", - "proc-macro2", - "quote", - "semver", - "serde", - "serde_json", - "sha2", - "syn 2.0.106", - "tauri-utils", - "thiserror 2.0.16", - "time", - "url", - "uuid", - "walkdir", + "futf", + "mac", + "utf-8", ] [[package]] -name = "tauri-macros" -version = "2.4.0" +name = "termcolor" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4368ea8094e7045217edb690f493b55b30caf9f3e61f79b4c24b6db91f07995e" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.106", - "tauri-codegen", - "tauri-utils", + "winapi-util", ] [[package]] -name = "tauri-nspanel" -version = "2.0.1" -dependencies = [ - "bitflags 2.13.1", - "block", - "cocoa", - "core-foundation 0.10.1", - "core-graphics 0.25.0", - "objc", - "objc-foundation", - "objc_exception", - "objc_id", - "tauri", -] - -[[package]] -name = "tauri-plugin" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9946a3cede302eac0c6eb6c6070ac47b1768e326092d32efbb91f21ed58d978f" -dependencies = [ - "anyhow", - "glob", - "plist", - "schemars 0.8.22", - "serde", - "serde_json", - "tauri-utils", - "toml 0.9.7", - "walkdir", -] - -[[package]] -name = "tauri-plugin-clipboard-manager" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adddd9e9275b20e77af3061d100a25a884cced3c4c9ef680bd94dd0f7e26c1ca" -dependencies = [ - "arboard", - "log", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "thiserror 2.0.16", -] - -[[package]] -name = "tauri-plugin-deep-link" -version = "2.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd67112fb1131834c2a7398ffcba520dbbf62c17de3b10329acd1a3554b1a9bb" -dependencies = [ - "dunce", - "plist", - "rust-ini", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "tauri-utils", - "thiserror 2.0.16", - "tracing", - "url", - "windows-registry", - "windows-result 0.3.4", -] - -[[package]] -name = "tauri-plugin-dialog" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0beee42a4002bc695550599b011728d9dfabf82f767f134754ed6655e434824e" -dependencies = [ - "log", - "raw-window-handle", - "rfd", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "tauri-plugin-fs", - "thiserror 2.0.16", - "url", -] - -[[package]] -name = "tauri-plugin-fs" -version = "2.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "315784ec4be45e90a987687bae7235e6be3d6e9e350d2b75c16b8a4bf22c1db7" -dependencies = [ - "anyhow", - "dunce", - "glob", - "percent-encoding", - "schemars 0.8.22", - "serde", - "serde_json", - "serde_repr", - "tauri", - "tauri-plugin", - "tauri-utils", - "thiserror 2.0.16", - "toml 0.9.7", - "url", -] - -[[package]] -name = "tauri-plugin-global-shortcut" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6df9f0f7bf2fe768b85fee4951c2505a35b72c44df1f6403e74e110bc13c5f58" -dependencies = [ - "global-hotkey", - "log", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "thiserror 2.0.16", -] - -[[package]] -name = "tauri-plugin-http" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938a3d7051c9a82b431e3a0f3468f85715b3442b3c3a3913095e9fa509e2652c" -dependencies = [ - "bytes", - "cookie_store", - "data-url", - "http 1.3.1", - "regex", - "reqwest", - "schemars 0.8.22", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "tauri-plugin-fs", - "thiserror 2.0.16", - "tokio", - "url", - "urlpattern", -] - -[[package]] -name = "tauri-plugin-notification" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fbc86b929b5376ab84b25c060f966d146b2fbd59b6af8264027b343c82c219" -dependencies = [ - "log", - "notify-rust", - "rand 0.9.2", - "serde", - "serde_json", - "serde_repr", - "tauri", - "tauri-plugin", - "thiserror 2.0.16", - "time", - "url", -] - -[[package]] -name = "tauri-plugin-oauth" -version = "2.0.0" -source = "git+https://github.com/FabianLars/tauri-plugin-oauth?branch=v2#f941c99c3ed528a55db7fe05c931480a8255041d" -dependencies = [ - "httparse", - "log", - "serde", - "tauri", - "tauri-plugin", - "thiserror 1.0.69", - "url", -] - -[[package]] -name = "tauri-plugin-opener" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786156aa8e89e03d271fbd3fe642207da8e65f3c961baa9e2930f332bf80a1f5" -dependencies = [ - "dunce", - "glob", - "objc2-app-kit 0.3.1", - "objc2-foundation 0.3.1", - "open", - "schemars 0.8.22", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "thiserror 2.0.16", - "url", - "windows 0.61.3", - "zbus", -] - -[[package]] -name = "tauri-plugin-os" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a1c77ebf6f20417ab2a74e8c310820ba52151406d0c80fbcea7df232e3f6ba" -dependencies = [ - "gethostname", - "log", - "os_info", - "serde", - "serde_json", - "serialize-to-javascript", - "sys-locale", - "tauri", - "tauri-plugin", - "thiserror 2.0.16", -] - -[[package]] -name = "tauri-plugin-positioner" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a01e373ea3f3f5f46d40f434ba13bd12fa4833aabab50dfc09f6362bad27c95" -dependencies = [ - "log", - "serde", - "serde_json", - "serde_repr", - "tauri", - "tauri-plugin", - "thiserror 2.0.16", -] - -[[package]] -name = "tauri-plugin-process" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7461c622a5ea00eb9cd9f7a08dbd3bf79484499fd5c21aa2964677f64ca651ab" -dependencies = [ - "tauri", - "tauri-plugin", -] - -[[package]] -name = "tauri-plugin-sentry" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7432b519b6d2d027082a940783c61ba9b684b38d8df7558cd5f924d87009b295" -dependencies = [ - "base64 0.22.1", - "schemars 0.8.22", - "sentry", - "sentry-rust-minidump", - "serde", - "tauri", - "tauri-plugin", - "thiserror 2.0.16", -] - -[[package]] -name = "tauri-plugin-shell" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54777d0c0d8add34eea3ced84378619ef5b97996bd967d3038c668feefd21071" -dependencies = [ - "encoding_rs", - "log", - "open", - "os_pipe", - "regex", - "schemars 0.8.22", - "serde", - "serde_json", - "shared_child", - "tauri", - "tauri-plugin", - "thiserror 2.0.16", - "tokio", -] - -[[package]] -name = "tauri-plugin-single-instance" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb9cac815bf11c4a80fb498666bcdad66d65b89e3ae24669e47806febb76389c" -dependencies = [ - "serde", - "serde_json", - "tauri", - "tauri-plugin-deep-link", - "thiserror 2.0.16", - "tracing", - "windows-sys 0.60.2", - "zbus", -] - -[[package]] -name = "tauri-plugin-store" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d85dd80d60a76ee2c2fdce09e9ef30877b239c2a6bb76e6d7d03708aa5f13a19" -dependencies = [ - "dunce", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "thiserror 2.0.16", - "tokio", - "tracing", -] - -[[package]] -name = "tauri-plugin-updater" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27cbc31740f4d507712550694749572ec0e43bdd66992db7599b89fbfd6b167b" -dependencies = [ - "base64 0.22.1", - "dirs 6.0.0", - "flate2", - "futures-util", - "http 1.3.1", - "infer", - "log", - "minisign-verify", - "osakit", - "percent-encoding", - "reqwest", - "semver", - "serde", - "serde_json", - "tar", - "tauri", - "tauri-plugin", - "tempfile", - "thiserror 2.0.16", - "time", - "tokio", - "url", - "windows-sys 0.60.2", - "zip", -] - -[[package]] -name = "tauri-plugin-window-state" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d5f6fe3291bfa609c7e0b0ee3bedac294d94c7018934086ce782c1d0f2a468e" -dependencies = [ - "bitflags 2.13.1", - "log", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "thiserror 2.0.16", -] - -[[package]] -name = "tauri-runtime" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4cfc9ad45b487d3fded5a4731a567872a4812e9552e3964161b08edabf93846" -dependencies = [ - "cookie", - "dpi", - "gtk", - "http 1.3.1", - "jni 0.21.1", - "objc2 0.6.2", - "objc2-ui-kit 0.3.1", - "objc2-web-kit", - "raw-window-handle", - "serde", - "serde_json", - "tauri-utils", - "thiserror 2.0.16", - "url", - "webkit2gtk", - "webview2-com", - "windows 0.61.3", -] - -[[package]] -name = "tauri-runtime-wry" -version = "2.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fe9d48bd122ff002064e88cfcd7027090d789c4302714e68fcccba0f4b7807" -dependencies = [ - "gtk", - "http 1.3.1", - "jni 0.21.1", - "log", - "objc2 0.6.2", - "objc2-app-kit 0.3.1", - "objc2-foundation 0.3.1", - "once_cell", - "percent-encoding", - "raw-window-handle", - "softbuffer", - "tao", - "tauri-runtime", - "tauri-utils", - "url", - "webkit2gtk", - "webview2-com", - "windows 0.61.3", - "wry", -] - -[[package]] -name = "tauri-specta" -version = "2.0.0-rc.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d06336a2fa3ead0c8d08719e78cbc1fb73650845789605bd2ab908cbde72815" -dependencies = [ - "heck 0.5.0", - "serde", - "serde_json", - "specta", - "specta-typescript", - "tauri", - "tauri-specta-macros", - "thiserror 1.0.69", -] - -[[package]] -name = "tauri-specta-macros" -version = "2.0.0-rc.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a4aa93823e07859546aa796b8a5d608190cd8037a3a5dce3eb63d491c34bda8" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "tauri-utils" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41a3852fdf9a4f8fbeaa63dc3e9a85284dd6ef7200751f0bd66ceee30c93f212" -dependencies = [ - "anyhow", - "brotli", - "cargo_metadata", - "ctor 0.2.9", - "dunce", - "glob", - "html5ever", - "http 1.3.1", - "infer", - "json-patch", - "kuchikiki", - "log", - "memchr", - "phf 0.11.3", - "proc-macro2", - "quote", - "regex", - "schemars 0.8.22", - "semver", - "serde", - "serde-untagged", - "serde_json", - "serde_with", - "swift-rs", - "thiserror 2.0.16", - "toml 0.9.7", - "url", - "urlpattern", - "uuid", - "walkdir", -] - -[[package]] -name = "tauri-winres" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd21509dd1fa9bd355dc29894a6ff10635880732396aa38c0066c1e6c1ab8074" -dependencies = [ - "embed-resource", - "toml 0.9.7", -] - -[[package]] -name = "tauri-winrt-notification" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b1e66e07de489fe43a46678dd0b8df65e0c973909df1b60ba33874e297ba9b9" -dependencies = [ - "quick-xml 0.37.5", - "thiserror 2.0.16", - "windows 0.61.3", - "windows-version", -] - -[[package]] -name = "tempfile" -version = "3.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" -dependencies = [ - "fastrand", - "getrandom 0.3.3", - "once_cell", - "rustix 1.1.2", - "windows-sys 0.61.2", -] - -[[package]] -name = "tendril" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" -dependencies = [ - "futf", - "mac", - "utf-8", -] - -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl 1.0.69", ] @@ -11336,15 +8831,6 @@ dependencies = [ "time-core", ] -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - [[package]] name = "tiny-skia" version = "0.11.4" @@ -11409,39 +8895,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" -[[package]] -name = "tokenizers" -version = "0.22.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b238e22d44a15349529690fb07bd645cf58149a1b1e44d6cb5bd1641ff1a6223" -dependencies = [ - "ahash", - "aho-corasick", - "compact_str", - "dary_heap", - "derive_builder", - "esaxx-rs", - "getrandom 0.3.3", - "itertools 0.14.0", - "log", - "macro_rules_attribute", - "monostate", - "onig", - "paste", - "rand 0.9.2", - "rayon", - "rayon-cond", - "regex", - "regex-syntax", - "serde", - "serde_json", - "spm_precompiled", - "thiserror 2.0.16", - "unicode-normalization-alignments", - "unicode-segmentation", - "unicode_categories", -] - [[package]] name = "tokio" version = "1.47.1" @@ -11494,18 +8947,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-stream" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", - "tokio-util", -] - [[package]] name = "tokio-tungstenite" version = "0.24.0" @@ -11515,19 +8956,7 @@ dependencies = [ "futures-util", "log", "tokio", - "tungstenite 0.24.0", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c" -dependencies = [ - "futures-util", - "log", - "tokio", - "tungstenite 0.29.0", + "tungstenite", ] [[package]] @@ -11613,17 +9042,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap 2.11.4", - "toml_datetime 0.6.3", - "winnow 0.5.40", -] - [[package]] name = "toml_edit" version = "0.20.2" @@ -11665,38 +9083,6 @@ version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" -[[package]] -name = "tonic" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb7613188ce9f7df5bfe185db26c5814347d110db17920415cf2fbcad85e7203" -dependencies = [ - "async-trait", - "base64 0.22.1", - "bytes", - "http 1.3.1", - "http-body", - "http-body-util", - "percent-encoding", - "pin-project", - "sync_wrapper", - "tokio-stream", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tonic-prost" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66bd50ad6ce1252d87ef024b3d64fe4c3cf54a86fb9ef4c631fdd0ded7aeaa67" -dependencies = [ - "bytes", - "prost", - "tonic", -] - [[package]] name = "tower" version = "0.5.2" @@ -11785,19 +9171,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", - "valuable", -] - -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "futures", - "futures-task", - "pin-project", - "tracing", + "valuable", ] [[package]] @@ -11811,25 +9185,6 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "tracing-opentelemetry" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6e5658463dd88089aba75c7791e1d3120633b1bfde22478b28f625a9bb1b8e" -dependencies = [ - "js-sys", - "opentelemetry", - "opentelemetry_sdk", - "rustversion", - "smallvec", - "thiserror 2.0.16", - "tracing", - "tracing-core", - "tracing-log", - "tracing-subscriber", - "web-time", -] - [[package]] name = "tracing-subscriber" version = "0.3.20" @@ -11858,40 +9213,6 @@ dependencies = [ "strength_reduce", ] -[[package]] -name = "tray-icon" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d92153331e7d02ec09137538996a7786fe679c629c279e82a6be762b7e6fe2" -dependencies = [ - "crossbeam-channel", - "dirs 6.0.0", - "libappindicator", - "muda", - "objc2 0.6.2", - "objc2-app-kit 0.3.1", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-foundation 0.3.1", - "once_cell", - "png 0.17.16", - "serde", - "thiserror 2.0.16", - "windows-sys 0.59.0", -] - -[[package]] -name = "tree_magic_mini" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f943391d896cdfe8eec03a04d7110332d445be7df856db382dd96a730667562c" -dependencies = [ - "memchr", - "nom 7.1.3", - "once_cell", - "petgraph", -] - [[package]] name = "try-lock" version = "0.2.5" @@ -11937,28 +9258,6 @@ dependencies = [ "utf-8", ] -[[package]] -name = "tungstenite" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" -dependencies = [ - "bytes", - "data-encoding", - "http 1.3.1", - "httparse", - "log", - "rand 0.9.2", - "sha1", - "thiserror 2.0.16", -] - -[[package]] -name = "twox-hash" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" - [[package]] name = "typeid" version = "1.0.3" @@ -11971,15 +9270,6 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" -[[package]] -name = "uds" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "885c31f06fce836457fe3ef09a59f83fe8db95d270b11cd78f40a4666c4d1661" -dependencies = [ - "libc", -] - [[package]] name = "uds_windows" version = "1.1.0" @@ -12089,15 +9379,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" -[[package]] -name = "unicode-normalization-alignments" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f613e4fa046e69818dd287fdc4bc78175ff20331479dab6e1b0f98d57062de" -dependencies = [ - "smallvec", -] - [[package]] name = "unicode-properties" version = "0.1.3" @@ -12140,12 +9421,6 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" -[[package]] -name = "unicode_categories" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" - [[package]] name = "untrusted" version = "0.9.0" @@ -12332,26 +9607,6 @@ version = "0.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" -[[package]] -name = "vswhom" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" -dependencies = [ - "libc", - "vswhom-sys", -] - -[[package]] -name = "vswhom-sys" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150" -dependencies = [ - "cc", - "libc", -] - [[package]] name = "walkdir" version = "2.5.0" @@ -12615,50 +9870,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webkit2gtk" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76b1bc1e54c581da1e9f179d0b38512ba358fb1af2d634a1affe42e37172361a" -dependencies = [ - "bitflags 1.3.2", - "cairo-rs", - "gdk", - "gdk-sys", - "gio", - "gio-sys", - "glib", - "glib-sys", - "gobject-sys", - "gtk", - "gtk-sys", - "javascriptcore-rs", - "libc", - "once_cell", - "soup3", - "webkit2gtk-sys", -] - -[[package]] -name = "webkit2gtk-sys" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62daa38afc514d1f8f12b8693d30d5993ff77ced33ce30cd04deebc267a6d57c" -dependencies = [ - "bitflags 1.3.2", - "cairo-sys-rs", - "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "gtk-sys", - "javascriptcore-rs-sys", - "libc", - "pkg-config", - "soup3-sys", - "system-deps 6.2.2", -] - [[package]] name = "webpki-root-certs" version = "1.0.2" @@ -12677,42 +9888,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "webview2-com" -version = "0.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4ba622a989277ef3886dd5afb3e280e3dd6d974b766118950a08f8f678ad6a4" -dependencies = [ - "webview2-com-macros", - "webview2-com-sys", - "windows 0.61.3", - "windows-core 0.61.2", - "windows-implement 0.60.2", - "windows-interface 0.59.3", -] - -[[package]] -name = "webview2-com-macros" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a921c1b6914c367b2b823cd4cde6f96beec77d30a939c8199bb377cf9b9b54" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "webview2-com-sys" -version = "0.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36695906a1b53a3bf5c4289621efedac12b73eeb0b89e7e1a89b517302d5d75c" -dependencies = [ - "thiserror 2.0.16", - "windows 0.61.3", - "windows-core 0.61.2", -] - [[package]] name = "weezl" version = "0.1.10" @@ -12727,7 +9902,7 @@ checksum = "ec8fb398f119472be4d80bc3647339f56eb63b2a331f6a3d16e25d8144197dd9" dependencies = [ "arrayvec", "bitflags 2.13.1", - "cfg_aliases 0.2.1", + "cfg_aliases", "document-features", "hashbrown 0.15.5", "js-sys", @@ -12757,7 +9932,7 @@ dependencies = [ "bit-set", "bit-vec", "bitflags 2.13.1", - "cfg_aliases 0.2.1", + "cfg_aliases", "document-features", "hashbrown 0.15.5", "indexmap 2.11.4", @@ -12817,7 +9992,7 @@ dependencies = [ "block", "bytemuck", "cfg-if", - "cfg_aliases 0.2.1", + "cfg_aliases", "core-graphics-types 0.1.3", "glow", "glutin_wgl_sys", @@ -12876,27 +10051,6 @@ dependencies = [ "rustix 0.38.44", ] -[[package]] -name = "whisper-rs" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed7a191078e189d96d029244ab1dff159775adec71dc89a222e9bb9d21a7d161" -dependencies = [ - "whisper-rs-sys", -] - -[[package]] -name = "whisper-rs-sys" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2834f4ca6472b02748c6c282a60cea538f962428f79e685c3205a08efd711336" -dependencies = [ - "bindgen 0.69.5", - "cfg-if", - "cmake", - "fs_extra", -] - [[package]] name = "wild" version = "2.2.1" @@ -12937,21 +10091,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "window-vibrancy" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" -dependencies = [ - "objc2 0.6.2", - "objc2-app-kit 0.3.1", - "objc2-core-foundation", - "objc2-foundation 0.3.1", - "raw-window-handle", - "windows-sys 0.59.0", - "windows-version", -] - [[package]] name = "windows" version = "0.48.0" @@ -12981,16 +10120,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f919aee0a93304be7f62e8e5027811bbba96bcb1de84d6618be56e43f8a32a1" -dependencies = [ - "windows-core 0.59.0", - "windows-targets 0.53.3", -] - [[package]] name = "windows" version = "0.60.0" @@ -13058,19 +10187,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-core" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce" -dependencies = [ - "windows-implement 0.59.0", - "windows-interface 0.59.3", - "windows-result 0.3.4", - "windows-strings 0.3.1", - "windows-targets 0.53.3", -] - [[package]] name = "windows-core" version = "0.60.1" @@ -13410,24 +10526,6 @@ dependencies = [ "windows-link 0.1.3", ] -[[package]] -name = "windows-version" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e061eb0a22b4a1d778ad70f7575ec7845490abb35b08fa320df7895882cacb" -dependencies = [ - "windows-link 0.2.1", -] - -[[package]] -name = "windows-win" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58e23e33622b3b52f948049acbec9bcc34bf6e26d74176b88941f213c75cf2dc" -dependencies = [ - "error-code", -] - [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -13621,7 +10719,7 @@ dependencies = [ "block2 0.5.1", "bytemuck", "calloop", - "cfg_aliases 0.2.1", + "cfg_aliases", "concurrent-queue", "core-foundation 0.9.4", "core-graphics 0.23.2", @@ -13634,7 +10732,7 @@ dependencies = [ "objc2 0.5.2", "objc2-app-kit 0.2.2", "objc2-foundation 0.2.2", - "objc2-ui-kit 0.2.2", + "objc2-ui-kit", "orbclient", "percent-encoding", "pin-project", @@ -13687,41 +10785,12 @@ dependencies = [ "memchr", ] -[[package]] -name = "winreg" -version = "0.55.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" -dependencies = [ - "cfg-if", - "windows-sys 0.59.0", -] - [[package]] name = "wit-bindgen" version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" -[[package]] -name = "wl-clipboard-rs" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5ff8d0e60065f549fafd9d6cb626203ea64a798186c80d8e7df4f8af56baeb" -dependencies = [ - "libc", - "log", - "os_pipe", - "rustix 0.38.44", - "tempfile", - "thiserror 2.0.16", - "tree_magic_mini", - "wayland-backend", - "wayland-client", - "wayland-protocols", - "wayland-protocols-wlr", -] - [[package]] name = "workspace-hack" version = "0.1.0" @@ -13826,51 +10895,6 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" -[[package]] -name = "wry" -version = "0.53.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f0e9642a0d061f6236c54ccae64c2722a7879ad4ec7dff59bd376d446d8e90" -dependencies = [ - "base64 0.22.1", - "block2 0.6.1", - "cookie", - "crossbeam-channel", - "dirs 6.0.0", - "dpi", - "dunce", - "gdkx11", - "gtk", - "html5ever", - "http 1.3.1", - "javascriptcore-rs", - "jni 0.21.1", - "kuchikiki", - "libc", - "ndk 0.9.0", - "objc2 0.6.2", - "objc2-app-kit 0.3.1", - "objc2-core-foundation", - "objc2-foundation 0.3.1", - "objc2-ui-kit 0.3.1", - "objc2-web-kit", - "once_cell", - "percent-encoding", - "raw-window-handle", - "sha2", - "soup3", - "tao-macros", - "thiserror 2.0.16", - "url", - "webkit2gtk", - "webkit2gtk-sys", - "webview2-com", - "windows 0.61.3", - "windows-core 0.61.2", - "windows-version", - "x11-dl", -] - [[package]] name = "x11" version = "2.21.0" @@ -14065,7 +11089,7 @@ version = "5.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe96480bed92df2b442a1a30df364e12d08eed03aeb061f2b8dc6afb2be91119" dependencies = [ - "proc-macro-crate 3.4.0", + "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.106", @@ -14171,18 +11195,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "zip" -version = "4.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caa8cd6af31c3b31c6631b8f483848b91589021b28fffe50adada48d4f4d2ed1" -dependencies = [ - "arbitrary", - "crc32fast", - "indexmap 2.11.4", - "memchr", -] - [[package]] name = "zlib-rs" version = "0.5.2" @@ -14234,7 +11246,7 @@ version = "5.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38a708216a18780796770bfe3f4739c7c83a3e8f789b755534bbbc06e4e23e12" dependencies = [ - "proc-macro-crate 3.4.0", + "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.106", diff --git a/Cargo.toml b/Cargo.toml index fa189ab7752..a43675c14f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,6 @@ resolver = "2" members = [ "apps/cli", - "apps/desktop/src-tauri", "crates/*", "crates/workspace-hack", ] @@ -24,7 +23,6 @@ tokio = { version = "1.39.3", features = [ "rt-multi-thread", "time", ] } -tauri = { version = "2.5.0", features = ["specta"] } specta = { version = "=2.0.0-rc.20", features = [ "derive", "serde_json", @@ -163,15 +161,6 @@ cidre = { git = "https://github.com/CapSoftware/cidre", rev = "bf84b67079a8" } # https://github.com/gfx-rs/wgpu/pull/7550 # wgpu = { git = "https://github.com/gfx-rs/wgpu", rev = "cd41a6e32a6239b65d1cecbeccde6a43a100914a" } wgpu-hal = { path = "vendor/wgpu-hal" } -tao = { path = "vendor/tao" } # https://github.com/CapSoftware/reqwest/commit/9b5ecbd5210a9510fde766015cabb724c1e70d2e reqwest = { git = "https://github.com/CapSoftware/reqwest", rev = "9b5ecbd5210a9510fde766015cabb724c1e70d2e" } - -# tauri-nspanel v2 @ 18ffb9a with ownership fixes: `to_panel()` no longer steals -# tao's NSWindow retain (every repeat call was an over-release), converting the -# same window twice is a no-op, the store forgets destroyed windows, and the -# broken `dealloc` override (NSObject dealloc + jump through a garbage pointer) -# is gone. See vendor/tauri-nspanel/CAP-CHANGES.md. -[patch."https://github.com/ahkohd/tauri-nspanel"] -tauri-nspanel = { path = "vendor/tauri-nspanel" } diff --git a/README.md b/README.md index a05520a1b15..c1e2d45b357 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- Cap logo + Cap logo

Cap

@@ -37,7 +37,7 @@ Use Cap for product demos, bug reports, onboarding, tutorials, design reviews, e - **Record, edit, share.** Capture your screen, camera, and microphone, then share a link or export a finished video. - **Instant Mode for speed.** Upload while recording and get a shareable link the moment you stop. - **Studio Mode for polish.** Record locally, edit with backgrounds, zooms, trimming, captions, and export controls. -- **Desktop apps for your team.** Cap runs on macOS and Windows, with a web dashboard for viewing, sharing, and managing recordings. +- **A native desktop app.** Cap runs on macOS, Windows, and Linux, with a web dashboard for viewing, sharing, and managing recordings. - **Own your storage.** Use Cap Cloud, connect your own S3-compatible bucket, keep recordings local, or self-host the full platform. - **Privacy by default.** Share publicly or privately, add passwords, use your own domain, or keep sensitive recordings off hosted infrastructure. - **Async collaboration.** Comments, reactions, transcripts, viewer analytics, and team workspaces keep feedback attached to the video. @@ -65,7 +65,7 @@ Cap is designed for people and teams who do not want their recording workflow lo For most users, the fastest path is: -1. Download Cap for macOS or Windows from [cap.so/download](https://cap.so/download). +1. Download Cap for macOS, Windows, or Linux from [cap.so/download](https://cap.so/download). 2. Sign in or create an account. 3. Choose Instant Mode or Studio Mode. 4. Record your first Cap. @@ -116,13 +116,13 @@ secret, proxy hardening, and how to trigger sign-in without a built-in login but ## Local Development -Cap is a Turborepo monorepo with Rust, TypeScript, Tauri, SolidStart, Next.js, Drizzle, MySQL, Tailwind CSS, and shared media crates. +Cap is a Turborepo monorepo. The desktop app is native Rust with a [GPUI](https://www.gpui.rs/) interface, the web app is Next.js with Drizzle and MySQL, and recording, rendering, and export live in shared Rust crates. Requirements: - Node.js 24 or newer - Bun 1.4.4 -- Rust 1.88 or newer +- Rust via [rustup](https://rustup.rs). The workspace pins 1.88; the desktop app pins its own toolchain, which rustup installs on first build. - Docker for MySQL, MinIO, and local services Install and set up the repo: @@ -139,9 +139,9 @@ Common commands: | --- | --- | | `bun run dev` | Start the full local development stack | | `bun run dev:web` | Start the web app without the desktop app | -| `bun run dev:desktop` | Start the desktop app | +| `bun run dev:desktop` | Build and run the desktop app, rebuilding on save on macOS | | `bun run build` | Build the workspace | -| `bun run tauri:build` | Build the desktop release | +| `bun run gpui:build ` | Build and package a desktop release for a Rust target triple | | `bun run lint` | Run Biome linting | | `bun run format` | Format with Biome | | `bun run typecheck` | Run TypeScript project references | @@ -159,14 +159,13 @@ Database commands: | Path | What lives there | | --- | --- | -| `apps/desktop` | Tauri v2 desktop app with SolidStart UI and Rust backend | +| `apps/desktop-gpui` | The Cap desktop app: native Rust and GPUI for macOS, Windows, and Linux | | `apps/web` | Next.js web app for marketing, docs, dashboard, sharing, API routes, and auth | | `apps/cli` | Rust CLI | | `apps/media-server` | Media processing service used by the web app | | `apps/discord-bot` | Discord integration | | `packages/database` | Drizzle schema and database access | | `packages/ui` | Shared React UI | -| `packages/ui-solid` | Shared Solid UI | | `packages/web-backend` | Backend service layer | | `packages/web-domain` | Web domain models and types | | `packages/env` | Environment validation | diff --git a/apps/cli/src/automation.rs b/apps/cli/src/automation.rs index bd998934635..be6573e77a9 100644 --- a/apps/cli/src/automation.rs +++ b/apps/cli/src/automation.rs @@ -1,5 +1,5 @@ //! Runs Cap automation rules from the CLI, sharing the exact rule model and engine the desktop app -//! uses (`cap_automation`). Rules are authored in Cap Desktop and persisted to its tauri-plugin-store +//! uses (`cap_automation`). Rules are authored in Cap Desktop and persisted to its JSON store //! file; the CLI reads that file directly (same approach as `credentials.rs`) so a rule like //! "on screenshot, save to ~/Shots" is honored whether the capture came from the app or `cap`. diff --git a/apps/cli/src/credentials.rs b/apps/cli/src/credentials.rs index ad9b4225d03..ca3b497529e 100644 --- a/apps/cli/src/credentials.rs +++ b/apps/cli/src/credentials.rs @@ -3,7 +3,7 @@ //! Priority: explicit `CAP_API_KEY`/`CAP_SERVER_URL` env vars (for CI/headless), then the login the //! desktop app already stored. The CLI is the same product as Cap Desktop, so if the user is signed //! in there, `cap upload` just works — no key to copy, no env var to set. The desktop persists its -//! auth as plain JSON via tauri-plugin-store, so we read it directly without any Tauri dependency. +//! auth as a plain JSON store file, so we read it directly. use std::collections::BTreeMap; diff --git a/apps/cli/src/recordings.rs b/apps/cli/src/recordings.rs index dc517bb81ad..fcd996bb305 100644 --- a/apps/cli/src/recordings.rs +++ b/apps/cli/src/recordings.rs @@ -9,8 +9,8 @@ use serde::Serialize; use crate::{OutputFormat, write_json}; -// Production bundle identifier; matches tauri.prod.conf.json. Dev builds use `so.cap.desktop.dev`, -// which the user can reach with an explicit `--dir`. +// The desktop app's bundle identifier (`identifier` in apps/desktop-gpui/tauri.conf.json). Dev +// builds of 0.6.0 and earlier used `so.cap.desktop.dev`, which the user can reach with `--dir`. const DESKTOP_BUNDLE_IDENTIFIER: &str = "so.cap.desktop"; fn library_dirs(app_data: &Path) -> Vec { diff --git a/apps/desktop-gpui/Cargo.toml b/apps/desktop-gpui/Cargo.toml index 3a717d0a636..f2306ee9252 100644 --- a/apps/desktop-gpui/Cargo.toml +++ b/apps/desktop-gpui/Cargo.toml @@ -1,8 +1,8 @@ # Standalone workspace on purpose: the gpui dependency tree is enormous and # pulls its own git revisions of wgpu/font stacks. Keeping it out of the root -# workspace leaves the root Cargo.lock, `cargo hakari` workspace-hack and CI -# untouched, and sidesteps the root `[patch.crates-io]` entries (vendored -# wgpu-hal, tao) that only exist for the Tauri app. +# workspace keeps the root Cargo.lock and `cargo hakari` workspace-hack free of +# it, and sidesteps the root `[patch.crates-io]` forks (reqwest, cidre) that +# gpui's tree does not want. [workspace] resolver = "2" members = [".", "kernels", "i18n-build", "glass"] @@ -40,15 +40,15 @@ gpui_platform = { git = "https://github.com/wingleeio/zed", rev = "5d1f83d9f27a1 ] } gpui_tokio = { git = "https://github.com/wingleeio/zed", rev = "5d1f83d9f27a19bec1fb241dc33b42238af9cf8d" } -# Device enumeration reuses the same crates the Tauri app records with, so the -# device identities here are byte-identical to the ones cap-recording expects. +# Device enumeration reuses the crates cap-recording records with, so the +# device identities here are byte-identical to the ones it expects. cap-camera = { path = "../../crates/camera" } scap-targets = { path = "../../crates/scap-targets" } # Same fork/rev as the root workspace: MicrophoneFeed enumerates through this. cpal = { git = "https://github.com/CapSoftware/cpal", rev = "6013cb5f8bd3" } -# The actual recording engine -- the same studio/instant actors the Tauri app -# drives. Drags in the ffmpeg encode stack; that is the point. +# The actual recording engine: the studio/instant actors. Drags in the ffmpeg +# encode stack; that is the point. cap-recording = { path = "../../crates/recording" } cap-media-info = { path = "../../crates/media-info" } cap-enc-ffmpeg = { path = "../../crates/enc-ffmpeg" } @@ -71,13 +71,12 @@ rodio = { version = "0.19.0", default-features = false, features = [ # already depends on it, so wgpu 25 and its vendored wgpu-hal have been built # by this workspace since the recording unit; naming it here only makes the # dependency direct so the editor can talk to `RenderedFrame`/`FrameLayout`. -# `cap-editor` is the seam the Tauri editor window uses too: `EditorInstance` -# owns the decoders, the renderer actor, the preview/scrub renderer and -# playback, and hands frames back through a plain `FnMut` callback. It carries -# no tauri types -- the websocket lives in the Tauri binary, not in the crate. +# `cap-editor` is the editor's seam: `EditorInstance` owns the decoders, the +# renderer actor, the preview/scrub renderer and playback, and hands frames +# back through a plain `FnMut` callback. cap-rendering = { path = "../../crates/rendering" } # The camera bubble's live background blur (`src/camera_blur.rs`): the same -# `BlurProcessor` the Tauri preview and the editor's camera layer run. +# `BlurProcessor` the editor's camera layer runs. # Already in this lockfile through cap-rendering, so naming it only makes the # edge direct. cap-camera-effects = { path = "../../crates/camera-effects" } @@ -91,7 +90,7 @@ cap-editor = { path = "../../crates/editor" } # is the cheaper of the two options rather than the only one. cap-export = { path = "../../crates/export" } # The first-frame JPEG a finished recording's Recents card is drawn from -# (`create_screenshot` in the Tauri binary). Same package/git/rev the root +# (`create_screenshot`, ported from 0.6.0). Same package/git/rev the root # workspace pins, and cap-recording already builds it, so this is an import, # not an extra dependency tree. ffmpeg = { package = "ffmpeg-next", git = "https://github.com/CapSoftware/rust-ffmpeg", rev = "49db1fede112" } @@ -121,9 +120,9 @@ sys-locale = "0.3" unicode-segmentation = "1" # spawn_blocking for finalize; the runtime itself comes from gpui_tokio. tokio = { version = "1", features = ["rt", "time"] } -# The same crate `tauri_plugin_global_shortcut` wraps, at the Tauri app's pin: -# store bindings are W3C `KeyboardEvent.code` strings and this owns the -# platform mapping (Carbon RegisterEventHotKey on macOS). +# The crate 0.6.0's global-shortcut plugin wrapped, at the same pin: stored +# bindings are W3C `KeyboardEvent.code` strings and this owns the platform +# mapping (Carbon RegisterEventHotKey on macOS). global-hotkey = "0.7.0" # cap-recording's actor system; version must match its `kameo = "0.17.2"`. kameo = "0.17.2" @@ -132,7 +131,7 @@ flume = "0.11.0" lyon_tessellation = "1.0" anyhow = "1" chrono = "0.4" -# Read the Tauri app's settings store so both apps share one recordings library. +# The JSON `store` file in the app-data directory (`src/store.rs`). serde_json = "1" serde = { version = "1", features = ["derive"] } sanitize-filename = "0.6.0" @@ -156,14 +155,14 @@ sha2 = "0.10" tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } # The rolling file log the Feedback page uploads. Same crate and rolling -# strategy the Tauri app uses, under a different filename prefix so the two -# apps never write into one file (`src/diagnostics.rs`). +# strategy 0.6.0 used, under its own `cap-gpui` prefix so an update never +# appends to a 0.6.0 log (`src/diagnostics.rs`). tracing-appender = "0.2" # Web-backed settings pages (feedback, changelog, license) and transcription # model downloads. rustls so Linux builds do not pick up an OpenSSL system dep. # `multipart` is the log/diagnostic-report upload (`src/diagnostics.rs`): -# `/api/desktop/logs` takes a multipart form, the same one the Tauri app posts. +# `/api/desktop/logs` takes a multipart form, the same one 0.6.0 posted. bytes = "1" reqwest = { version = "0.12", default-features = false, features = [ "json", @@ -174,9 +173,8 @@ reqwest = { version = "0.12", default-features = false, features = [ futures-util = "0.3" dirs = "6" dunce = "1.0.5" -# Caption transcription (`src/transcription.rs`): the exact engine pin the -# Tauri app carries (`apps/desktop/src-tauri/Cargo.toml:75`), so a model file -# downloaded by either app loads identically in both. +# Caption transcription (`src/transcription.rs`): the engine pin 0.6.0 +# shipped, so model files it downloaded keep loading identically. whisper-rs = "0.11.0" [build-dependencies] @@ -273,8 +271,8 @@ block2 = "0.6" raw-window-handle = "0.6" core-foundation = "0.10" core-video = { version = "0.5.2", features = ["metal"] } -# ScreenCaptureKit shareable content, acquired the same way recording.rs in -# src-tauri does. Same fork/rev/features as the root workspace. +# ScreenCaptureKit shareable content. Same fork/rev/features as the root +# workspace. cidre = { git = "https://github.com/CapSoftware/cidre", rev = "bf84b67079a8", features = [ "macos_12_7", "cv", @@ -292,7 +290,6 @@ cidre = { git = "https://github.com/CapSoftware/cidre", rev = "bf84b67079a8", fe "vn", ], default-features = false } -# The Tauri app's own target gate (`apps/desktop/src-tauri/Cargo.toml:151-152`): # parakeet-rs has no Intel-macOS ONNX Runtime build, so those Macs get the # Whisper caption models only. [target.'cfg(not(all(target_os = "macos", target_arch = "x86_64")))'.dependencies] diff --git a/apps/desktop-gpui/README.md b/apps/desktop-gpui/README.md index 6830cfa41ff..13093e19179 100644 --- a/apps/desktop-gpui/README.md +++ b/apps/desktop-gpui/README.md @@ -3,9 +3,9 @@ Cap's desktop app, rewritten in [gpui](https://www.gpui.rs/). No Tauri, no webview — the whole UI is drawn by gpui and every pixel is Rust. -This is the app that ships as **Cap**, from 0.6.1 on. The Tauri app in -`apps/desktop` last shipped in 0.6.0 and is kept only for the dev harness; see -[Shipping and updates](#shipping-and-updates). +This is the app that ships as **Cap**, from 0.6.1 on, and the only desktop app +in this repository. It replaced the Tauri app, which last shipped in 0.6.0; see +[Shipping and updates](#shipping-and-updates) and [The Tauri app](#the-tauri-app). The main recording window uses a fixed 330×432 layout with device controls and recording and screenshot browsers. The expanded view is no longer available. @@ -43,8 +43,10 @@ behind a plain-slice function and call that from the app. ./dev.sh ``` -`bun run dev:desktop` (from the repo root) starts this loop automatically next -to the Tauri app, output prefixed `[gpui]`; set `CAP_GPUI_DEV=0` to opt out +`bun run dev:desktop` from the repo root runs `bun run cap-setup`, checks out +the patched gpui next to the repository (`scripts/prepare-gpui-dependency.sh`) +and starts this loop. The loop needs macOS (BSD `stat` and `md5`); on Windows +and Linux the same command builds and runs the app once (`scripts/dev-desktop.mjs`). Native Rust cannot hot-reload, so this is the Solid-dev-server feel rebuilt @@ -67,15 +69,17 @@ by hand: switching between `./dev.sh` and `cargo build` rebuilds nothing. ### Why it is a separate workspace -`Cargo.toml` declares its own `[workspace]`. The root workspace carries -`[patch.crates-io]` entries — a vendored `wgpu-hal`, a forked `tao` — that exist -only for the Tauri app and that gpui's tree does not want. Nesting a second -workspace here leaves the root `Cargo.lock`, the `cargo hakari` workspace-hack -and CI completely untouched. +`Cargo.toml` declares its own `[workspace]`. gpui's dependency tree is enormous +and pins its own git revisions of the wgpu and font stacks, and the root +workspace's `[patch.crates-io]` entries (forked `reqwest` and `cidre`) are not +ones that tree wants. Nesting a second workspace keeps the root `Cargo.lock` +and the `cargo hakari` workspace-hack independent of it. The vendored +`wgpu-hal` is patched in both workspaces. `rust-toolchain.toml` pins `stable` rather than the root's 1.88.0, because -gpui's dependencies need 1.89+ (`smol_str` 0.3.6, `cosmic-text` 0.19). The -nearest toolchain file wins, so the Tauri app is unaffected. +gpui's dependencies need 1.89+ (`smol_str` 0.3.6, `cosmic-text` 0.19). CI and +release builds use 1.95.0 explicitly. The nearest toolchain file wins, so the +CLI and the shared crates keep building on 1.88.0. ## Shipping and updates @@ -144,12 +148,22 @@ while a recording, export, upload, import or transcription is running. ### The Tauri app -Releases no longer build the Tauri app. 0.6.0 was its last version, and the -website's [all versions](https://cap.so/download/versions) page keeps it -downloadable. In a debug build started from `target/`, Settings → Experimental -still has the **Cap GPUI** switch that hands the session back to the Tauri -app running under `bun run dev:desktop`, through the dev supervisor -(`store::request_classic_reopen` and `cap-classic.pending`). +0.6.0 was the last release of the Tauri app, and the website's +[all versions](https://cap.so/download/versions) page keeps it downloadable. +Its source (`apps/desktop`, with the shared Solid UI in `packages/ui-solid`) +was removed from the repository after 0.6.2 and stays browsable at +[`cap-v0.6.2`](https://github.com/CapSoftware/Cap/tree/cap-v0.6.2/apps/desktop). + +This app was built as a 1:1 port of it, so these notes and many comments in +`src/` cite its files: `*.tsx` routes and components, `apps/desktop/...`, +`packages/ui-solid/...`, often with line numbers. Those references all point +at that tag. + +The formats it defined are still live: the `store` file in the app-data +directory (its `general_settings`, `auth` and other sections), the +`so.cap.desktop` identifier, the `cap-desktop` deep-link scheme and the +updater key and endpoint. 0.6.0 installs update +straight into this app and keep their recordings and settings. ## What is implemented @@ -1046,7 +1060,7 @@ Settings-specific deviations: | **Settings does not park the other windows** | `ShowCapWindow::Settings::show` also calls `hide_recording_windows` and `release_camera_preview_if_idle`, and its close calls `restore_camera_window`. Neither half is reproduced — the gear hides the main window and nothing else. | | **Several settings persist without a consumer** | `hideDockIcon`, `enableNotifications`, the countdown, the post-recording behaviours and the update channel write the same store keys as Tauri; the machinery that would obey them is not built yet. Theme is applied. | | **No confirm on the recordings folder move** | `pickRecordingsFolder` offers to migrate existing recordings afterwards; here the path is written and nothing is moved. | -| **Version is this crate's** | The sidebar footer shows the crate version from `CARGO_PKG_VERSION` (kept in lockstep with the Tauri app by `scripts/sync-desktop-versions.mjs`), not `getVersion()`. "Check for updates" runs the native updater and shows its download progress in place. | +| **Version is this crate's** | The sidebar footer shows the crate version from `CARGO_PKG_VERSION` (the bundled CLI is kept in lockstep with it by `scripts/sync-desktop-versions.mjs`), not `getVersion()`. "Check for updates" runs the native updater and shows its download progress in place. | ## Mode select diff --git a/apps/desktop/src-tauri/assets/backgrounds/blue/1-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/blue/1-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/blue/1-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/blue/1-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/blue/1.jpg b/apps/desktop-gpui/assets/backgrounds/blue/1.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/blue/1.jpg rename to apps/desktop-gpui/assets/backgrounds/blue/1.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/blue/2-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/blue/2-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/blue/2-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/blue/2-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/blue/2.jpg b/apps/desktop-gpui/assets/backgrounds/blue/2.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/blue/2.jpg rename to apps/desktop-gpui/assets/backgrounds/blue/2.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/blue/3-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/blue/3-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/blue/3-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/blue/3-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/blue/3.jpg b/apps/desktop-gpui/assets/backgrounds/blue/3.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/blue/3.jpg rename to apps/desktop-gpui/assets/backgrounds/blue/3.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/blue/4-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/blue/4-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/blue/4-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/blue/4-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/blue/4.jpg b/apps/desktop-gpui/assets/backgrounds/blue/4.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/blue/4.jpg rename to apps/desktop-gpui/assets/backgrounds/blue/4.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/blue/5-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/blue/5-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/blue/5-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/blue/5-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/blue/5.jpg b/apps/desktop-gpui/assets/backgrounds/blue/5.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/blue/5.jpg rename to apps/desktop-gpui/assets/backgrounds/blue/5.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/blue/6-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/blue/6-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/blue/6-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/blue/6-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/blue/6.jpg b/apps/desktop-gpui/assets/backgrounds/blue/6.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/blue/6.jpg rename to apps/desktop-gpui/assets/backgrounds/blue/6.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/cities/liverpool-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/cities/liverpool-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/cities/liverpool-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/cities/liverpool-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/cities/liverpool.jpg b/apps/desktop-gpui/assets/backgrounds/cities/liverpool.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/cities/liverpool.jpg rename to apps/desktop-gpui/assets/backgrounds/cities/liverpool.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/cities/london-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/cities/london-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/cities/london-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/cities/london-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/cities/london.jpg b/apps/desktop-gpui/assets/backgrounds/cities/london.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/cities/london.jpg rename to apps/desktop-gpui/assets/backgrounds/cities/london.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/cities/miami-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/cities/miami-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/cities/miami-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/cities/miami-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/cities/miami.jpg b/apps/desktop-gpui/assets/backgrounds/cities/miami.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/cities/miami.jpg rename to apps/desktop-gpui/assets/backgrounds/cities/miami.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/cities/monaco-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/cities/monaco-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/cities/monaco-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/cities/monaco-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/cities/monaco.jpg b/apps/desktop-gpui/assets/backgrounds/cities/monaco.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/cities/monaco.jpg rename to apps/desktop-gpui/assets/backgrounds/cities/monaco.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/cities/nyc-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/cities/nyc-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/cities/nyc-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/cities/nyc-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/cities/nyc.jpg b/apps/desktop-gpui/assets/backgrounds/cities/nyc.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/cities/nyc.jpg rename to apps/desktop-gpui/assets/backgrounds/cities/nyc.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/cities/rome-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/cities/rome-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/cities/rome-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/cities/rome-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/cities/rome.jpg b/apps/desktop-gpui/assets/backgrounds/cities/rome.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/cities/rome.jpg rename to apps/desktop-gpui/assets/backgrounds/cities/rome.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/cities/santorini-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/cities/santorini-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/cities/santorini-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/cities/santorini-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/cities/santorini.jpg b/apps/desktop-gpui/assets/backgrounds/cities/santorini.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/cities/santorini.jpg rename to apps/desktop-gpui/assets/backgrounds/cities/santorini.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/cities/sf-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/cities/sf-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/cities/sf-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/cities/sf-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/cities/sf.jpg b/apps/desktop-gpui/assets/backgrounds/cities/sf.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/cities/sf.jpg rename to apps/desktop-gpui/assets/backgrounds/cities/sf.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/dark/1-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/dark/1-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/dark/1-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/dark/1-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/dark/1.jpg b/apps/desktop-gpui/assets/backgrounds/dark/1.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/dark/1.jpg rename to apps/desktop-gpui/assets/backgrounds/dark/1.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/dark/2-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/dark/2-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/dark/2-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/dark/2-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/dark/2.jpg b/apps/desktop-gpui/assets/backgrounds/dark/2.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/dark/2.jpg rename to apps/desktop-gpui/assets/backgrounds/dark/2.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/dark/3-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/dark/3-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/dark/3-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/dark/3-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/dark/3.jpg b/apps/desktop-gpui/assets/backgrounds/dark/3.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/dark/3.jpg rename to apps/desktop-gpui/assets/backgrounds/dark/3.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/dark/4-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/dark/4-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/dark/4-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/dark/4-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/dark/4.jpg b/apps/desktop-gpui/assets/backgrounds/dark/4.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/dark/4.jpg rename to apps/desktop-gpui/assets/backgrounds/dark/4.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/dark/5-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/dark/5-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/dark/5-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/dark/5-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/dark/5.jpg b/apps/desktop-gpui/assets/backgrounds/dark/5.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/dark/5.jpg rename to apps/desktop-gpui/assets/backgrounds/dark/5.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/dark/6-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/dark/6-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/dark/6-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/dark/6-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/dark/6.jpg b/apps/desktop-gpui/assets/backgrounds/dark/6.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/dark/6.jpg rename to apps/desktop-gpui/assets/backgrounds/dark/6.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/sequoia-dark-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/sequoia-dark-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/sequoia-dark-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/sequoia-dark-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/sequoia-dark.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/sequoia-dark.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/sequoia-dark.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/sequoia-dark.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/sequoia-light-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/sequoia-light-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/sequoia-light-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/sequoia-light-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/sequoia-light.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/sequoia-light.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/sequoia-light.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/sequoia-light.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-clouds-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/sonoma-clouds-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-clouds-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/sonoma-clouds-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-clouds.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/sonoma-clouds.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-clouds.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/sonoma-clouds.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-dark-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/sonoma-dark-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-dark-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/sonoma-dark-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-dark.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/sonoma-dark.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-dark.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/sonoma-dark.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-evening-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/sonoma-evening-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-evening-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/sonoma-evening-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-evening.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/sonoma-evening.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-evening.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/sonoma-evening.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-fromabove-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/sonoma-fromabove-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-fromabove-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/sonoma-fromabove-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-fromabove.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/sonoma-fromabove.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-fromabove.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/sonoma-fromabove.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-horizon-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/sonoma-horizon-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-horizon-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/sonoma-horizon-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-horizon.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/sonoma-horizon.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-horizon.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/sonoma-horizon.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-light-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/sonoma-light-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-light-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/sonoma-light-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-light.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/sonoma-light.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-light.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/sonoma-light.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-river-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/sonoma-river-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-river-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/sonoma-river-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-river.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/sonoma-river.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/sonoma-river.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/sonoma-river.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-dark-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/tahoe-dark-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-dark-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/tahoe-dark-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-dark.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/tahoe-dark.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-dark.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/tahoe-dark.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-dawn-min-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/tahoe-dawn-min-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-dawn-min-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/tahoe-dawn-min-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-dawn-min.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/tahoe-dawn-min.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-dawn-min.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/tahoe-dawn-min.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-day-min-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/tahoe-day-min-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-day-min-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/tahoe-day-min-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-day-min.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/tahoe-day-min.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-day-min.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/tahoe-day-min.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-dusk-min-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/tahoe-dusk-min-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-dusk-min-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/tahoe-dusk-min-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-dusk-min.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/tahoe-dusk-min.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-dusk-min.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/tahoe-dusk-min.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-light-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/tahoe-light-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-light-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/tahoe-light-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-light.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/tahoe-light.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-light.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/tahoe-light.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-night-min-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/tahoe-night-min-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-night-min-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/tahoe-night-min-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-night-min.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/tahoe-night-min.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/tahoe-night-min.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/tahoe-night-min.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/ventura-dark-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/ventura-dark-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/ventura-dark-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/ventura-dark-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/ventura-dark.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/ventura-dark.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/ventura-dark.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/ventura-dark.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/ventura-semi-dark-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/ventura-semi-dark-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/ventura-semi-dark-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/ventura-semi-dark-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/ventura-semi-dark.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/ventura-semi-dark.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/ventura-semi-dark.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/ventura-semi-dark.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/ventura-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/ventura-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/ventura-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/ventura-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/macOS/ventura.jpg b/apps/desktop-gpui/assets/backgrounds/macOS/ventura.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/macOS/ventura.jpg rename to apps/desktop-gpui/assets/backgrounds/macOS/ventura.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/orange/1-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/orange/1-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/orange/1-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/orange/1-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/orange/1.jpg b/apps/desktop-gpui/assets/backgrounds/orange/1.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/orange/1.jpg rename to apps/desktop-gpui/assets/backgrounds/orange/1.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/orange/2-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/orange/2-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/orange/2-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/orange/2-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/orange/2.jpg b/apps/desktop-gpui/assets/backgrounds/orange/2.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/orange/2.jpg rename to apps/desktop-gpui/assets/backgrounds/orange/2.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/orange/3-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/orange/3-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/orange/3-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/orange/3-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/orange/3.jpg b/apps/desktop-gpui/assets/backgrounds/orange/3.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/orange/3.jpg rename to apps/desktop-gpui/assets/backgrounds/orange/3.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/orange/4-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/orange/4-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/orange/4-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/orange/4-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/orange/4.jpg b/apps/desktop-gpui/assets/backgrounds/orange/4.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/orange/4.jpg rename to apps/desktop-gpui/assets/backgrounds/orange/4.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/orange/5-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/orange/5-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/orange/5-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/orange/5-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/orange/5.jpg b/apps/desktop-gpui/assets/backgrounds/orange/5.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/orange/5.jpg rename to apps/desktop-gpui/assets/backgrounds/orange/5.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/orange/6-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/orange/6-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/orange/6-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/orange/6-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/orange/6.jpg b/apps/desktop-gpui/assets/backgrounds/orange/6.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/orange/6.jpg rename to apps/desktop-gpui/assets/backgrounds/orange/6.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/orange/7-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/orange/7-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/orange/7-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/orange/7-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/orange/7.jpg b/apps/desktop-gpui/assets/backgrounds/orange/7.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/orange/7.jpg rename to apps/desktop-gpui/assets/backgrounds/orange/7.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/orange/8-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/orange/8-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/orange/8-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/orange/8-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/orange/8.jpg b/apps/desktop-gpui/assets/backgrounds/orange/8.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/orange/8.jpg rename to apps/desktop-gpui/assets/backgrounds/orange/8.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/orange/9-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/orange/9-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/orange/9-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/orange/9-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/orange/9.jpg b/apps/desktop-gpui/assets/backgrounds/orange/9.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/orange/9.jpg rename to apps/desktop-gpui/assets/backgrounds/orange/9.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/purple/1-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/purple/1-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/purple/1-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/purple/1-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/purple/1.jpg b/apps/desktop-gpui/assets/backgrounds/purple/1.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/purple/1.jpg rename to apps/desktop-gpui/assets/backgrounds/purple/1.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/purple/2-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/purple/2-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/purple/2-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/purple/2-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/purple/2.jpg b/apps/desktop-gpui/assets/backgrounds/purple/2.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/purple/2.jpg rename to apps/desktop-gpui/assets/backgrounds/purple/2.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/purple/3-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/purple/3-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/purple/3-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/purple/3-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/purple/3.jpg b/apps/desktop-gpui/assets/backgrounds/purple/3.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/purple/3.jpg rename to apps/desktop-gpui/assets/backgrounds/purple/3.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/purple/4-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/purple/4-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/purple/4-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/purple/4-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/purple/4.jpg b/apps/desktop-gpui/assets/backgrounds/purple/4.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/purple/4.jpg rename to apps/desktop-gpui/assets/backgrounds/purple/4.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/purple/5-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/purple/5-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/purple/5-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/purple/5-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/purple/5.jpg b/apps/desktop-gpui/assets/backgrounds/purple/5.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/purple/5.jpg rename to apps/desktop-gpui/assets/backgrounds/purple/5.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/purple/6-thumbnail.jpg b/apps/desktop-gpui/assets/backgrounds/purple/6-thumbnail.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/purple/6-thumbnail.jpg rename to apps/desktop-gpui/assets/backgrounds/purple/6-thumbnail.jpg diff --git a/apps/desktop/src-tauri/assets/backgrounds/purple/6.jpg b/apps/desktop-gpui/assets/backgrounds/purple/6.jpg similarity index 100% rename from apps/desktop/src-tauri/assets/backgrounds/purple/6.jpg rename to apps/desktop-gpui/assets/backgrounds/purple/6.jpg diff --git a/apps/desktop/src/assets/music/ambient-trap-empty-streets-dreamstate-openmindaudio.mp3 b/apps/desktop-gpui/assets/music/ambient-trap-empty-streets-dreamstate-openmindaudio.mp3 similarity index 100% rename from apps/desktop/src/assets/music/ambient-trap-empty-streets-dreamstate-openmindaudio.mp3 rename to apps/desktop-gpui/assets/music/ambient-trap-empty-streets-dreamstate-openmindaudio.mp3 diff --git a/apps/desktop/src/assets/music/cassette-retrositive.mp3 b/apps/desktop-gpui/assets/music/cassette-retrositive.mp3 similarity index 100% rename from apps/desktop/src/assets/music/cassette-retrositive.mp3 rename to apps/desktop-gpui/assets/music/cassette-retrositive.mp3 diff --git a/apps/desktop/src/assets/music/good-night-lofi-cozy-chill-fassounds.mp3 b/apps/desktop-gpui/assets/music/good-night-lofi-cozy-chill-fassounds.mp3 similarity index 100% rename from apps/desktop/src/assets/music/good-night-lofi-cozy-chill-fassounds.mp3 rename to apps/desktop-gpui/assets/music/good-night-lofi-cozy-chill-fassounds.mp3 diff --git a/apps/desktop/src/assets/music/lofi-beats-mirostar.mp3 b/apps/desktop-gpui/assets/music/lofi-beats-mirostar.mp3 similarity index 100% rename from apps/desktop/src/assets/music/lofi-beats-mirostar.mp3 rename to apps/desktop-gpui/assets/music/lofi-beats-mirostar.mp3 diff --git a/apps/desktop/src/assets/music/lofi-cinematic-pulsebox.mp3 b/apps/desktop-gpui/assets/music/lofi-cinematic-pulsebox.mp3 similarity index 100% rename from apps/desktop/src/assets/music/lofi-cinematic-pulsebox.mp3 rename to apps/desktop-gpui/assets/music/lofi-cinematic-pulsebox.mp3 diff --git a/apps/desktop/src/assets/music/lofi-hip-hop-leberch.mp3 b/apps/desktop-gpui/assets/music/lofi-hip-hop-leberch.mp3 similarity index 100% rename from apps/desktop/src/assets/music/lofi-hip-hop-leberch.mp3 rename to apps/desktop-gpui/assets/music/lofi-hip-hop-leberch.mp3 diff --git a/apps/desktop/src/assets/music/lofi-smooth-pulsebox.mp3 b/apps/desktop-gpui/assets/music/lofi-smooth-pulsebox.mp3 similarity index 100% rename from apps/desktop/src/assets/music/lofi-smooth-pulsebox.mp3 rename to apps/desktop-gpui/assets/music/lofi-smooth-pulsebox.mp3 diff --git a/apps/desktop/src/assets/music/lofi-study-calm-peaceful-chill-hop-fassounds.mp3 b/apps/desktop-gpui/assets/music/lofi-study-calm-peaceful-chill-hop-fassounds.mp3 similarity index 100% rename from apps/desktop/src/assets/music/lofi-study-calm-peaceful-chill-hop-fassounds.mp3 rename to apps/desktop-gpui/assets/music/lofi-study-calm-peaceful-chill-hop-fassounds.mp3 diff --git a/apps/desktop/src/assets/music/raindrops-lofi-sleep-bluelike.mp3 b/apps/desktop-gpui/assets/music/raindrops-lofi-sleep-bluelike.mp3 similarity index 100% rename from apps/desktop/src/assets/music/raindrops-lofi-sleep-bluelike.mp3 rename to apps/desktop-gpui/assets/music/raindrops-lofi-sleep-bluelike.mp3 diff --git a/apps/desktop/src/assets/music/sunday-mood-lofi-cafe-upbeat-bluelike.mp3 b/apps/desktop-gpui/assets/music/sunday-mood-lofi-cafe-upbeat-bluelike.mp3 similarity index 100% rename from apps/desktop/src/assets/music/sunday-mood-lofi-cafe-upbeat-bluelike.mp3 rename to apps/desktop-gpui/assets/music/sunday-mood-lofi-cafe-upbeat-bluelike.mp3 diff --git a/packages/ui-solid/icons/cursor-macos.svg b/apps/desktop-gpui/assets/onboarding/cursor-macos.svg similarity index 100% rename from packages/ui-solid/icons/cursor-macos.svg rename to apps/desktop-gpui/assets/onboarding/cursor-macos.svg diff --git a/packages/ui-solid/icons/cursor-windows.svg b/apps/desktop-gpui/assets/onboarding/cursor-windows.svg similarity index 100% rename from packages/ui-solid/icons/cursor-windows.svg rename to apps/desktop-gpui/assets/onboarding/cursor-windows.svg diff --git a/apps/desktop/src/assets/tears-and-fireflies-adi-goldstein.mp3 b/apps/desktop-gpui/assets/onboarding/tears-and-fireflies-adi-goldstein.mp3 similarity index 100% rename from apps/desktop/src/assets/tears-and-fireflies-adi-goldstein.mp3 rename to apps/desktop-gpui/assets/onboarding/tears-and-fireflies-adi-goldstein.mp3 diff --git a/apps/desktop/src-tauri/sounds/action.ogg b/apps/desktop-gpui/assets/sounds/action.ogg similarity index 100% rename from apps/desktop/src-tauri/sounds/action.ogg rename to apps/desktop-gpui/assets/sounds/action.ogg diff --git a/apps/desktop/src-tauri/sounds/start-recording.ogg b/apps/desktop-gpui/assets/sounds/start-recording.ogg similarity index 100% rename from apps/desktop/src-tauri/sounds/start-recording.ogg rename to apps/desktop-gpui/assets/sounds/start-recording.ogg diff --git a/apps/desktop/src-tauri/sounds/stop-recording.ogg b/apps/desktop-gpui/assets/sounds/stop-recording.ogg similarity index 100% rename from apps/desktop/src-tauri/sounds/stop-recording.ogg rename to apps/desktop-gpui/assets/sounds/stop-recording.ogg diff --git a/apps/desktop/src-tauri/icons/tray-default-icon.png b/apps/desktop-gpui/assets/tray/tray-default-icon.png similarity index 100% rename from apps/desktop/src-tauri/icons/tray-default-icon.png rename to apps/desktop-gpui/assets/tray/tray-default-icon.png diff --git a/apps/desktop/src-tauri/binaries/.gitignore b/apps/desktop-gpui/binaries/.gitignore similarity index 100% rename from apps/desktop/src-tauri/binaries/.gitignore rename to apps/desktop-gpui/binaries/.gitignore diff --git a/apps/desktop-gpui/build.rs b/apps/desktop-gpui/build.rs index 151c6bf353a..1a417c62433 100644 --- a/apps/desktop-gpui/build.rs +++ b/apps/desktop-gpui/build.rs @@ -22,7 +22,7 @@ fn main() { println!("cargo:rustc-link-arg-bin=cap-gpui=/STACK:16777216"); } - let icon = "../desktop/src-tauri/icons/icon.ico"; + let icon = "icons/icon.ico"; println!("cargo:rerun-if-changed={icon}"); tauri_winres::WindowsResource::new() .set_icon_with_id(icon, "1") diff --git a/apps/desktop-gpui/dev.sh b/apps/desktop-gpui/dev.sh index c073cd6239d..39157e45883 100755 --- a/apps/desktop-gpui/dev.sh +++ b/apps/desktop-gpui/dev.sh @@ -10,7 +10,7 @@ STATE_FILE="$PWD/target/dev-restore.json" BIN="$PWD/target/debug/cap-gpui" BUILD=cargo -WATCH_PATHS=(src kernels/src kernels/Cargo.toml i18n-build/src i18n-build/Cargo.toml locales assets Cargo.toml ../desktop/src-tauri/sounds) +WATCH_PATHS=(src kernels/src kernels/Cargo.toml i18n-build/src i18n-build/Cargo.toml locales assets Cargo.toml) [ -d resources ] && WATCH_PATHS+=(resources) for crate in camera scap-targets recording timestamp utils project rendering editor export; do [ -d "../../crates/$crate/src" ] && WATCH_PATHS+=("../../crates/$crate/src") @@ -27,22 +27,6 @@ fingerprint() { APP_PID="" -SHARED_DIR="$HOME/Library/Application Support/so.cap.desktop" - -# Launching unconditionally would put this app on screen next to the classic -# one every session: under the experimental switch the two share ownership of -# the session (`enableGpuiApp` in the shared store), so a build only launches -# when this app owns it or an instance is already running (a rebuild swap). -gpui_owns_session() { - grep -Eq '"enableGpuiApp":[[:space:]]*true' "$SHARED_DIR/store" 2>/dev/null -} - -instance_live() { - local pid - pid=$(cat "$SHARED_DIR/cap-gpui.pid" 2>/dev/null) || return 1 - [ -n "$pid" ] && ps -p "$pid" -o comm= 2>/dev/null | grep -q cap-gpui -} - stop_app() { [ -n "$APP_PID" ] || return 0 if ! kill -0 "$APP_PID" 2>/dev/null; then @@ -80,12 +64,8 @@ while true; do LAST="$CURRENT" echo "[dev] building..." if "$BUILD" build; then - if [ -n "$APP_PID" ] || gpui_owns_session || instance_live; then - stop_app - start_app - else - echo "[dev] built; not launching (the classic app owns the session)" - fi + stop_app + start_app else echo "[dev] build failed; keeping the previous app running" fi diff --git a/apps/desktop/src-tauri/icons/128x128.png b/apps/desktop-gpui/icons/128x128.png similarity index 100% rename from apps/desktop/src-tauri/icons/128x128.png rename to apps/desktop-gpui/icons/128x128.png diff --git a/apps/desktop/src-tauri/icons/128x128@2x.png b/apps/desktop-gpui/icons/128x128@2x.png similarity index 100% rename from apps/desktop/src-tauri/icons/128x128@2x.png rename to apps/desktop-gpui/icons/128x128@2x.png diff --git a/apps/desktop/src-tauri/icons/32x32.png b/apps/desktop-gpui/icons/32x32.png similarity index 100% rename from apps/desktop/src-tauri/icons/32x32.png rename to apps/desktop-gpui/icons/32x32.png diff --git a/apps/desktop/src-tauri/icons/Square310x310Logo.png b/apps/desktop-gpui/icons/Square310x310Logo.png similarity index 100% rename from apps/desktop/src-tauri/icons/Square310x310Logo.png rename to apps/desktop-gpui/icons/Square310x310Logo.png diff --git a/apps/desktop/src-tauri/icons/icon.ico b/apps/desktop-gpui/icons/icon.ico similarity index 100% rename from apps/desktop/src-tauri/icons/icon.ico rename to apps/desktop-gpui/icons/icon.ico diff --git a/apps/desktop/src-tauri/icons/icon.png b/apps/desktop-gpui/icons/icon.png similarity index 100% rename from apps/desktop/src-tauri/icons/icon.png rename to apps/desktop-gpui/icons/icon.png diff --git a/apps/desktop/src-tauri/icons/macos/icon.icns b/apps/desktop-gpui/icons/macos/icon.icns similarity index 100% rename from apps/desktop/src-tauri/icons/macos/icon.icns rename to apps/desktop-gpui/icons/macos/icon.icns diff --git a/apps/desktop-gpui/locales/de.toml b/apps/desktop-gpui/locales/de.toml index 186c6c912e8..20701865b6e 100644 --- a/apps/desktop-gpui/locales/de.toml +++ b/apps/desktop-gpui/locales/de.toml @@ -544,27 +544,10 @@ terms_title = "Gemerkte Begriffe" title = "Transkription" [settings.experimental] -developer = "Entwickler" -developer_description = "Wird nur in Entwicklungs-Builds angezeigt." muxer = "Muxer in separatem Prozess" muxer_description = "Führt den Muxer für fragmentiertes MP4 in einem isolierten Unterprozess aus, damit Muxer-Abstürze Ihre Aufnahme nicht beenden. Erfordert das mitgelieferte Programm cap-muxer." -native_app = "Native App verwenden" -native_app_description = "Ausschalten, um diese App zu schließen und die klassische Tauri-App in der Entwicklungsumgebung wieder zu öffnen. Aufnahmen und Einstellungen werden geteilt." reliability = "Zuverlässigkeit" -[settings.experimental.switch] -busy = "Schließen Sie Ihre Aufnahme, den Export, Upload, Import oder die Transkription ab, bevor Sie zur klassischen App wechseln." -check_failed = "Es konnte nicht geprüft werden, ob die klassische Cap-App geöffnet wurde: {error}" -data_stays = "Ihre Aufnahmen und Einstellungen bleiben genau dort, wo sie sind." -failed = "Die klassische Cap-App konnte nicht geöffnet werden." -not_found = "Die klassische Cap-App, zu der gewechselt werden soll, wurde nicht gefunden." -open_failed = "Die klassische Cap-App konnte nicht geöffnet werden: {error}" -opening = "Die klassische Cap-App wird geöffnet" -opening_detail = "Dieses Fenster wird geschlossen, sobald die klassische Cap-App bereit ist." -save_failed = "Ihre App-Einstellung konnte nicht gespeichert werden. Cap bleibt geöffnet." -switching = "Es wird zur klassischen Cap-App zurückgewechselt." -timed_out = "Die klassische App wurde nicht geöffnet. Prüfen Sie das Entwicklungsterminal auf Build-Fehler und versuchen Sie es dann erneut." - [settings.feedback] app_version = "App-Version" capture_support = "Aufnahmeunterstützung" @@ -960,7 +943,6 @@ name = "Benachrichtigen, wenn ein Upload fertig ist" description = "Den Link zum Teilen an Slack, Discord oder Ihren eigenen Webhook senden." name = "Slack beim Teilen benachrichtigen" - [main] delete_recording_confirm = "Möchten Sie diese Aufnahme wirklich löschen?" delete_screenshot_confirm = "Möchten Sie dieses Bildschirmfoto wirklich löschen?" diff --git a/apps/desktop-gpui/locales/en.toml b/apps/desktop-gpui/locales/en.toml index adc646a6803..ff6f72e44b1 100644 --- a/apps/desktop-gpui/locales/en.toml +++ b/apps/desktop-gpui/locales/en.toml @@ -546,27 +546,10 @@ terms_title = "Remembered terms" title = "Transcription" [settings.experimental] -developer = "Developer" -developer_description = "Only shown in development builds." muxer = "Out-of-process muxer" muxer_description = "Run the fragmented-MP4 muxer in an isolated subprocess so muxer crashes can't take down your recording. Requires the bundled cap-muxer binary." -native_app = "Use native app" -native_app_description = "Turn off to close this app and reopen the classic Tauri app in the dev harness. Recordings and settings are shared." reliability = "Reliability" -[settings.experimental.switch] -busy = "Finish your recording, export, upload, import, or transcription task before switching to the classic app." -check_failed = { text = "Couldn't check whether the classic Cap app opened: {error}", context = "{error} is a technical error message, usually in English." } -data_stays = "Your recordings and settings stay exactly where they are." -failed = "Couldn't open the classic Cap app." -not_found = "Couldn't find the classic Cap app to switch back to." -open_failed = { text = "Couldn't open the classic Cap app: {error}", context = "{error} is a technical error message, usually in English." } -opening = "Opening the classic Cap app" -opening_detail = "This window will close when the classic Cap app is ready." -save_failed = "Couldn't save your app preference. Cap is still open." -switching = "Switching back to the classic Cap app." -timed_out = "The classic app hasn't opened. Check the dev terminal for build errors, then try again." - [settings.feedback] app_version = "App Version" capture_support = "Capture Support" @@ -962,7 +945,6 @@ name = "Ping me when an upload is ready" description = "Send the share link to Slack, Discord, or your own webhook." name = "Tell Slack when you share something" - [main] delete_recording_confirm = "Are you sure you want to delete this recording?" delete_screenshot_confirm = "Are you sure you want to delete this screenshot?" diff --git a/apps/desktop-gpui/locales/es.toml b/apps/desktop-gpui/locales/es.toml index c0b5f57b038..3156d6cb740 100644 --- a/apps/desktop-gpui/locales/es.toml +++ b/apps/desktop-gpui/locales/es.toml @@ -544,27 +544,10 @@ terms_title = "Términos guardados" title = "Transcripción" [settings.experimental] -developer = "Desarrollador" -developer_description = "Solo se muestra en las compilaciones de desarrollo." muxer = "Multiplexor fuera de proceso" muxer_description = "Ejecuta el multiplexor de MP4 fragmentado en un subproceso aislado para que sus fallos no arruinen tu grabación. Requiere el binario cap-muxer incluido." -native_app = "Usar la app nativa" -native_app_description = "Desactívalo para cerrar esta app y volver a abrir la app Tauri clásica en el entorno de desarrollo. Las grabaciones y los ajustes se comparten." reliability = "Fiabilidad" -[settings.experimental.switch] -busy = "Termina la grabación, exportación, subida, importación o transcripción antes de cambiar a la app clásica." -check_failed = "No se pudo comprobar si la app clásica de Cap se abrió: {error}" -data_stays = "Tus grabaciones y ajustes se quedan exactamente donde están." -failed = "No se pudo abrir la app clásica de Cap." -not_found = "No se encontró la app clásica de Cap a la que volver." -open_failed = "No se pudo abrir la app clásica de Cap: {error}" -opening = "Abriendo la app clásica de Cap" -opening_detail = "Esta ventana se cerrará cuando la app clásica de Cap esté lista." -save_failed = "No se pudo guardar tu preferencia de app. Cap sigue abierto." -switching = "Volviendo a la app clásica de Cap." -timed_out = "La app clásica no se ha abierto. Revisa los errores de compilación en la terminal de desarrollo y vuelve a intentarlo." - [settings.feedback] app_version = "Versión de la app" capture_support = "Compatibilidad de captura" @@ -960,7 +943,6 @@ name = "Avisarme cuando una subida esté lista" description = "Envía el enlace para compartir a Slack, Discord o tu propio webhook." name = "Avisar a Slack cuando compartas algo" - [main] delete_recording_confirm = "¿Seguro que quieres eliminar esta grabación?" delete_screenshot_confirm = "¿Seguro que quieres eliminar esta captura de pantalla?" diff --git a/apps/desktop-gpui/locales/fr.toml b/apps/desktop-gpui/locales/fr.toml index dee8942f499..16385c4743d 100644 --- a/apps/desktop-gpui/locales/fr.toml +++ b/apps/desktop-gpui/locales/fr.toml @@ -544,27 +544,10 @@ terms_title = "Termes mémorisés" title = "Transcription" [settings.experimental] -developer = "Développeur" -developer_description = "Affiché uniquement dans les versions de développement." muxer = "Multiplexeur hors processus" muxer_description = "Exécute le multiplexeur MP4 fragmenté dans un sous-processus isolé pour que ses plantages ne fassent pas échouer votre enregistrement. Nécessite le binaire cap-muxer fourni." -native_app = "Utiliser l'app native" -native_app_description = "Désactivez pour fermer cette app et rouvrir l'app Tauri classique dans l'environnement de développement. Les enregistrements et les paramètres sont partagés." reliability = "Fiabilité" -[settings.experimental.switch] -busy = "Terminez votre enregistrement, exportation, mise en ligne, importation ou transcription avant de passer à l'app classique." -check_failed = "Impossible de vérifier si l'app Cap classique s'est ouverte : {error}" -data_stays = "Vos enregistrements et vos paramètres restent exactement où ils sont." -failed = "Impossible d'ouvrir l'app Cap classique." -not_found = "Impossible de trouver l'app Cap classique vers laquelle revenir." -open_failed = "Impossible d'ouvrir l'app Cap classique : {error}" -opening = "Ouverture de l'app Cap classique" -opening_detail = "Cette fenêtre se fermera quand l'app Cap classique sera prête." -save_failed = "Impossible d'enregistrer votre préférence d'app. Cap reste ouvert." -switching = "Retour à l'app Cap classique." -timed_out = "L'app classique ne s'est pas ouverte. Vérifiez les erreurs de compilation dans le terminal de développement, puis réessayez." - [settings.feedback] app_version = "Version de l'app" capture_support = "Prise en charge de la capture" @@ -960,7 +943,6 @@ name = "Me prévenir quand une mise en ligne est prête" description = "Envoyez le lien de partage à Slack, Discord ou votre propre webhook." name = "Prévenir Slack quand vous partagez" - [main] delete_recording_confirm = "Voulez-vous vraiment supprimer cet enregistrement ?" delete_screenshot_confirm = "Voulez-vous vraiment supprimer cette capture d'écran ?" diff --git a/apps/desktop-gpui/locales/hi.toml b/apps/desktop-gpui/locales/hi.toml index 7b7393439b8..b8d7d9f0015 100644 --- a/apps/desktop-gpui/locales/hi.toml +++ b/apps/desktop-gpui/locales/hi.toml @@ -544,27 +544,10 @@ terms_title = "याद रखे गए शब्द" title = "ट्रांसक्रिप्शन" [settings.experimental] -developer = "डेवलपर" -developer_description = "सिर्फ़ डेवलपमेंट बिल्ड में दिखता है।" muxer = "अलग प्रोसेस में मक्सर" muxer_description = "फ़्रैगमेंटेड-MP4 मक्सर को अलग सबप्रोसेस में चलाता है ताकि मक्सर क्रैश होने से आपकी रिकॉर्डिंग न रुके। इसके लिए बंडल की गई cap-muxer बाइनरी ज़रूरी है।" -native_app = "नेटिव ऐप इस्तेमाल करें" -native_app_description = "बंद करने पर यह ऐप बंद होगा और डेवलपमेंट हार्नेस में क्लासिक Tauri ऐप फिर से खुलेगा। रिकॉर्डिंग और सेटिंग्स साझा रहती हैं।" reliability = "विश्वसनीयता" -[settings.experimental.switch] -busy = "क्लासिक ऐप पर जाने से पहले अपनी रिकॉर्डिंग, एक्सपोर्ट, अपलोड, इम्पोर्ट या ट्रांसक्रिप्शन का काम पूरा करें।" -check_failed = "यह जाँच नहीं हो सकी कि क्लासिक Cap ऐप खुला या नहीं: {error}" -data_stays = "आपकी रिकॉर्डिंग और सेटिंग्स ठीक वहीं रहती हैं जहाँ वे हैं।" -failed = "क्लासिक Cap ऐप नहीं खुल सका।" -not_found = "वापस जाने के लिए क्लासिक Cap ऐप नहीं मिला।" -open_failed = "क्लासिक Cap ऐप नहीं खुल सका: {error}" -opening = "क्लासिक Cap ऐप खुल रहा है" -opening_detail = "क्लासिक Cap ऐप तैयार होने पर यह विंडो बंद हो जाएगी।" -save_failed = "आपकी ऐप पसंद सेव नहीं हो सकी। Cap अभी भी खुला है।" -switching = "क्लासिक Cap ऐप पर वापस जा रहे हैं।" -timed_out = "क्लासिक ऐप नहीं खुला। डेव टर्मिनल में बिल्ड की गड़बड़ियाँ देखें, फिर दोबारा कोशिश करें।" - [settings.feedback] app_version = "ऐप वर्ज़न" capture_support = "कैप्चर सपोर्ट" @@ -960,7 +943,6 @@ name = "अपलोड तैयार होने पर मुझे बत description = "शेयर लिंक Slack, Discord या अपने वेबहुक पर भेजें।" name = "कुछ शेयर करने पर Slack को बताएँ" - [main] delete_recording_confirm = "क्या आप वाकई यह रिकॉर्डिंग हटाना चाहते हैं?" delete_screenshot_confirm = "क्या आप वाकई यह स्क्रीनशॉट हटाना चाहते हैं?" diff --git a/apps/desktop-gpui/locales/ja.toml b/apps/desktop-gpui/locales/ja.toml index 60637b0c9c1..c04e300ea12 100644 --- a/apps/desktop-gpui/locales/ja.toml +++ b/apps/desktop-gpui/locales/ja.toml @@ -544,27 +544,10 @@ terms_title = "登録した用語" title = "文字起こし" [settings.experimental] -developer = "開発者" -developer_description = "開発ビルドでのみ表示されます。" muxer = "別プロセスのマルチプレクサ" muxer_description = "フラグメント化MP4のマルチプレクサを独立したサブプロセスで実行し、マルチプレクサがクラッシュしても録画が失われないようにします。同梱のcap-muxerバイナリが必要です。" -native_app = "ネイティブアプリを使う" -native_app_description = "オフにするとこのアプリを閉じ、開発用ハーネスで従来のTauriアプリを開き直します。録画と設定は共有されます。" reliability = "信頼性" -[settings.experimental.switch] -busy = "従来のアプリに切り替える前に、録画、書き出し、アップロード、読み込み、文字起こしの作業を完了してください。" -check_failed = "従来のCapアプリが開いたかどうか確認できませんでした:{error}" -data_stays = "録画と設定はそのまま残ります。" -failed = "従来のCapアプリを開けませんでした。" -not_found = "切り替え先の従来のCapアプリが見つかりませんでした。" -open_failed = "従来のCapアプリを開けませんでした:{error}" -opening = "従来のCapアプリを開いています" -opening_detail = "従来のCapアプリの準備ができると、このウィンドウは閉じます。" -save_failed = "アプリの設定を保存できませんでした。Capは開いたままです。" -switching = "従来のCapアプリに戻しています。" -timed_out = "従来のアプリが開きません。開発用ターミナルでビルドエラーを確認してから、もう一度お試しください。" - [settings.feedback] app_version = "アプリのバージョン" capture_support = "キャプチャ対応" @@ -960,7 +943,6 @@ name = "アップロードの準備ができたら通知" description = "共有リンクをSlack、Discord、または独自のWebhookに送ります。" name = "共有したらSlackに知らせる" - [main] delete_recording_confirm = "この録画を削除してもよろしいですか?" delete_screenshot_confirm = "このスクリーンショットを削除してもよろしいですか?" diff --git a/apps/desktop-gpui/locales/zh-CN.toml b/apps/desktop-gpui/locales/zh-CN.toml index 1c18cc7ab65..0d3ddef7591 100644 --- a/apps/desktop-gpui/locales/zh-CN.toml +++ b/apps/desktop-gpui/locales/zh-CN.toml @@ -544,27 +544,10 @@ terms_title = "记住的词语" title = "转写" [settings.experimental] -developer = "开发者" -developer_description = "仅在开发版本中显示。" muxer = "进程外混流器" muxer_description = "在独立的子进程中运行分段 MP4 混流器,混流器崩溃时不会影响你的录制。需要内置的 cap-muxer 程序。" -native_app = "使用原生应用" -native_app_description = "关闭后会退出此应用,并在开发环境中重新打开经典的 Tauri 应用。录制和设置是共享的。" reliability = "可靠性" -[settings.experimental.switch] -busy = "请先完成录制、导出、上传、导入或转写任务,再切换到经典版应用。" -check_failed = "无法确认经典版 Cap 应用是否已打开:{error}" -data_stays = "你的录制和设置会原样保留。" -failed = "无法打开经典版 Cap 应用。" -not_found = "找不到可以切换回去的经典版 Cap 应用。" -open_failed = "无法打开经典版 Cap 应用:{error}" -opening = "正在打开经典版 Cap 应用" -opening_detail = "经典版 Cap 应用准备就绪后,此窗口将关闭。" -save_failed = "无法保存你的应用偏好设置。Cap 仍保持打开。" -switching = "正在切换回经典版 Cap 应用。" -timed_out = "经典版应用尚未打开。请在开发终端中检查构建错误,然后重试。" - [settings.feedback] app_version = "应用版本" capture_support = "捕获支持" @@ -960,7 +943,6 @@ name = "上传就绪时提醒我" description = "将分享链接发送到 Slack、Discord 或你自己的 Webhook。" name = "分享内容时通知 Slack" - [main] delete_recording_confirm = "确定要删除这段录制吗?" delete_screenshot_confirm = "确定要删除这张截图吗?" diff --git a/apps/desktop-gpui/package.json b/apps/desktop-gpui/package.json new file mode 100644 index 00000000000..6d653fe24df --- /dev/null +++ b/apps/desktop-gpui/package.json @@ -0,0 +1,12 @@ +{ + "name": "@cap/desktop", + "private": true, + "type": "module", + "scripts": { + "dev": "bun run --cwd ../.. cap-setup && dotenv -e ../../.env -- node ../../scripts/dev-desktop.mjs", + "tauri": "tauri" + }, + "devDependencies": { + "@tauri-apps/cli": "2.8.4" + } +} diff --git a/apps/desktop/src-tauri/Entitlements.plist b/apps/desktop-gpui/packaging/macos/Entitlements.plist similarity index 100% rename from apps/desktop/src-tauri/Entitlements.plist rename to apps/desktop-gpui/packaging/macos/Entitlements.plist diff --git a/apps/desktop/src-tauri/assets/dmg-background.png b/apps/desktop-gpui/packaging/macos/dmg-background.png similarity index 100% rename from apps/desktop/src-tauri/assets/dmg-background.png rename to apps/desktop-gpui/packaging/macos/dmg-background.png diff --git a/apps/desktop/src-tauri/assets/nsis-header.bmp b/apps/desktop-gpui/packaging/windows/nsis-header.bmp similarity index 100% rename from apps/desktop/src-tauri/assets/nsis-header.bmp rename to apps/desktop-gpui/packaging/windows/nsis-header.bmp diff --git a/apps/desktop/src-tauri/assets/nsis-sidebar.bmp b/apps/desktop-gpui/packaging/windows/nsis-sidebar.bmp similarity index 100% rename from apps/desktop/src-tauri/assets/nsis-sidebar.bmp rename to apps/desktop-gpui/packaging/windows/nsis-sidebar.bmp diff --git a/apps/desktop-gpui/rust-toolchain.toml b/apps/desktop-gpui/rust-toolchain.toml index 97b41dac9af..9138b245a20 100644 --- a/apps/desktop-gpui/rust-toolchain.toml +++ b/apps/desktop-gpui/rust-toolchain.toml @@ -1,6 +1,6 @@ -# The root repo pins 1.88.0 for the Tauri app; gpui's dependency tree needs -# newer (smol_str 0.3.6 / cosmic-text 0.19 declare rust-version 1.89). The -# nearest toolchain file wins, so this only affects apps/desktop-gpui. +# The root workspace pins 1.88.0; gpui's dependency tree needs newer +# (smol_str 0.3.6 / cosmic-text 0.19 declare rust-version 1.89). The nearest +# toolchain file wins, so this only affects apps/desktop-gpui. [toolchain] channel = "stable" components = ["rustfmt", "clippy"] diff --git a/apps/desktop-gpui/src/app_sounds.rs b/apps/desktop-gpui/src/app_sounds.rs index c2ab9dd6400..2e59938c37d 100644 --- a/apps/desktop-gpui/src/app_sounds.rs +++ b/apps/desktop-gpui/src/app_sounds.rs @@ -3,7 +3,6 @@ use std::io::Cursor; use anyhow::Context as _; use rodio::{Decoder, OutputStream, Sink}; -#[path = "../../desktop/src-tauri/src/recording_start_sound.rs"] mod recording_start_sound; pub use recording_start_sound::StartCue; @@ -27,12 +26,12 @@ impl AppSound { fn bytes(self) -> &'static [u8] { match self { Self::StartRecording => { - include_bytes!("../../desktop/src-tauri/sounds/start-recording.ogg") + include_bytes!("../assets/sounds/start-recording.ogg") } Self::StopRecording => { - include_bytes!("../../desktop/src-tauri/sounds/stop-recording.ogg") + include_bytes!("../assets/sounds/stop-recording.ogg") } - Self::Notification => include_bytes!("../../desktop/src-tauri/sounds/action.ogg"), + Self::Notification => include_bytes!("../assets/sounds/action.ogg"), } } diff --git a/apps/desktop/src-tauri/src/recording_start_sound.rs b/apps/desktop-gpui/src/app_sounds/recording_start_sound.rs similarity index 100% rename from apps/desktop/src-tauri/src/recording_start_sound.rs rename to apps/desktop-gpui/src/app_sounds/recording_start_sound.rs diff --git a/apps/desktop-gpui/src/assets.rs b/apps/desktop-gpui/src/assets.rs index f94bfb25386..0a89510493b 100644 --- a/apps/desktop-gpui/src/assets.rs +++ b/apps/desktop-gpui/src/assets.rs @@ -248,9 +248,9 @@ const ONBOARDING: &[(&str, &[u8])] = &[ ("onboarding/mist.svg", br##""##), ("onboarding/vignette.svg", br##""##), ("onboarding/wordmark.svg", br##""##), - ("onboarding/music.mp3", include_bytes!("../../desktop/src/assets/tears-and-fireflies-adi-goldstein.mp3")), - ("onboarding/cursor-macos.svg", include_bytes!("../../../packages/ui-solid/icons/cursor-macos.svg")), - ("onboarding/cursor-windows.svg", include_bytes!("../../../packages/ui-solid/icons/cursor-windows.svg")), + ("onboarding/music.mp3", include_bytes!("../assets/onboarding/tears-and-fireflies-adi-goldstein.mp3")), + ("onboarding/cursor-macos.svg", include_bytes!("../assets/onboarding/cursor-macos.svg")), + ("onboarding/cursor-windows.svg", include_bytes!("../assets/onboarding/cursor-windows.svg")), ("onboarding/volume-2.svg", include_bytes!("../assets/icons/volume-2.svg")), ("onboarding/volume-x.svg", include_bytes!("../assets/icons/volume-x.svg")), ]; diff --git a/apps/desktop-gpui/src/editor_audio.rs b/apps/desktop-gpui/src/editor_audio.rs index fad14dccf3f..742f4ca4968 100644 --- a/apps/desktop-gpui/src/editor_audio.rs +++ b/apps/desktop-gpui/src/editor_audio.rs @@ -131,10 +131,7 @@ fn bundled_track_path_from( .iter() .map(|directory| directory.join("assets/music").join(&file)) .collect::>(); - candidates.extend([ - manifest.join("../desktop/src/assets/music").join(&file), - manifest.join("assets/music").join(&file), - ]); + candidates.push(manifest.join("assets/music").join(&file)); candidates.into_iter().find(|path| path.is_file()) } diff --git a/apps/desktop-gpui/src/editor_clips.rs b/apps/desktop-gpui/src/editor_clips.rs index 23a0dccd4b0..872d3592965 100644 --- a/apps/desktop-gpui/src/editor_clips.rs +++ b/apps/desktop-gpui/src/editor_clips.rs @@ -3539,9 +3539,7 @@ mod tests { #[test] fn split_thumbnails_use_requested_time_inside_keyframe_interval() { - let fixture = ImportFixture::new(include_bytes!( - "../../desktop/src-tauri/test-data/clip-thumbnail-gop.mp4" - )); + let fixture = ImportFixture::new(include_bytes!("../tests/data/clip-thumbnail-gop.mp4")); for (time, expected_channel) in [(0.0, 2), (1.5, 1), (2.5, 0), (3.0, 0)] { let thumbnail = decode_thumbnail_frame(&fixture.source, time).unwrap(); let data = thumbnail.as_bytes(0).unwrap(); @@ -3560,9 +3558,8 @@ mod tests { #[test] fn long_gop_thumbnails_reach_requested_time_and_preserve_eof_fallback() { - let fixture = ImportFixture::new(include_bytes!( - "../../desktop/src-tauri/test-data/clip-thumbnail-long-gop.mp4" - )); + let fixture = + ImportFixture::new(include_bytes!("../tests/data/clip-thumbnail-long-gop.mp4")); for time in [8.5, 10.0, 11.0] { let thumbnail = decode_thumbnail_frame(&fixture.source, time).unwrap(); let data = thumbnail.as_bytes(0).unwrap(); @@ -3576,9 +3573,8 @@ mod tests { #[test] fn exhausted_decode_budget_does_not_return_partial_thumbnail() { - let fixture = ImportFixture::new(include_bytes!( - "../../desktop/src-tauri/test-data/clip-thumbnail-long-gop.mp4" - )); + let fixture = + ImportFixture::new(include_bytes!("../tests/data/clip-thumbnail-long-gop.mp4")); for (packet_limit, timeout, expected_error) in [ (240, std::time::Duration::from_secs(2), "packet budget"), ( diff --git a/apps/desktop-gpui/src/editor_sidebar.rs b/apps/desktop-gpui/src/editor_sidebar.rs index 443ce9226d2..52febe73953 100644 --- a/apps/desktop-gpui/src/editor_sidebar.rs +++ b/apps/desktop-gpui/src/editor_sidebar.rs @@ -534,37 +534,10 @@ fn wallpaper_dir_from( candidates.push(PathBuf::from( "/Applications/Cap.app/Contents/Resources/assets/backgrounds", )); - candidates.push( - manifest - .join("../desktop/src-tauri/assets/backgrounds") - .clean(), - ); + candidates.push(manifest.join("assets/backgrounds")); candidates.into_iter().find(|path| path.is_dir()) } -/// `PathBuf::canonicalize` fails on a path that does not exist, and a `..` -/// segment left in place reads badly in a log line, so the `../` is folded -/// here instead. -trait Clean { - fn clean(self) -> PathBuf; -} - -impl Clean for PathBuf { - fn clean(self) -> PathBuf { - let mut out = PathBuf::new(); - for component in self.components() { - match component { - std::path::Component::ParentDir => { - out.pop(); - } - std::path::Component::CurDir => {} - other => out.push(other), - } - } - out - } -} - pub fn wallpaper_path(id: &str) -> Option { if !WALLPAPER_NAMES.contains(&id) { return None; diff --git a/apps/desktop-gpui/src/i18n/settings_surface_tests.rs b/apps/desktop-gpui/src/i18n/settings_surface_tests.rs index 4cae02da1d6..6286b1a1b66 100644 --- a/apps/desktop-gpui/src/i18n/settings_surface_tests.rs +++ b/apps/desktop-gpui/src/i18n/settings_surface_tests.rs @@ -39,8 +39,6 @@ const FORMATTED: &[&str] = &[ "settings.cli.installs_command", "settings.cli.path_missing", "settings.transcription.count", - "settings.experimental.switch.open_failed", - "settings.experimental.switch.check_failed", "settings.feedback.diagnostic.confirm_body", "settings.changelog.version", "settings.integrations.managed_by", @@ -512,52 +510,6 @@ fn settings_surfaces_match_the_literals_they_replaced() { tr::settings::experimental::muxer_description(), "Run the fragmented-MP4 muxer in an isolated subprocess so muxer crashes can't take down your recording. Requires the bundled cap-muxer binary.", ), - (tr::settings::experimental::developer(), "Developer"), - ( - tr::settings::experimental::developer_description(), - "Only shown in development builds.", - ), - (tr::settings::experimental::native_app(), "Use native app"), - ( - tr::settings::experimental::native_app_description(), - "Turn off to close this app and reopen the classic Tauri app in the dev harness. Recordings and settings are shared.", - ), - ( - tr::settings::experimental::switch::switching(), - "Switching back to the classic Cap app.", - ), - ( - tr::settings::experimental::switch::data_stays(), - "Your recordings and settings stay exactly where they are.", - ), - ( - tr::settings::experimental::switch::opening(), - "Opening the classic Cap app", - ), - ( - tr::settings::experimental::switch::opening_detail(), - "This window will close when the classic Cap app is ready.", - ), - ( - tr::settings::experimental::switch::busy(), - "Finish your recording, export, upload, import, or transcription task before switching to the classic app.", - ), - ( - tr::settings::experimental::switch::not_found(), - "Couldn't find the classic Cap app to switch back to.", - ), - ( - tr::settings::experimental::switch::save_failed(), - "Couldn't save your app preference. Cap is still open.", - ), - ( - tr::settings::experimental::switch::timed_out(), - "The classic app hasn't opened. Check the dev terminal for build errors, then try again.", - ), - ( - tr::settings::experimental::switch::failed(), - "Couldn't open the classic Cap app.", - ), (tr::settings::feedback::title(), "Feedback"), ( tr::settings::feedback::description(), @@ -1496,14 +1448,6 @@ fn settings_surface_messages_format_like_the_code_they_replaced() { tr::settings::cli::load_failed(&error), format!("Couldn't load CLI status: {error}") ); - assert_eq!( - tr::settings::experimental::switch::open_failed(&error), - format!("Couldn't open the classic Cap app: {error}") - ); - assert_eq!( - tr::settings::experimental::switch::check_failed(&error), - format!("Couldn't check whether the classic Cap app opened: {error}") - ); let path_entry = "~/.local/bin".to_string(); assert_eq!( tr::settings::cli::path_missing(&path_entry), diff --git a/apps/desktop-gpui/src/main.rs b/apps/desktop-gpui/src/main.rs index b0a3ef392f3..0819040393f 100644 --- a/apps/desktop-gpui/src/main.rs +++ b/apps/desktop-gpui/src/main.rs @@ -165,10 +165,9 @@ fn resolve_auto_screenshot_editor(target: &str) -> Option { } /// Windows ends the process at logoff or shutdown without running -/// `on_app_quit`, so both markers that mean "this session crashed" clear here. +/// `on_app_quit`, so the marker that means "this session crashed" clears here. #[cfg(target_os = "windows")] fn end_windows_session() { - crate::store::clear_handoff_marker(); crash_capture::mark_clean_exit(); } @@ -343,9 +342,6 @@ fn main() { single_instance::acquire(); let previous_session = crash_capture::begin_session(&diagnostics::logs_dir()); blur_recovery::configure(previous_session); - if cfg!(debug_assertions) { - store::mark_handoff_session(); - } #[cfg(target_os = "macos")] platform::install_appkit_exception_guards(); @@ -479,12 +475,6 @@ fn main() { return; }; - if cfg!(debug_assertions) { - cx.on_app_quit(|_| async { - crate::store::clear_handoff_marker(); - }) - .detach(); - } cx.on_app_quit(|_| async { crash_capture::mark_clean_exit(); }) diff --git a/apps/desktop-gpui/src/settings_pages.rs b/apps/desktop-gpui/src/settings_pages.rs index 3ab0cd94daf..1042fa4a81d 100644 --- a/apps/desktop-gpui/src/settings_pages.rs +++ b/apps/desktop-gpui/src/settings_pages.rs @@ -360,12 +360,6 @@ pub(crate) struct PagesState { s3: S3Page, gdrive: GDrivePage, - // Experimental (experimental.tsx). The Developer section's hand-back takes the - // whole settings window over, so its clock and the ticker that repaints the - // sequence live here and the overlay renders from the window root. - switch_back: Option, - switch_back_ticker: Option>, - // Automations (automations.tsx) automations: AutomationsStore, automations_loaded: bool, @@ -475,8 +469,6 @@ impl PagesState { error: None, poll: None, }, - switch_back: None, - switch_back_ticker: None, automations: AutomationsStore::default(), automations_loaded: false, automations_save_failed: false, @@ -1441,10 +1433,6 @@ impl SettingsWindow { self.pages.listening.is_some() } - pub(crate) fn switch_back_running(&self) -> bool { - self.pages.switch_back.is_some() - } - /// Leave recording mode without touching the binding. Safe to call when /// nothing is recording; every exit path (Escape, a click elsewhere, /// another page, the window losing focus or closing) lands here. @@ -2666,75 +2654,13 @@ impl SettingsWindow { // Experimental (experimental.tsx) // --------------------------------------------------------------------------- -pub(crate) enum SwitchBack { - Running(std::time::Instant), - WaitingForClassic, - Failed(String), -} - -/// A cold dev build can genuinely take this long; past it, assume the build -/// failed and hand the user back their app with a pointer at the terminal. -const CLASSIC_WAIT_TIMEOUT: Duration = Duration::from_secs(10 * 60); - -const SWITCH_SENTENCES: &[fn() -> &'static str] = &[ - tr::settings::experimental::switch::switching, - tr::settings::experimental::switch::data_stays, -]; -const SWITCH_SENTENCE_MS: u64 = 2000; -const SWITCH_FADE_MS: f32 = 400.; -const SWITCH_COUNTDOWN_FROM: u32 = 5; -const SWITCH_TAKEOVER_MS: u64 = SWITCH_COUNTDOWN_FROM as u64 * 1000; - -/// The overlay's whole appearance at one instant: which sentence, how opaque, -/// and the number. -fn takeover_frame(elapsed_ms: f32) -> (usize, f32, u32) { - let last = SWITCH_SENTENCES.len() - 1; - let index = ((elapsed_ms / SWITCH_SENTENCE_MS as f32) as usize).min(last); - let within = elapsed_ms - index as f32 * SWITCH_SENTENCE_MS as f32; - let fade_in = (within / SWITCH_FADE_MS).clamp(0., 1.); - // The last line holds rather than fading out; blanking the column while the - // countdown finishes would read as a stall. - let alpha = if index == last { - fade_in - } else { - fade_in.min(((SWITCH_SENTENCE_MS as f32 - within) / SWITCH_FADE_MS).clamp(0., 1.)) - }; - // Five on the first frame down to one in the last second; the switch fires - // rather than ever showing zero. - let left = SWITCH_TAKEOVER_MS as f32 - elapsed_ms; - let remaining = (left / 1000.) - .ceil() - .clamp(1., SWITCH_COUNTDOWN_FROM as f32) as u32; - (index, alpha, remaining) -} - -/// Cap ships as this app alone, so the classic Tauri app only exists inside -/// the `tauri dev` harness: a debug cargo build can hand the session back to -/// it through the dev-session supervisor (`store::request_classic_reopen`), -/// and nothing else has a classic app to switch to. -fn dev_supervisor_available_for(exe: Option<&std::path::Path>, debug_build: bool) -> bool { - debug_build - && exe.is_some_and(|exe| { - exe.components() - .any(|component| component.as_os_str() == "target") - }) -} - -fn dev_supervisor_available() -> bool { - dev_supervisor_available_for( - std::env::current_exe().ok().as_deref(), - cfg!(debug_assertions), - ) -} - impl SettingsWindow { pub(crate) fn render_experimental(&self, cx: &mut Context) -> Vec { - // No "Native camera preview" toggle here: in this app the native - // camera path is the only implementation, so the Tauri page's - // experimental switch has nothing to switch. The store key - // (`enableNativeCameraPreview`) stays readable in `store.rs` and is - // left untouched in the shared store -- the Tauri app still uses it. - let mut sections = vec![ + // No "Native camera preview" toggle here: the native camera path is + // the only implementation, so the 0.6.0 page's experimental switch has + // nothing to switch. The store key (`enableNativeCameraPreview`) stays + // readable in `store.rs` and is left untouched in the store. + vec![ self.section( tr::settings::experimental::reliability(), None, @@ -2763,283 +2689,7 @@ impl SettingsWindow { ], ) .into_any_element(), - ]; - if dev_supervisor_available() { - sections.push( - self.section( - tr::settings::experimental::developer(), - Some(tr::settings::experimental::developer_description()), - None, - vec![self.rows(vec![self.classic_app_row(cx)]).into_any_element()], - ) - .into_any_element(), - ); - } - sections - } - - /// The dev harness's way back to the classic app: being in this app is what - /// the toggle means, and turning it off reopens the classic app under - /// `tauri dev`. - fn classic_app_row(&self, cx: &mut Context) -> gpui::AnyElement { - let checked = !matches!(self.pages.switch_back, Some(SwitchBack::Running(_))); - self.setting_row( - tr::settings::experimental::native_app(), - Some(tr::settings::experimental::native_app_description()), - self.toggle( - "enable-gpui-app", - tr::settings::experimental::native_app(), - checked, - cx, - |this, cx| { - match this.pages.switch_back { - Some(SwitchBack::Running(_)) => this.cancel_switch_back(cx), - // Committed: the classic app is already being brought up. - Some(SwitchBack::WaitingForClassic) => {} - _ => this.start_switch_back(cx), - } - }, - ) - .into_any_element(), - ) - } - - /// The full-window takeover, painted from `SettingsWindow::render` so it - /// covers the sidebar and the menus too. - pub(crate) fn render_switch_overlay(&self, cx: &mut Context) -> Option { - let switch = self.pages.switch_back.as_ref()?; - let white = gpui::white(); - let mut column = div() - .absolute() - .inset_0() - .when(cfg!(target_os = "windows"), |overlay| overlay.top(px(36.))) - // Nothing behind the takeover is clickable while it runs. - .occlude() - .flex() - .flex_col() - .items_center() - .justify_center() - .gap(px(28.)) - .bg(gpui::hsla(0., 0., 0., 0.92)); - - match switch { - SwitchBack::Running(started) => { - let (index, alpha, remaining) = - takeover_frame(started.elapsed().as_secs_f32() * 1000.); - column = column - .child( - div() - .text_size(px(72.)) - .line_height(px(76.)) - .font_weight(FontWeight::SEMIBOLD) - .text_color(white) - .child(SharedString::from(remaining.to_string())), - ) - .child( - div() - .h(px(40.)) - .max_w(px(380.)) - .flex() - .items_center() - .text_size(px(15.)) - .text_center() - .text_color(gpui::hsla(0., 0., 1., alpha)) - .child(SWITCH_SENTENCES[index]()), - ); - } - SwitchBack::WaitingForClassic => { - column = column - .child( - div() - .max_w(px(380.)) - .text_size(px(17.)) - .font_weight(FontWeight::SEMIBOLD) - .text_center() - .text_color(white) - .child(tr::settings::experimental::switch::opening()), - ) - .child( - div() - .max_w(px(380.)) - .text_size(px(14.)) - .text_center() - .text_color(gpui::hsla(0., 0., 1., 0.7)) - .child(tr::settings::experimental::switch::opening_detail()), - ); - } - SwitchBack::Failed(error) => { - column = column.child( - div() - .max_w(px(380.)) - .text_size(px(14.)) - .text_center() - .text_color(rgb(0xf87171)) - .child(SharedString::from(error.clone())), - ); - } - } - - // Committed states have nothing to cancel. - if matches!(switch, SwitchBack::WaitingForClassic) { - return Some(column.into_any_element()); - } - - Some( - column - .child( - div() - .id("switch-back-cancel") - .flex() - .items_center() - .px(px(16.)) - .h(px(32.)) - .rounded(px(8.)) - .border_1() - .border_color(gpui::hsla(0., 0., 1., 0.25)) - .text_size(px(13.)) - .text_color(white) - .cursor_pointer() - .hover(|style| style.bg(gpui::hsla(0., 0., 1., 0.12))) - .on_click(cx.listener(|this, _, _window, cx| this.cancel_switch_back(cx))) - .child(if matches!(switch, SwitchBack::Failed(_)) { - tr::common::close() - } else { - tr::common::cancel() - }), - ) - .into_any_element(), - ) - } - - fn start_switch_back(&mut self, cx: &mut Context) { - if self.switch_back_blocked(cx) { - return; - } - - self.pages.switch_back = Some(SwitchBack::Running(std::time::Instant::now())); - // gpui only renders on invalidation, so the fades and the countdown - // need a pulse to run at all -- the `toggle_placeholders` shape. - // Assigning over the previous task drops it, which is how Cancel and a - // restart stop the one already in flight. - self.pages.switch_back_ticker = Some(cx.spawn(async move |this, cx| { - loop { - cx.background_executor() - .timer(Duration::from_millis(16)) - .await; - let running = this - .update(cx, |this, cx| { - let started = match &this.pages.switch_back { - Some(SwitchBack::Running(started)) => *started, - _ => return false, - }; - if started.elapsed() >= Duration::from_millis(SWITCH_TAKEOVER_MS) { - this.finish_switch_back(cx); - return false; - } - cx.notify(); - true - }) - .unwrap_or(false); - if !running { - return; - } - } - })); - cx.notify(); - } - - fn cancel_switch_back(&mut self, cx: &mut Context) { - self.pages.switch_back = None; - self.pages.switch_back_ticker = None; - cx.notify(); - } - - fn switch_back_blocked(&mut self, cx: &mut Context) -> bool { - if !crate::updates::work_in_flight(cx) { - return false; - } - - self.pages.switch_back = Some(SwitchBack::Failed( - tr::settings::experimental::switch::busy().to_string(), - )); - cx.notify(); - true - } - - /// Hand the session (`enableGpuiApp`) to the classic dev app, ask the dev - /// supervisor to start it, then quit once it is visible. - fn finish_switch_back(&mut self, cx: &mut Context) { - if self.switch_back_blocked(cx) { - return; - } - if !dev_supervisor_available() { - self.pages.switch_back = Some(SwitchBack::Failed( - tr::settings::experimental::switch::not_found().to_string(), - )); - cx.notify(); - return; - } - if let Err(error) = crate::app_windows::flush_pending_editor_saves(cx) { - self.pages.switch_back = Some(SwitchBack::Failed(error)); - cx.notify(); - return; - } - - if !store::set_store_setting(GENERAL_SETTINGS, "enableGpuiApp", Value::Bool(false)) { - self.pages.switch_back = Some(SwitchBack::Failed( - tr::settings::experimental::switch::save_failed().to_string(), - )); - cx.notify(); - return; - } - let pending = store::mark_classic_pending(); - self.pages.switch_back = Some(SwitchBack::WaitingForClassic); - self.pages.switch_back_ticker = None; - cx.notify(); - - // The handoff must finish even if its settings window closes. - cx.spawn(async move |this, cx| { - let result = cx - .background_executor() - .spawn(async move { pending.and_then(|()| store::request_classic_reopen()) }) - .await; - let mut failure = result - .err() - .map(tr::settings::experimental::switch::open_failed); - let started = std::time::Instant::now(); - while failure.is_none() { - match store::classic_pending_path().try_exists() { - Ok(false) => { - tracing::info!("classic app is visible; quitting GPUI"); - cx.update(crate::menus::quit); - return; - } - Ok(true) => {} - Err(error) => { - failure = Some(tr::settings::experimental::switch::check_failed(error)); - break; - } - } - if started.elapsed() >= CLASSIC_WAIT_TIMEOUT { - failure = Some(tr::settings::experimental::switch::timed_out().to_string()); - break; - } - cx.background_executor() - .timer(Duration::from_millis(250)) - .await; - } - let message = - failure.unwrap_or_else(|| tr::settings::experimental::switch::failed().to_string()); - tracing::error!("{message}"); - store::clear_classic_pending(); - store::set_store_setting(GENERAL_SETTINGS, "enableGpuiApp", Value::Bool(true)); - this.update(cx, |this, cx| { - this.pages.switch_back = Some(SwitchBack::Failed(message)); - cx.notify(); - }) - .ok(); - }) - .detach(); + ] } } @@ -8825,41 +8475,6 @@ mod tests { ); } - #[test] - fn only_debug_cargo_builds_can_switch_back_to_the_dev_harness() { - let cargo_build = - std::path::Path::new("/Users/x/Cap/apps/desktop-gpui/target/debug/cap-gpui"); - let installed_app = std::path::Path::new("/Applications/Cap.app/Contents/MacOS/Cap"); - - assert!(dev_supervisor_available_for(Some(cargo_build), true)); - assert!(!dev_supervisor_available_for(Some(cargo_build), false)); - assert!(!dev_supervisor_available_for(Some(installed_app), true)); - assert!(!dev_supervisor_available_for(Some(installed_app), false)); - assert!(!dev_supervisor_available_for(None, true)); - } - - /// The takeover's whole timeline, read off its one clock. - #[test] - fn the_takeover_counts_down_while_the_lines_fade() { - // The number is up from the first frame and never reaches zero. - assert_eq!(takeover_frame(0.).2, SWITCH_COUNTDOWN_FROM); - assert_eq!(takeover_frame(1000.).2, SWITCH_COUNTDOWN_FROM - 1); - assert_eq!(takeover_frame(SWITCH_TAKEOVER_MS as f32 - 1.).2, 1); - assert_eq!(takeover_frame(SWITCH_TAKEOVER_MS as f32).2, 1); - - // First line, faded in over its lead, and out again as its slot ends. - let (index, alpha, _) = takeover_frame(0.); - assert_eq!(index, 0); - assert_eq!(alpha, 0.); - assert_eq!(takeover_frame(SWITCH_FADE_MS).1, 1.); - assert_eq!(takeover_frame(SWITCH_SENTENCE_MS as f32 - 1.).1.round(), 0.); - - // The last line holds rather than blanking while the number finishes. - let (index, alpha, _) = takeover_frame(SWITCH_TAKEOVER_MS as f32 - 1.); - assert_eq!(index, SWITCH_SENTENCES.len() - 1); - assert_eq!(alpha, 1.); - } - /// `conditionAppliesToTrigger` / `actionAppliesToTrigger` against the /// tables in `utils/automations.ts`. #[test] diff --git a/apps/desktop-gpui/src/settings_window.rs b/apps/desktop-gpui/src/settings_window.rs index c3e649a37f6..cd7339ca053 100644 --- a/apps/desktop-gpui/src/settings_window.rs +++ b/apps/desktop-gpui/src/settings_window.rs @@ -854,7 +854,7 @@ impl SettingsWindow { let pages = crate::settings_pages::PagesState::new(window, cx); let page_scroll = ScrollHandle::new(); let keyboard_nav = ui::keyboard_nav::install(window, cx, |this: &Self, _| { - this.menu.is_some() || this.shortcut_listening() || this.switch_back_running() + this.menu.is_some() || this.shortcut_listening() }); Self { @@ -1736,9 +1736,6 @@ fn covers_default_exclusion(entry: &WindowExclusion, default: &WindowExclusion) impl Render for SettingsWindow { fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { self.sync_appearance(window, cx); - if self.switch_back_running() { - ui::keyboard_nav::leave(window, cx); - } self.keyboard_nav = ui::keyboard_nav::active(window, cx); let theme = self.theme; if self.page == Page::Quality @@ -1852,9 +1849,6 @@ impl Render for SettingsWindow { // the drag layer the zoom slider needs while the button is held. .children(self.render_menu(cx)) .children(self.render_slider_drag_layer(cx)) - // Over everything, including the menus: the Experimental page's - // hand-back takes the whole window while it counts down. - .children(self.render_switch_overlay(cx)) } } diff --git a/apps/desktop-gpui/src/store.rs b/apps/desktop-gpui/src/store.rs index 543f3a6d246..97ce398ba88 100644 --- a/apps/desktop-gpui/src/store.rs +++ b/apps/desktop-gpui/src/store.rs @@ -1,16 +1,18 @@ -//! Persisted state: this app's own, and the Tauri app's settings store. +//! Persisted state: this app's own, and the settings store it shares with +//! 0.6.0 and earlier (the Tauri app, still downloadable and able to open the +//! same data after a downgrade). //! //! Two files, both inside `so.cap.desktop`'s app-data dir: //! -//! - `gpui-state.json` -- ours. The Tauri app keeps the camera window's chrome +//! - `gpui-state.json` -- ours. The Tauri app kept the camera window's chrome //! state in the webview's `localStorage` (`cameraWindowState`); there is no //! webview here, so the same shape lives in a file. Reads happen once at //! open; writes are whole-file rewrites on a background thread -- the state //! is a handful of scalars, atomicity beyond rename is not worth plumbing. -//! - `store` -- the tauri-plugin-store file the shipping app loads -//! (`Store.load("store")` in `apps/desktop/src/store.ts`), holding -//! `general_settings`, `recording_start_safety`, `auth`, `presets` and the -//! rest. Both apps read and write it, so every write here is a +//! - `store` -- the tauri-plugin-store file 0.6.0 loads +//! (`Store.load("store")` in `apps/desktop/src/store.ts` at `cap-v0.6.2`), +//! holding `general_settings`, `recording_start_safety`, `auth`, `presets` +//! and the rest. Both apps read and write it, so every write here is a //! read-modify-write on the raw JSON that touches exactly one key: see //! [`set_store_setting`]. @@ -154,9 +156,9 @@ pub struct ExportPrefs { /// `so.cap.desktop`'s app-data dir -- where both stores live. /// -/// Same identifier the Tauri app uses (`so.cap.desktop`), resolved the way -/// each OS's app-data convention spells it so a recording made on Windows or -/// Linux lands in the folder both apps already agree on. +/// The identifier every Cap release has used (`so.cap.desktop`), resolved +/// the way each OS's app-data convention spells it, so recordings and +/// settings from 0.6.0 and earlier are found where those builds left them. pub fn app_data_dir() -> PathBuf { if let Ok(dir) = std::env::var("CAP_GPUI_APP_DATA_DIR") && !dir.trim().is_empty() @@ -221,81 +223,6 @@ fn bundled_resource_dirs_for( directories } -/// The Tauri dev harness's hand-off marker (`gpui_app.rs` over there): it -/// survives the whole session and is removed only on a clean quit, so a marker -/// left behind reads as a crash and routes the next `bun run dev:desktop` back -/// to the classic app. -pub fn handoff_marker_path() -> PathBuf { - app_data_dir().join("cap-gpui.handoff") -} - -pub fn mark_handoff_session() { - if let Err(error) = mark_handoff_session_at(&handoff_marker_path()) { - tracing::warn!("writing the hand-off marker: {error}"); - } -} - -fn mark_handoff_session_at(path: &Path) -> std::io::Result<()> { - if let Some(parent) = path.parent() { - std::fs::create_dir_all(parent)?; - } - let staged = path.with_extension(format!("handoff-{}", std::process::id())); - std::fs::write(&staged, std::process::id().to_string())?; - std::fs::rename(&staged, path).inspect_err(|_| { - let _ = std::fs::remove_file(&staged); - }) -} - -pub fn clear_handoff_marker() { - clear_handoff_marker_at(&handoff_marker_path()); -} - -fn clear_handoff_marker_at(path: &Path) { - match std::fs::remove_file(path) { - Ok(()) => tracing::info!("cleared the hand-off marker"), - Err(error) if error.kind() == std::io::ErrorKind::NotFound => {} - Err(error) => tracing::warn!("clearing the hand-off marker: {error}"), - } -} - -/// A dev-checkout switch-back has no `Cap.app` to `open`: the classic app only -/// runs inside its `tauri dev` harness, which exited with the hand-off. This -/// sentinel asks whatever supervises the dev session (`scripts/dev-desktop.mjs` -/// watches for it) to start that harness again; with no supervisor listening it -/// is inert, and the flag written alongside it still routes the next -/// `bun run dev:desktop` to the classic app. -pub fn classic_reopen_path() -> PathBuf { - app_data_dir().join("cap-classic.reopen") -} - -pub fn request_classic_reopen() -> std::io::Result<()> { - let path = classic_reopen_path(); - if let Some(parent) = path.parent() { - std::fs::create_dir_all(parent)?; - } - std::fs::write(&path, std::process::id().to_string()) -} - -pub fn classic_pending_path() -> PathBuf { - app_data_dir().join("cap-classic.pending") -} - -pub fn mark_classic_pending() -> std::io::Result<()> { - let path = classic_pending_path(); - if let Some(parent) = path.parent() { - std::fs::create_dir_all(parent)?; - } - std::fs::write(&path, std::process::id().to_string()) -} - -pub fn clear_classic_pending() { - if let Err(error) = std::fs::remove_file(classic_pending_path()) - && error.kind() != std::io::ErrorKind::NotFound - { - tracing::warn!(%error, "couldn't clear classic handoff readiness"); - } -} - fn state_path() -> PathBuf { app_data_dir().join("gpui-state.json") } @@ -2106,23 +2033,6 @@ pub fn preset_names() -> Vec { #[cfg(test)] mod tests { - #[test] - fn the_handoff_marker_holds_this_pid_until_a_clean_quit_clears_it() { - let directory = - std::env::temp_dir().join(format!("cap-gpui-handoff-{}", super::new_uuid_v4())); - let marker = directory.join("cap-gpui.handoff"); - super::mark_handoff_session_at(&marker).unwrap(); - assert_eq!( - std::fs::read_to_string(&marker).unwrap(), - std::process::id().to_string() - ); - assert_eq!(std::fs::read_dir(&directory).unwrap().count(), 1); - super::clear_handoff_marker_at(&marker); - assert!(!marker.exists()); - super::clear_handoff_marker_at(&marker); - std::fs::remove_dir_all(directory).unwrap(); - } - use super::*; struct TempStore { diff --git a/apps/desktop-gpui/src/tray/windows.rs b/apps/desktop-gpui/src/tray/windows.rs index aec176d7c66..1e311ff669c 100644 --- a/apps/desktop-gpui/src/tray/windows.rs +++ b/apps/desktop-gpui/src/tray/windows.rs @@ -15,8 +15,7 @@ use super::{ use crate::{i18n::tr, main_window::Mode}; const TRAY_ID: &str = "cap-gpui-tray"; -const DEFAULT_ICON: &[u8] = - include_bytes!("../../../desktop/src-tauri/icons/tray-default-icon.png"); +const DEFAULT_ICON: &[u8] = include_bytes!("../../assets/tray/tray-default-icon.png"); const STOP_ICON: &[u8] = include_bytes!("../../assets/tray/tray-stop-icon.png"); enum Event { diff --git a/apps/desktop-gpui/tauri.conf.json b/apps/desktop-gpui/tauri.conf.json index bc6696d7056..ed29600ca92 100644 --- a/apps/desktop-gpui/tauri.conf.json +++ b/apps/desktop-gpui/tauri.conf.json @@ -22,25 +22,22 @@ "targets": "all", "category": "Video", "longDescription": "Cap is the open source alternative to Loom. Lightweight, powerful, and cross-platform. Record and share in seconds.", - "externalBin": [ - "../desktop/src-tauri/binaries/cap-muxer", - "../desktop/src-tauri/binaries/cap-cli" - ], + "externalBin": ["binaries/cap-muxer", "binaries/cap-cli"], "icon": [ - "../desktop/src-tauri/icons/32x32.png", - "../desktop/src-tauri/icons/128x128.png", - "../desktop/src-tauri/icons/128x128@2x.png", - "../desktop/src-tauri/icons/macos/icon.icns", - "../desktop/src-tauri/icons/icon.ico" + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/macos/icon.icns", + "icons/icon.ico" ], "resources": { - "../desktop/src-tauri/assets/backgrounds/macOS/*": "assets/backgrounds/macOS/", - "../desktop/src-tauri/assets/backgrounds/blue/*": "assets/backgrounds/blue/", - "../desktop/src-tauri/assets/backgrounds/cities/*": "assets/backgrounds/cities/", - "../desktop/src-tauri/assets/backgrounds/dark/*": "assets/backgrounds/dark/", - "../desktop/src-tauri/assets/backgrounds/orange/*": "assets/backgrounds/orange/", - "../desktop/src-tauri/assets/backgrounds/purple/*": "assets/backgrounds/purple/", - "../desktop/src/assets/music/*.mp3": "assets/music/" + "assets/backgrounds/macOS/*": "assets/backgrounds/macOS/", + "assets/backgrounds/blue/*": "assets/backgrounds/blue/", + "assets/backgrounds/cities/*": "assets/backgrounds/cities/", + "assets/backgrounds/dark/*": "assets/backgrounds/dark/", + "assets/backgrounds/orange/*": "assets/backgrounds/orange/", + "assets/backgrounds/purple/*": "assets/backgrounds/purple/", + "assets/music/*.mp3": "assets/music/" }, "fileAssociations": [ { @@ -52,7 +49,7 @@ ], "macOS": { "minimumSystemVersion": "12.3", - "entitlements": "../desktop/src-tauri/Entitlements.plist", + "entitlements": "packaging/macos/Entitlements.plist", "frameworks": ["../../target/native-deps/Spacedrive.framework"], "files": { "Resources/en.lproj/InfoPlist.strings": "macos/en.lproj/InfoPlist.strings", @@ -64,7 +61,7 @@ "Resources/hi.lproj/InfoPlist.strings": "macos/hi.lproj/InfoPlist.strings" }, "dmg": { - "background": "../desktop/src-tauri/assets/dmg-background.png", + "background": "packaging/macos/dmg-background.png", "appPosition": { "x": 180, "y": 140 @@ -77,9 +74,9 @@ }, "windows": { "nsis": { - "headerImage": "../desktop/src-tauri/assets/nsis-header.bmp", - "sidebarImage": "../desktop/src-tauri/assets/nsis-sidebar.bmp", - "installerIcon": "../desktop/src-tauri/icons/icon.ico", + "headerImage": "packaging/windows/nsis-header.bmp", + "sidebarImage": "packaging/windows/nsis-sidebar.bmp", + "installerIcon": "icons/icon.ico", "installerHooks": "packaging/windows/installer-hooks.nsh", "compression": "lzma" }, diff --git a/apps/desktop/src-tauri/test-data/clip-thumbnail-gop.mp4 b/apps/desktop-gpui/tests/data/clip-thumbnail-gop.mp4 similarity index 100% rename from apps/desktop/src-tauri/test-data/clip-thumbnail-gop.mp4 rename to apps/desktop-gpui/tests/data/clip-thumbnail-gop.mp4 diff --git a/apps/desktop/src-tauri/test-data/clip-thumbnail-long-gop.mp4 b/apps/desktop-gpui/tests/data/clip-thumbnail-long-gop.mp4 similarity index 100% rename from apps/desktop/src-tauri/test-data/clip-thumbnail-long-gop.mp4 rename to apps/desktop-gpui/tests/data/clip-thumbnail-long-gop.mp4 diff --git a/apps/desktop/.gitignore b/apps/desktop/.gitignore deleted file mode 100644 index 76add878f8d..00000000000 --- a/apps/desktop/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -dist \ No newline at end of file diff --git a/apps/desktop/.vscode/extensions.json b/apps/desktop/.vscode/extensions.json deleted file mode 100644 index 9f54332817c..00000000000 --- a/apps/desktop/.vscode/extensions.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"] -} diff --git a/apps/desktop/app.config.ts b/apps/desktop/app.config.ts deleted file mode 100644 index f7caac6cabc..00000000000 --- a/apps/desktop/app.config.ts +++ /dev/null @@ -1,84 +0,0 @@ -import capUIPlugin from "@cap/ui-solid/vite"; -import { defineConfig } from "@solidjs/start/config"; -import devtools from "solid-devtools/vite"; -import topLevelAwait from "vite-plugin-top-level-await"; -import wasm from "vite-plugin-wasm"; -import tsconfigPaths from "vite-tsconfig-paths"; - -const enableSolidDevtools = !!process.env.VITE_SOLID_DEVTOOLS; - -// Bundled fonts load from local assets near-instantly, so `block` is safe and -// avoids the fallback-font flash (FOUT) that `swap` causes on every window -// open. Desktop-only: web keeps `swap` for slow networks. -// No `enforce`: must run after vite:css has inlined the virtual module's -// @import statements (a `pre` transform only sees the un-inlined imports). -const fontDisplayBlock = { - name: "cap:font-display-block", - transform(code: string, id: string) { - // unplugin-fonts inlines the @fontsource CSS into its virtual - // "unfonts.css" module, so match that as well as direct imports. - const [file] = id.split("?"); - const isFontCss = - file.endsWith("unfonts.css") || - (file.includes("@fontsource") && file.endsWith(".css")); - if (!isFontCss) return; - return { - code: code.replace(/font-display:\s*swap;/g, "font-display: block;"), - map: null, - }; - }, -}; - -export default defineConfig({ - ssr: false, - server: { preset: "static" }, - // https://vitejs.dev/config - vite: () => ({ - // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` - // 1. tauri expects a fixed port, fail if that port is not available - server: { - port: 3001, - strictPort: true, - watch: { - ignored: ["**/src-tauri/**"], - }, - headers: { - "Cross-Origin-Opener-Policy": "same-origin", - "Cross-Origin-Embedder-Policy": "require-corp", - }, - }, - // 3. to make use of `TAURI_DEBUG` and other env variables - // https://tauri.studio/v1/api/config#buildconfig.beforedevcommand - envPrefix: ["VITE_", "TAURI_"], - assetsInclude: ["**/*.riv"], - plugins: [ - ...(enableSolidDevtools ? [devtools({ autoname: true })] : []), - fontDisplayBlock, - wasm(), - topLevelAwait(), - capUIPlugin, - tsconfigPaths({ - root: ".", - }), - ], - define: { - "import.meta.vitest": "undefined", - }, - optimizeDeps: { - include: [ - "@tauri-apps/plugin-os", - "@tanstack/solid-query", - "@tauri-apps/api/webviewWindow", - "@tauri-apps/plugin-dialog", - "@tauri-apps/plugin-store", - "@openpanel/web", - "uuid", - "@tauri-apps/plugin-clipboard-manager", - "@tauri-apps/api/window", - "@tauri-apps/api/core", - "@tauri-apps/api/event", - "cva", - ], - }, - }), -}); diff --git a/apps/desktop/package.json b/apps/desktop/package.json deleted file mode 100644 index 1b7ebd5e966..00000000000 --- a/apps/desktop/package.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "name": "@cap/desktop", - "type": "module", - "scripts": { - "dev": "bun run --cwd ../.. cap-setup && bun run build:sidecar && bun run build:gpui:dev && dotenv -e ../../.env -- bun run preparescript && dotenv -e ../../.env -- node ../../scripts/dev-desktop.mjs", - "build:tauri": "bun run build:sidecar && bun run build:gpui && dotenv -e ../../.env -- bun run preparescript --release && node ../../scripts/verify-gpui-release-inputs.mjs && dotenv -e ../../.env -- bun run tauri build", - "build:sidecar": "node ../../scripts/build-desktop-binaries.mjs", - "build:gpui": "node ../../scripts/run-gpui-build.mjs release", - "build:gpui:dev": "dotenv -e ../../.env -- node ../../scripts/run-gpui-build.mjs debug", - "preparescript": "node scripts/prepare.js", - "localdev": "dotenv -e ../../.env -- vinxi dev --port 3002", - "build": "vinxi build", - "tauri": "tauri", - "test:display-transport": "node --experimental-websocket scripts/desktop-display-transport-benchmark.js", - "test:memory": "node scripts/desktop-memory-soak.js", - "test:memory:unit": "vitest run scripts/desktop-memory-soak.test.js" - }, - "dependencies": { - "@aerofoil/rive-solid-canvas": "^2.1.4", - "@cap/database": "workspace:*", - "@cap/ui-solid": "workspace:*", - "@cap/utils": "workspace:*", - "@cap/web-api-contract": "workspace:*", - "@corvu/tooltip": "^0.2.1", - "@kobalte/core": "^0.13.11", - "@openpanel/web": "^1.4.1", - "@radix-ui/colors": "^3.0.0", - "@rive-app/canvas": "^2.32.2", - "@solid-primitives/bounds": "^0.0.122", - "@solid-primitives/broadcast-channel": "^0.1.1", - "@solid-primitives/context": "^0.2.3", - "@solid-primitives/date": "^2.0.23", - "@solid-primitives/deep": "^0.2.9", - "@solid-primitives/event-bus": "^1.1.1", - "@solid-primitives/event-listener": "^2.3.3", - "@solid-primitives/history": "^0.1.5", - "@solid-primitives/memo": "^1.4.2", - "@solid-primitives/mouse": "^2.1.2", - "@solid-primitives/refs": "^1.0.8", - "@solid-primitives/resize-observer": "^2.0.26", - "@solid-primitives/scheduled": "^1.4.3", - "@solid-primitives/storage": "^4.0.0", - "@solid-primitives/timer": "^1.3.9", - "@solid-primitives/websocket": "^1.2.2", - "@solidjs/router": "^0.14.2", - "@solidjs/start": "^1.1.3", - "@tanstack/solid-query": "^5.51.21", - "@tauri-apps/api": "2.8.0", - "@tauri-apps/plugin-clipboard-manager": "^2.3.0", - "@tauri-apps/plugin-deep-link": "^2.4.1", - "@tauri-apps/plugin-dialog": "2.4.2", - "@tauri-apps/plugin-fs": "2.4.2", - "@tauri-apps/plugin-http": "2.5.2", - "@tauri-apps/plugin-notification": "^2.3.0", - "@tauri-apps/plugin-opener": "^2.5.0", - "@tauri-apps/plugin-os": "^2.3.0", - "@tauri-apps/plugin-process": "2.3.0", - "@tauri-apps/plugin-shell": "^2.3.0", - "@tauri-apps/plugin-store": "^2.4.0", - "@tauri-apps/plugin-updater": "2.9.0", - "@ts-rest/core": "^3.52.1", - "@types/react-tooltip": "^4.2.4", - "cva": "npm:class-variance-authority@^0.7.0", - "effect": "^3.18.4", - "lz4-wasm": "^0.9.2", - "mp4box": "^0.5.2", - "solid-js": "^1.9.3", - "solid-markdown": "^2.0.13", - "solid-presence": "^0.1.8", - "solid-toast": "^0.5.0", - "solid-transition-group": "^0.2.3", - "unplugin-auto-import": "^0.18.2", - "unplugin-icons": "^0.19.2", - "uuid": "^9.0.1", - "vinxi": "^0.5.6", - "webcodecs": "^0.1.0", - "zod": "^3.25.76" - }, - "devDependencies": { - "@fontsource/geist-sans": "^5.0.3", - "@iconify/json": "^2.2.239", - "@solid-devtools/overlay": "^0.33.5", - "@tailwindcss/postcss": "^4.2.2", - "@tailwindcss/typography": "^0.5.9", - "@tauri-apps/cli": "2.8.4", - "@total-typescript/ts-reset": "^0.6.1", - "@types/dom-webcodecs": "^0.1.11", - "@types/uuid": "^9.0.8", - "@webgpu/types": "^0.1.44", - "autoprefixer": "^10.4.21", - "cross-env": "^7.0.3", - "solid-devtools": "^0.34.5", - "tailwind-scrollbar": "^3.1.0", - "typescript": "^5.8.3", - "vite": "^6.3.5", - "vite-plugin-top-level-await": "^1.4.4", - "vite-plugin-wasm": "^3.4.1", - "vite-tsconfig-paths": "^5.0.1", - "vitest": "~2.1.9" - } -} diff --git a/apps/desktop/postcss.config.cjs b/apps/desktop/postcss.config.cjs deleted file mode 100644 index eebbe271c7d..00000000000 --- a/apps/desktop/postcss.config.cjs +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: { - "@tailwindcss/postcss": {}, - autoprefixer: {}, - }, -}; diff --git a/apps/desktop/scripts/desktop-display-transport-benchmark.js b/apps/desktop/scripts/desktop-display-transport-benchmark.js deleted file mode 100644 index 162d2ef4980..00000000000 --- a/apps/desktop/scripts/desktop-display-transport-benchmark.js +++ /dev/null @@ -1,591 +0,0 @@ -import { spawn } from "node:child_process"; -import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; -import net from "node:net"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import { fileURLToPath, pathToFileURL } from "node:url"; -import { build } from "vite"; -import { resolveDesktopBenchmarkBrowser } from "./desktop-display-transport-browser.js"; - -const DESKTOP_ROOT = path.resolve( - path.dirname(fileURLToPath(import.meta.url)), - "..", -); -const REPO_ROOT = path.resolve(DESKTOP_ROOT, "../.."); -const DEFAULT_RECORDING = - "/tmp/cap-performance-fixtures/reference-recording.cap"; - -function parseArgs(argv) { - const options = { - recordingPath: DEFAULT_RECORDING, - fps: 60, - frames: 300, - resolution: "half", - startupDelayMs: 5000, - allowNonWebGPU: false, - keepTemp: false, - }; - - for (let index = 0; index < argv.length; index++) { - const token = argv[index]; - if (!token.startsWith("--")) continue; - if (token === "--") continue; - if (token === "--allow-non-webgpu") { - options.allowNonWebGPU = true; - continue; - } - if (token === "--keep-temp") { - options.keepTemp = true; - continue; - } - - const rawValue = token.includes("=") - ? token.slice(token.indexOf("=") + 1) - : argv[index + 1]; - if (!token.includes("=")) index++; - - if (token.startsWith("--recording-path")) options.recordingPath = rawValue; - if (token.startsWith("--fps")) options.fps = Number(rawValue); - if (token.startsWith("--frames")) options.frames = Number(rawValue); - if (token.startsWith("--resolution")) options.resolution = rawValue; - if (token.startsWith("--startup-delay-ms")) - options.startupDelayMs = Number(rawValue); - } - - return options; -} - -async function findFreePort() { - const server = net.createServer(); - await new Promise((resolve, reject) => { - server.once("error", reject); - server.listen(0, "127.0.0.1", resolve); - }); - const address = server.address(); - await new Promise((resolve) => server.close(resolve)); - return address.port; -} - -async function buildHarness(tempDir) { - const socketPath = path - .resolve(DESKTOP_ROOT, "src/utils/socket.ts") - .replaceAll(path.sep, "/"); - const entryPath = path.join(tempDir, "entry.ts"); - - writeFileSync( - entryPath, - `import { createImageDataWS, getFpsStats } from "${socketPath}"; - -const params = new URLSearchParams(window.location.search); -const wsUrl = params.get("ws"); -if (!wsUrl) throw new Error("Missing ws query param"); - -const canvas = document.getElementById("canvas"); -const status = document.getElementById("status"); -const samples = []; -const animationFrameIntervals = []; -let frameNotifications = 0; -let latestFrame = null; -let lastRequestFrameCount = 0; -let previousAnimationFrameAt = null; -let animationFrameId = null; - -function observeAnimationFrame(timestamp) { - if (previousAnimationFrameAt !== null) { - animationFrameIntervals.push(timestamp - previousAnimationFrameAt); - } - previousAnimationFrameAt = timestamp; - animationFrameId = requestAnimationFrame(observeAnimationFrame); -} - -animationFrameId = requestAnimationFrame(observeAnimationFrame); - -const [ws, isConnected, isWorkerReady, controls] = createImageDataWS( - wsUrl, - (data) => { - frameNotifications++; - latestFrame = { - width: data.width, - height: data.height, - hasBitmap: Boolean(data.bitmap), - }; - }, - () => { - lastRequestFrameCount++; - }, -); - -controls.initDirectCanvas(canvas); - -function summarizeSamples(sampleSet) { - if (sampleSet.length === 0) return null; - const average = (field) => - sampleSet.reduce((sum, sample) => sum + sample.stats[field], 0) / - sampleSet.length; - const maximum = (field) => - Math.max(...sampleSet.map((sample) => sample.stats[field])); - const sum = (field) => - sampleSet.reduce((total, sample) => total + sample.stats[field], 0); - return { - sampleCount: sampleSet.length, - avgFps: average("fps"), - avgRenderFps: average("renderFps"), - avgMbPerSec: average("mbPerSec"), - avgFrameMs: average("avgFrameMs"), - maxFrameMs: maximum("maxFrameMs"), - avgRenderMs: average("avgRenderMs"), - maxRenderMs: maximum("maxRenderMs"), - avgUploadMs: average("avgUploadMs"), - maxUploadMs: maximum("maxUploadMs"), - avgReceiveToDisplayMs: average("avgReceiveToDisplayMs"), - maxReceiveToDisplayMs: maximum("maxReceiveToDisplayMs"), - sharedBufferWrites: sum("sharedBufferWrites"), - sharedBufferFallbacks: sum("sharedBufferFallbacks"), - frameCount: sum("frameCount"), - renderCount: sum("renderCount"), - uploadCount: sum("uploadCount"), - receiveToDisplayCount: sum("receiveToDisplayCount"), - transportModes: [...new Set(sampleSet.map((sample) => sample.stats.transportMode))], - }; -} - -function snapshot() { - const stats = getFpsStats(); - const sample = { - atMs: performance.now(), - connected: isConnected(), - workerReady: isWorkerReady(), - frameNotifications, - lastRequestFrameCount, - latestFrame, - stats, - }; - samples.push(sample); - if (status) status.textContent = JSON.stringify(sample, null, 2); - return sample; -} - -const interval = window.setInterval(snapshot, 250); -window.__capDisplayBenchmarkResult = () => { - const resultSamples = samples.filter((sample) => sample.stats); - const stableSamples = resultSamples.filter( - (sample) => sample.stats.windowMs >= 500 && sample.stats.renderCount >= 15, - ); - const summarizedSamples = - stableSamples.length > 0 ? stableSamples : resultSamples; - const best = resultSamples.reduce( - (current, sample) => - !current || sample.stats.renderFps > current.stats.renderFps - ? sample - : current, - null, - ); - const mostFrames = resultSamples.reduce( - (current, sample) => - !current || sample.frameNotifications > current.frameNotifications - ? sample - : current, - null, - ); - return { - best, - mostFrames, - lastWithStats: resultSamples.at(-1) ?? null, - aggregate: summarizeSamples(summarizedSamples), - stableSampleCount: stableSamples.length, - latest: samples.at(-1) ?? null, - sampleCount: samples.length, - frameNotifications, - lastRequestFrameCount, - readyState: ws.readyState, - animationFrames: { - sampleCount: animationFrameIntervals.length, - averageFps: - animationFrameIntervals.length === 0 - ? 0 - : (animationFrameIntervals.length * 1000) / - animationFrameIntervals.reduce((total, interval) => total + interval, 0), - maximumIntervalMs: Math.max(0, ...animationFrameIntervals), - visibilityState: document.visibilityState, - hasFocus: document.hasFocus(), - }, - }; -}; -window.__capDisplayBenchmarkDispose = () => { - window.clearInterval(interval); - if (animationFrameId !== null) cancelAnimationFrame(animationFrameId); - controls.dispose(); -}; -window.__capDisplayBenchmarkReady = true; -snapshot(); -`, - ); - - await build({ - root: tempDir, - configFile: false, - base: "./", - logLevel: "warn", - build: { - outDir: "dist", - emptyOutDir: true, - target: "esnext", - lib: { - entry: entryPath, - formats: ["es"], - fileName: "entry", - }, - }, - server: { - fs: { - allow: [DESKTOP_ROOT, tempDir], - }, - }, - }); - - writeFileSync( - path.join(tempDir, "dist/index.html"), - `Cap Display Benchmark
`,
-	);
-
-	return path.join(tempDir, "dist/index.html");
-}
-
-function spawnRustBenchmark(options) {
-	const args = [
-		"run",
-		"-p",
-		"cap-desktop",
-		"--example",
-		"desktop-display-transport-benchmark",
-		"--",
-		"--recording-path",
-		options.recordingPath,
-		"--fps",
-		String(options.fps),
-		"--frames",
-		String(options.frames),
-		"--resolution",
-		options.resolution,
-		"--startup-delay-ms",
-		String(options.startupDelayMs),
-	];
-	const child = spawn("cargo", args, {
-		cwd: REPO_ROOT,
-		stdio: ["ignore", "pipe", "pipe"],
-	});
-
-	let buffer = "";
-	let wsUrlResolve;
-	let wsUrlReject;
-	const wsUrlPromise = new Promise((resolve, reject) => {
-		wsUrlResolve = resolve;
-		wsUrlReject = reject;
-	});
-	const outputLines = [];
-
-	function handleOutput(chunk, streamName) {
-		const text = chunk.toString();
-		process[streamName].write(text);
-		buffer += text;
-		let newlineIndex = buffer.indexOf("\n");
-		while (newlineIndex >= 0) {
-			const line = buffer.slice(0, newlineIndex).trim();
-			buffer = buffer.slice(newlineIndex + 1);
-			if (line) outputLines.push(line);
-			const match = line.match(/DISPLAY_WS_URL=(ws:\/\/[^\s]+)/);
-			if (match) wsUrlResolve(match[1]);
-			newlineIndex = buffer.indexOf("\n");
-		}
-	}
-
-	child.stdout.on("data", (chunk) => handleOutput(chunk, "stdout"));
-	child.stderr.on("data", (chunk) => handleOutput(chunk, "stderr"));
-	child.on("error", wsUrlReject);
-
-	const exitPromise = new Promise((resolve, reject) => {
-		child.on("exit", (code, signal) => {
-			if (code === 0) {
-				resolve({ outputLines });
-			} else {
-				reject(new Error(`Rust benchmark exited with ${code ?? signal}`));
-			}
-		});
-	});
-
-	return { child, wsUrlPromise, exitPromise };
-}
-
-function spawnChrome(debuggingPort, tempDir) {
-	const child = spawn(
-		resolveDesktopBenchmarkBrowser(),
-		[
-			`--user-data-dir=${path.join(tempDir, "chrome-profile")}`,
-			`--remote-debugging-port=${debuggingPort}`,
-			"--no-first-run",
-			"--no-default-browser-check",
-			"--disable-background-networking",
-			"--disable-component-update",
-			"--disable-extensions",
-			"--allow-file-access-from-files",
-			"--enable-unsafe-webgpu",
-			...(process.platform === "linux" && process.getuid?.() === 0
-				? ["--no-sandbox"]
-				: []),
-			...(process.env.CAP_DESKTOP_BENCHMARK_HEADLESS === "1"
-				? ["--headless=new"]
-				: []),
-			...(process.env.CAP_DESKTOP_BENCHMARK_SOFTWARE_GPU === "1"
-				? ["--use-angle=swiftshader", "--enable-unsafe-swiftshader"]
-				: []),
-			"about:blank",
-		],
-		{ stdio: ["ignore", "ignore", "pipe"] },
-	);
-	child.stderr.on("data", (chunk) => process.stderr.write(chunk));
-	return child;
-}
-
-async function waitForPage(debuggingPort, timeoutMs = 15000) {
-	const started = Date.now();
-	while (Date.now() - started < timeoutMs) {
-		try {
-			const response = await fetch(
-				`http://127.0.0.1:${debuggingPort}/json/list`,
-			);
-			const targets = await response.json();
-			const page = targets.find(
-				(target) => target.type === "page" && target.webSocketDebuggerUrl,
-			);
-			if (page) return page;
-		} catch {}
-		await new Promise((resolve) => setTimeout(resolve, 100));
-	}
-	throw new Error("Timed out waiting for Chrome page target");
-}
-
-async function connectCdp(wsUrl) {
-	const socket = new WebSocket(wsUrl);
-	const pending = new Map();
-	const eventHandlers = new Map();
-	let nextId = 1;
-
-	await new Promise((resolve, reject) => {
-		socket.addEventListener("open", resolve, { once: true });
-		socket.addEventListener("error", reject, { once: true });
-	});
-
-	socket.addEventListener("message", (event) => {
-		const message = JSON.parse(event.data);
-		if (!message.id) {
-			const handlers = eventHandlers.get(message.method);
-			if (handlers) {
-				for (const handler of handlers) handler(message.params);
-			}
-			return;
-		}
-		const entry = pending.get(message.id);
-		if (!entry) return;
-		pending.delete(message.id);
-		if (message.error) {
-			entry.reject(new Error(JSON.stringify(message.error)));
-		} else {
-			entry.resolve(message.result);
-		}
-	});
-
-	return {
-		send(method, params = {}, timeoutMs = 10000) {
-			const id = nextId++;
-			socket.send(JSON.stringify({ id, method, params }));
-			return new Promise((resolve, reject) => {
-				const timer = setTimeout(() => {
-					pending.delete(id);
-					reject(new Error(`Timed out waiting for ${method}`));
-				}, timeoutMs);
-				pending.set(id, {
-					resolve(value) {
-						clearTimeout(timer);
-						resolve(value);
-					},
-					reject(error) {
-						clearTimeout(timer);
-						reject(error);
-					},
-				});
-			});
-		},
-		on(method, handler) {
-			const handlers = eventHandlers.get(method) ?? new Set();
-			handlers.add(handler);
-			eventHandlers.set(method, handlers);
-		},
-		off(method, handler) {
-			const handlers = eventHandlers.get(method);
-			if (!handlers) return;
-			handlers.delete(handler);
-			if (handlers.size === 0) eventHandlers.delete(method);
-		},
-		close() {
-			socket.close();
-		},
-	};
-}
-
-function waitForCdpEvent(cdp, method, timeoutMs = 15000) {
-	return new Promise((resolve, reject) => {
-		const timer = setTimeout(() => {
-			cdp.off(method, handler);
-			reject(new Error(`Timed out waiting for ${method}`));
-		}, timeoutMs);
-		function handler(params) {
-			clearTimeout(timer);
-			cdp.off(method, handler);
-			resolve(params);
-		}
-		cdp.on(method, handler);
-	});
-}
-
-function sleep(ms) {
-	return new Promise((resolve) => setTimeout(resolve, ms));
-}
-
-async function stopProcess(child) {
-	if (!child || child.exitCode !== null || child.signalCode !== null) return;
-	child.kill();
-	await Promise.race([
-		new Promise((resolve) => child.once("exit", resolve)),
-		sleep(3000),
-	]);
-	if (child.exitCode === null && child.signalCode === null) {
-		child.kill("SIGKILL");
-		await Promise.race([
-			new Promise((resolve) => child.once("exit", resolve)),
-			sleep(1000),
-		]);
-	}
-}
-
-async function removeTempDir(tempDir) {
-	let lastError = null;
-	for (let attempt = 0; attempt < 5; attempt++) {
-		try {
-			rmSync(tempDir, { recursive: true, force: true });
-			return;
-		} catch (error) {
-			lastError = error;
-			await sleep(250);
-		}
-	}
-	if (lastError) {
-		console.error(`Failed to remove temp dir ${tempDir}: ${lastError.message}`);
-	}
-}
-
-async function waitForHarnessReady(cdp) {
-	const started = Date.now();
-	while (Date.now() - started < 10000) {
-		const result = await cdp.send("Runtime.evaluate", {
-			expression: "Boolean(window.__capDisplayBenchmarkReady)",
-			returnByValue: true,
-		});
-		if (result.result.value) return;
-		await new Promise((resolve) => setTimeout(resolve, 100));
-	}
-	throw new Error("Timed out waiting for display benchmark harness");
-}
-
-function assertResult(result, options) {
-	const displayStats = result.mostFrames?.stats ?? result.lastWithStats?.stats;
-	if (!displayStats) {
-		throw new Error("No desktop display stats captured");
-	}
-	if (result.frameNotifications <= 0) {
-		throw new Error("No displayed frame notifications captured");
-	}
-	const sawWebGPU =
-		displayStats.transportMode === "webgpu" ||
-		result.aggregate?.transportModes?.includes("webgpu");
-	if (!options.allowNonWebGPU && !sawWebGPU) {
-		throw new Error(
-			`Expected WebGPU transport, saw ${displayStats.transportMode}`,
-		);
-	}
-}
-
-async function main() {
-	const options = parseArgs(process.argv.slice(2));
-	const tempDir = mkdtempSync(path.join(tmpdir(), "cap-display-transport-"));
-	let chrome = null;
-	let rust = null;
-	let cdp = null;
-
-	try {
-		const indexPath = await buildHarness(tempDir);
-		rust = spawnRustBenchmark(options);
-		const wsUrl = await rust.wsUrlPromise;
-		const debuggingPort = await findFreePort();
-		const pageUrl = `${pathToFileURL(indexPath).href}?ws=${encodeURIComponent(wsUrl)}`;
-		chrome = spawnChrome(debuggingPort, tempDir);
-		const page = await waitForPage(debuggingPort);
-		cdp = await connectCdp(page.webSocketDebuggerUrl);
-		const runtimeIssues = [];
-		cdp.on("Runtime.exceptionThrown", (params) => {
-			runtimeIssues.push(params.exceptionDetails?.text ?? "Runtime exception");
-		});
-		cdp.on("Runtime.consoleAPICalled", (params) => {
-			const text = params.args
-				?.map((arg) => arg.value ?? arg.description ?? "")
-				.join(" ");
-			if (text) runtimeIssues.push(`${params.type}: ${text}`);
-		});
-		await cdp.send("Page.enable");
-		await cdp.send("Runtime.enable");
-		await cdp.send("Page.bringToFront");
-		await cdp.send("Emulation.setFocusEmulationEnabled", { enabled: true });
-		const loadPromise = waitForCdpEvent(cdp, "Page.loadEventFired").catch(
-			() => null,
-		);
-		await cdp.send("Page.navigate", { url: pageUrl });
-		await loadPromise;
-		try {
-			await waitForHarnessReady(cdp);
-		} catch (error) {
-			const snapshot = await cdp.send("Runtime.evaluate", {
-				expression:
-					"({ href: location.href, body: document.body?.innerText ?? null, ready: Boolean(window.__capDisplayBenchmarkReady) })",
-				returnByValue: true,
-			});
-			throw new Error(
-				`${error.message}; page=${JSON.stringify(snapshot.result.value)}; runtime=${JSON.stringify(runtimeIssues)}`,
-			);
-		}
-		await rust.exitPromise;
-		await new Promise((resolve) => setTimeout(resolve, 1000));
-		const evaluation = await cdp.send("Runtime.evaluate", {
-			expression: "window.__capDisplayBenchmarkResult()",
-			returnByValue: true,
-		});
-		const result = evaluation.result.value;
-		assertResult(result, options);
-		console.log(`DISPLAY_BROWSER_STATS=${JSON.stringify(result)}`);
-		await cdp.send("Runtime.evaluate", {
-			expression: "window.__capDisplayBenchmarkDispose()",
-		});
-	} finally {
-		if (cdp) cdp.close();
-		await stopProcess(chrome);
-		await stopProcess(rust?.child);
-		if (!options.keepTemp) {
-			await removeTempDir(tempDir);
-		} else {
-			console.log(`DISPLAY_BENCHMARK_TEMP=${tempDir}`);
-		}
-	}
-}
-
-main().catch((error) => {
-	console.error(error);
-	process.exit(1);
-});
diff --git a/apps/desktop/scripts/desktop-display-transport-browser.js b/apps/desktop/scripts/desktop-display-transport-browser.js
deleted file mode 100644
index 29f642a61b2..00000000000
--- a/apps/desktop/scripts/desktop-display-transport-browser.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import { existsSync } from "node:fs";
-import path from "node:path";
-
-export function resolveDesktopBenchmarkBrowser({
-	platform = process.platform,
-	environment = process.env,
-	fileExists = existsSync,
-} = {}) {
-	const override = environment.CAP_DESKTOP_BENCHMARK_BROWSER?.trim();
-	if (override) {
-		if (fileExists(override)) return override;
-		throw new Error(`Benchmark browser does not exist: ${override}`);
-	}
-
-	const candidates = [];
-	if (platform === "darwin") {
-		candidates.push(
-			"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
-			"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
-			"/Applications/Chromium.app/Contents/MacOS/Chromium",
-		);
-	} else if (platform === "win32") {
-		const roots = [
-			environment["PROGRAMFILES(X86)"] ?? "C:\\Program Files (x86)",
-			environment.PROGRAMFILES ?? "C:\\Program Files",
-			environment.LOCALAPPDATA,
-		].filter(Boolean);
-		for (const root of roots) {
-			candidates.push(
-				path.win32.join(root, "Google", "Chrome", "Application", "chrome.exe"),
-				path.win32.join(root, "Microsoft", "Edge", "Application", "msedge.exe"),
-			);
-		}
-	} else if (platform === "linux") {
-		candidates.push(
-			"/usr/bin/google-chrome-stable",
-			"/usr/bin/google-chrome",
-			"/usr/bin/chromium",
-			"/usr/bin/chromium-browser",
-			"/usr/bin/microsoft-edge",
-		);
-	}
-
-	const browser = candidates.find(fileExists);
-	if (browser) return browser;
-
-	throw new Error(
-		`No Chromium browser found for ${platform}; set CAP_DESKTOP_BENCHMARK_BROWSER to its executable path`,
-	);
-}
diff --git a/apps/desktop/scripts/desktop-display-transport-browser.test.js b/apps/desktop/scripts/desktop-display-transport-browser.test.js
deleted file mode 100644
index 3304ee6e4f2..00000000000
--- a/apps/desktop/scripts/desktop-display-transport-browser.test.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import { describe, expect, it } from "vitest";
-import { resolveDesktopBenchmarkBrowser } from "./desktop-display-transport-browser.js";
-
-describe("resolveDesktopBenchmarkBrowser", () => {
-	it("preserves the existing macOS Google Chrome selection", () => {
-		const chrome =
-			"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
-		expect(
-			resolveDesktopBenchmarkBrowser({
-				platform: "darwin",
-				environment: {},
-				fileExists: (candidate) => candidate === chrome,
-			}),
-		).toBe(chrome);
-	});
-
-	it("finds Microsoft Edge in Windows Program Files", () => {
-		const edge = "D:\\Programs\\Microsoft\\Edge\\Application\\msedge.exe";
-		expect(
-			resolveDesktopBenchmarkBrowser({
-				platform: "win32",
-				environment: {
-					"PROGRAMFILES(X86)": "D:\\Programs",
-				},
-				fileExists: (candidate) => candidate === edge,
-			}),
-		).toBe(edge);
-	});
-
-	it("finds a Linux Chromium installation", () => {
-		expect(
-			resolveDesktopBenchmarkBrowser({
-				platform: "linux",
-				environment: {},
-				fileExists: (candidate) => candidate === "/usr/bin/chromium",
-			}),
-		).toBe("/usr/bin/chromium");
-	});
-
-	it("uses an explicitly configured browser before platform discovery", () => {
-		const browser = "/opt/browser/chrome";
-		expect(
-			resolveDesktopBenchmarkBrowser({
-				platform: "linux",
-				environment: { CAP_DESKTOP_BENCHMARK_BROWSER: browser },
-				fileExists: (candidate) => candidate === browser,
-			}),
-		).toBe(browser);
-	});
-
-	it("rejects a missing explicitly configured browser", () => {
-		expect(() =>
-			resolveDesktopBenchmarkBrowser({
-				platform: "linux",
-				environment: { CAP_DESKTOP_BENCHMARK_BROWSER: "/missing/browser" },
-				fileExists: () => false,
-			}),
-		).toThrow("Benchmark browser does not exist: /missing/browser");
-	});
-
-	it("explains how to configure unsupported browser installations", () => {
-		expect(() =>
-			resolveDesktopBenchmarkBrowser({
-				platform: "linux",
-				environment: {},
-				fileExists: () => false,
-			}),
-		).toThrow("set CAP_DESKTOP_BENCHMARK_BROWSER");
-	});
-});
diff --git a/apps/desktop/scripts/desktop-memory-soak-lib.js b/apps/desktop/scripts/desktop-memory-soak-lib.js
deleted file mode 100644
index 66efbe64d4b..00000000000
--- a/apps/desktop/scripts/desktop-memory-soak-lib.js
+++ /dev/null
@@ -1,299 +0,0 @@
-import { existsSync } from "node:fs";
-import { fileURLToPath } from "node:url";
-
-const DEV_APP_COMMAND_PREFIX = fileURLToPath(
-	new URL("../../../target/debug/cap-desktop", import.meta.url),
-);
-const INSTALLED_APP_COMMAND_PREFIX = "/Applications/Cap.app/Contents/MacOS/Cap";
-
-export const DEFAULTS = {
-	appCommandPrefix:
-		process.env.CAP_APP_COMMAND_PREFIX ||
-		(existsSync(DEV_APP_COMMAND_PREFIX)
-			? DEV_APP_COMMAND_PREFIX
-			: INSTALLED_APP_COMMAND_PREFIX),
-	baselineSeconds: 30,
-	cycles: 3,
-	initialWebKitWindowSeconds: 180,
-	intervalSeconds: 10,
-	maxCycleRatchetMb: 128,
-	maxTotalGrowthMb: 768,
-	newWebKitWindowSeconds: 180,
-	recordingSeconds: 20,
-	displaySleepSeconds: 20,
-	launchTimeoutSeconds: 30,
-	stopTimeoutSeconds: 10,
-	storePath:
-		process.env.CAP_STORE_PATH ||
-		`${process.env.HOME}/Library/Application Support/so.cap.desktop.dev/store`,
-	settleSeconds: 120,
-	trailingSamples: 3,
-};
-
-const MEDIA_PROCESS_PATTERNS = [
-	["coreaudiod", /\/usr\/sbin\/coreaudiod$/],
-	[
-		"cmio-host",
-		/com\.apple\.cmio\.videodriverkithostextension\.systemextension/,
-	],
-	["cameracaptured", /\/usr\/libexec\/cameracaptured$/],
-	["continuity-agent", /\/usr\/libexec\/ContinuityCaptureAgent(?:\s|$)/],
-	["audioaccessoryd", /\/System\/Library\/CoreServices\/audioaccessoryd$/],
-	["avconferenced", /\/usr\/libexec\/avconferenced$/],
-	["vdcassistant", /\/VDC\.plugin\/Contents\/Resources\/VDCAssistant$/],
-];
-
-function toKb(mb) {
-	return Math.round(mb * 1024);
-}
-
-function parseElapsedSeconds(etime) {
-	const parts = etime.split("-");
-	const dayPart = parts.length === 2 ? Number(parts[0]) : 0;
-	const timePart = parts.length === 2 ? parts[1] : parts[0];
-	const segments = timePart.split(":").map(Number);
-
-	let hours = 0;
-	let minutes = 0;
-	let seconds = 0;
-
-	if (segments.length === 3) {
-		[hours, minutes, seconds] = segments;
-	} else if (segments.length === 2) {
-		[minutes, seconds] = segments;
-	}
-
-	return dayPart * 24 * 60 * 60 + hours * 60 * 60 + minutes * 60 + seconds;
-}
-
-export function parsePsOutput(output) {
-	return output
-		.split("\n")
-		.map((line) => line.trim())
-		.filter(Boolean)
-		.map((line) => {
-			const match = line.match(/^(\d+)\s+(\d+)\s+(\d+)\s+(\S+)\s+(.*)$/);
-
-			if (!match) return null;
-
-			const [, pid, rssKb, vszKb, etime, command] = match;
-
-			return {
-				command,
-				etimes: parseElapsedSeconds(etime),
-				pid: Number(pid),
-				rssKb: Number(rssKb),
-				vszKb: Number(vszKb),
-			};
-		})
-		.filter(Boolean);
-}
-
-export function classifyProcess(
-	command,
-	appCommandPrefix = DEFAULTS.appCommandPrefix,
-) {
-	if (
-		command.startsWith(
-			"/System/Library/PrivateFrameworks/SkyLight.framework/Resources/WindowServer",
-		)
-	) {
-		return {
-			group: "system",
-			kind: "window-server",
-			label: "windowserver",
-		};
-	}
-
-	if (command === appCommandPrefix) {
-		return { group: "cap", kind: "cap-main", label: "cap-main" };
-	}
-
-	if (command.startsWith(`${appCommandPrefix} --crash-reporter-server=`)) {
-		return { group: "cap", kind: "cap-crash", label: "cap-crash" };
-	}
-
-	if (command.includes("com.apple.WebKit.GPU.xpc")) {
-		return { group: "cap", kind: "webkit-gpu", label: "wk-gpu" };
-	}
-
-	if (command.includes("com.apple.WebKit.Networking.xpc")) {
-		return { group: "cap", kind: "webkit-networking", label: "wk-net" };
-	}
-
-	if (command.includes("com.apple.WebKit.WebContent.xpc")) {
-		return { group: "cap", kind: "webkit-webcontent", label: "wk-webcontent" };
-	}
-
-	for (const [label, pattern] of MEDIA_PROCESS_PATTERNS) {
-		if (pattern.test(command)) {
-			return { group: "media", kind: label, label };
-		}
-	}
-
-	return null;
-}
-
-export function findCapMainProcess(
-	processes,
-	appCommandPrefix = DEFAULTS.appCommandPrefix,
-) {
-	return processes
-		.filter((processInfo) => processInfo.command === appCommandPrefix)
-		.sort((left, right) => right.etimes - left.etimes)[0];
-}
-
-export function discoverTrackedProcesses(
-	processes,
-	tracked,
-	options = DEFAULTS,
-) {
-	const nextTracked = new Map(tracked);
-	const capMain = findCapMainProcess(processes, options.appCommandPrefix);
-
-	if (!capMain) {
-		throw new Error(
-			`No running Cap process found for ${options.appCommandPrefix}`,
-		);
-	}
-
-	for (const processInfo of processes) {
-		const classification = classifyProcess(
-			processInfo.command,
-			options.appCommandPrefix,
-		);
-
-		if (!classification) continue;
-
-		const isAlreadyTracked = nextTracked.has(processInfo.pid);
-		const isLongLivedCapWebKit =
-			classification.group === "cap" &&
-			classification.kind.startsWith("webkit-") &&
-			Math.abs(processInfo.etimes - capMain.etimes) <=
-				options.initialWebKitWindowSeconds;
-		const isFreshCapWebKit =
-			classification.group === "cap" &&
-			classification.kind.startsWith("webkit-") &&
-			processInfo.etimes <= options.newWebKitWindowSeconds;
-		const shouldTrack =
-			classification.kind === "cap-main" ||
-			classification.kind === "cap-crash" ||
-			classification.group === "system" ||
-			classification.group === "media" ||
-			isLongLivedCapWebKit ||
-			isFreshCapWebKit;
-
-		if (!shouldTrack) continue;
-
-		nextTracked.set(processInfo.pid, {
-			...processInfo,
-			...classification,
-			isNew: !isAlreadyTracked,
-		});
-	}
-
-	return nextTracked;
-}
-
-export function buildSample(processes, tracked, options = DEFAULTS) {
-	const discoveredTracked = discoverTrackedProcesses(
-		processes,
-		tracked,
-		options,
-	);
-	const liveTracked = new Map();
-	let capTotalKb = 0;
-	let mediaTotalKb = 0;
-	let windowServerTotalKb = 0;
-	const processRows = [];
-	const newPids = [];
-
-	for (const [pid, trackedProcess] of discoveredTracked.entries()) {
-		const liveProcess = processes.find(
-			(processInfo) => processInfo.pid === pid,
-		);
-
-		if (!liveProcess) continue;
-
-		const row = {
-			...trackedProcess,
-			etimes: liveProcess.etimes,
-			rssKb: liveProcess.rssKb,
-			vszKb: liveProcess.vszKb,
-		};
-
-		liveTracked.set(pid, row);
-		processRows.push(row);
-
-		if (row.group === "cap") capTotalKb += row.rssKb;
-		if (row.group === "media") mediaTotalKb += row.rssKb;
-		if (row.group === "system") windowServerTotalKb += row.rssKb;
-		if (row.isNew) newPids.push(pid);
-	}
-
-	processRows.sort((left, right) => right.rssKb - left.rssKb);
-
-	return {
-		capTotalKb,
-		grandTotalKb: capTotalKb + mediaTotalKb + windowServerTotalKb,
-		mediaTotalKb,
-		newPids: newPids.sort((left, right) => left - right),
-		processRows,
-		tracked: liveTracked,
-		windowServerTotalKb,
-	};
-}
-
-export function pickSettledSample(
-	samples,
-	trailingSamples = DEFAULTS.trailingSamples,
-) {
-	if (samples.length === 0) {
-		throw new Error("Cannot pick a settled sample from an empty set");
-	}
-
-	const window = samples.slice(-Math.min(trailingSamples, samples.length));
-
-	return window.reduce((best, sample) =>
-		sample.grandTotalKb < best.grandTotalKb ? sample : best,
-	);
-}
-
-export function evaluateCycles(
-	baselineKb,
-	settledCycleKbs,
-	options = DEFAULTS,
-) {
-	const maxCycleRatchetKb = toKb(options.maxCycleRatchetMb);
-	const maxTotalGrowthKb = toKb(options.maxTotalGrowthMb);
-	const failures = [];
-
-	for (let index = 0; index < settledCycleKbs.length; index += 1) {
-		const current = settledCycleKbs[index];
-		const previous = index === 0 ? baselineKb : settledCycleKbs[index - 1];
-		const cycleDeltaKb = current - previous;
-		const totalDeltaKb = current - baselineKb;
-
-		if (cycleDeltaKb > maxCycleRatchetKb) {
-			failures.push({
-				cycle: index + 1,
-				type: "cycle-ratchet",
-				valueKb: cycleDeltaKb,
-			});
-		}
-
-		if (totalDeltaKb > maxTotalGrowthKb) {
-			failures.push({
-				cycle: index + 1,
-				type: "total-growth",
-				valueKb: totalDeltaKb,
-			});
-		}
-	}
-
-	return failures;
-}
-
-export function formatMb(kb) {
-	return `${(kb / 1024).toFixed(1)} MB`;
-}
diff --git a/apps/desktop/scripts/desktop-memory-soak.js b/apps/desktop/scripts/desktop-memory-soak.js
deleted file mode 100644
index 1cfd23ae91c..00000000000
--- a/apps/desktop/scripts/desktop-memory-soak.js
+++ /dev/null
@@ -1,583 +0,0 @@
-import { execFileSync, spawn } from "node:child_process";
-import { existsSync, readFileSync, writeFileSync } from "node:fs";
-import process from "node:process";
-import { createInterface } from "node:readline/promises";
-import { setTimeout as sleep } from "node:timers/promises";
-import {
-	buildSample,
-	DEFAULTS,
-	evaluateCycles,
-	findCapMainProcess,
-	formatMb,
-	parsePsOutput,
-	pickSettledSample,
-} from "./desktop-memory-soak-lib.js";
-
-const HOTKEYS = {
-	startStudioRecording: {
-		code: "KeyR",
-		meta: true,
-		ctrl: true,
-		alt: true,
-		shift: true,
-	},
-	stopRecording: {
-		code: "KeyT",
-		meta: true,
-		ctrl: true,
-		alt: true,
-		shift: true,
-	},
-};
-
-const APPLE_KEY_CODES = {
-	KeyR: 15,
-	KeyT: 17,
-};
-
-const INSTALLED_APP_COMMAND_PREFIX = "/Applications/Cap.app/Contents/MacOS/Cap";
-
-function parseArgs(argv) {
-	const options = {
-		...DEFAULTS,
-		manual: false,
-		skipDisplaySleep: false,
-	};
-
-	for (let index = 0; index < argv.length; index += 1) {
-		const token = argv[index];
-		const next = argv[index + 1];
-
-		if (token === "--help" || token === "-h") {
-			options.help = true;
-			continue;
-		}
-
-		if (!token.startsWith("--")) continue;
-
-		if (token === "--manual") {
-			options.manual = true;
-			continue;
-		}
-
-		if (token === "--skip-display-sleep") {
-			options.skipDisplaySleep = true;
-			continue;
-		}
-
-		const rawValue = token.includes("=")
-			? token.slice(token.indexOf("=") + 1)
-			: next;
-
-		if (token.startsWith("--app-command-prefix")) {
-			options.appCommandPrefix = rawValue;
-			if (!token.includes("=")) index += 1;
-			continue;
-		}
-
-		if (token.startsWith("--store-path")) {
-			options.storePath = rawValue;
-			if (!token.includes("=")) index += 1;
-			continue;
-		}
-
-		const value = Number(rawValue);
-
-		if (token.startsWith("--cycles")) {
-			options.cycles = value;
-			if (!token.includes("=")) index += 1;
-			continue;
-		}
-
-		if (token.startsWith("--baseline-seconds")) {
-			options.baselineSeconds = value;
-			if (!token.includes("=")) index += 1;
-			continue;
-		}
-
-		if (token.startsWith("--settle-seconds")) {
-			options.settleSeconds = value;
-			if (!token.includes("=")) index += 1;
-			continue;
-		}
-
-		if (token.startsWith("--interval-seconds")) {
-			options.intervalSeconds = value;
-			if (!token.includes("=")) index += 1;
-			continue;
-		}
-
-		if (token.startsWith("--max-cycle-ratchet-mb")) {
-			options.maxCycleRatchetMb = value;
-			if (!token.includes("=")) index += 1;
-			continue;
-		}
-
-		if (token.startsWith("--max-total-growth-mb")) {
-			options.maxTotalGrowthMb = value;
-			if (!token.includes("=")) index += 1;
-			continue;
-		}
-
-		if (token.startsWith("--new-webkit-window-seconds")) {
-			options.newWebKitWindowSeconds = value;
-			if (!token.includes("=")) index += 1;
-			continue;
-		}
-
-		if (token.startsWith("--initial-webkit-window-seconds")) {
-			options.initialWebKitWindowSeconds = value;
-			if (!token.includes("=")) index += 1;
-			continue;
-		}
-
-		if (token.startsWith("--recording-seconds")) {
-			options.recordingSeconds = value;
-			if (!token.includes("=")) index += 1;
-			continue;
-		}
-
-		if (token.startsWith("--display-sleep-seconds")) {
-			options.displaySleepSeconds = value;
-			if (!token.includes("=")) index += 1;
-			continue;
-		}
-
-		if (token.startsWith("--launch-timeout-seconds")) {
-			options.launchTimeoutSeconds = value;
-			if (!token.includes("=")) index += 1;
-			continue;
-		}
-
-		if (token.startsWith("--stop-timeout-seconds")) {
-			options.stopTimeoutSeconds = value;
-			if (!token.includes("=")) index += 1;
-		}
-	}
-
-	return options;
-}
-
-function printHelp() {
-	console.log("Cap desktop memory soak test");
-	console.log("");
-	console.log("Usage:");
-	console.log("  bun run --cwd apps/desktop test:memory [options]");
-	console.log("");
-	console.log("Options:");
-	console.log(
-		`  --cycles                        default ${DEFAULTS.cycles}`,
-	);
-	console.log(
-		`  --baseline-seconds              default ${DEFAULTS.baselineSeconds}`,
-	);
-	console.log(
-		`  --settle-seconds                default ${DEFAULTS.settleSeconds}`,
-	);
-	console.log(
-		`  --interval-seconds              default ${DEFAULTS.intervalSeconds}`,
-	);
-	console.log(
-		`  --max-cycle-ratchet-mb          default ${DEFAULTS.maxCycleRatchetMb}`,
-	);
-	console.log(
-		`  --max-total-growth-mb           default ${DEFAULTS.maxTotalGrowthMb}`,
-	);
-	console.log(
-		`  --new-webkit-window-seconds     default ${DEFAULTS.newWebKitWindowSeconds}`,
-	);
-	console.log(
-		`  --initial-webkit-window-seconds  default ${DEFAULTS.initialWebKitWindowSeconds}`,
-	);
-	console.log(
-		`  --recording-seconds             default ${DEFAULTS.recordingSeconds}`,
-	);
-	console.log(
-		`  --display-sleep-seconds         default ${DEFAULTS.displaySleepSeconds}`,
-	);
-	console.log(
-		`  --launch-timeout-seconds        default ${DEFAULTS.launchTimeoutSeconds}`,
-	);
-	console.log(
-		`  --stop-timeout-seconds          default ${DEFAULTS.stopTimeoutSeconds}`,
-	);
-	console.log(
-		`  --app-command-prefix         default ${DEFAULTS.appCommandPrefix}`,
-	);
-	console.log(
-		`  --store-path                 default ${DEFAULTS.storePath}`,
-	);
-	console.log(
-		"  --manual                           keep the old prompt-driven flow",
-	);
-	console.log(
-		"  --skip-display-sleep               skip pmset displaysleepnow",
-	);
-	console.log("");
-	console.log(
-		"The script launches the target Cap binary, rewrites the selected store with temporary hotkeys, tracks Cap, WindowServer, related WebKit helpers, and camera/audio daemons, and restores the store afterward.",
-	);
-	console.log(
-		"Quit any other Cap instance before running this so WindowServer noise stays attributable to the dev build.",
-	);
-}
-
-function readProcesses() {
-	const output = execFileSync(
-		"ps",
-		["-axo", "pid=,rss=,vsz=,etime=,command="],
-		{ encoding: "utf8" },
-	);
-
-	return parsePsOutput(output);
-}
-
-function sampleCount(durationSeconds, intervalSeconds) {
-	return Math.max(1, Math.ceil(durationSeconds / intervalSeconds));
-}
-
-function renderTopProcesses(sample) {
-	return sample.processRows
-		.slice(0, 5)
-		.map((row) => `${row.label}:${row.pid}:${formatMb(row.rssKb)}`)
-		.join("  ");
-}
-
-async function collectPhase(name, seconds, intervalSeconds, tracked, options) {
-	const samples = [];
-	let currentTracked = tracked;
-	const totalSamples = sampleCount(seconds, intervalSeconds);
-
-	for (let index = 0; index < totalSamples; index += 1) {
-		const sample = buildSample(readProcesses(), currentTracked, options);
-		currentTracked = sample.tracked;
-		samples.push(sample);
-
-		const newPidSummary =
-			sample.newPids.length > 0 ? ` new:${sample.newPids.join(",")}` : "";
-
-		console.log(
-			`${name} ${index + 1}/${totalSamples} cap=${formatMb(sample.capTotalKb)} ws=${formatMb(sample.windowServerTotalKb)} media=${formatMb(sample.mediaTotalKb)} total=${formatMb(sample.grandTotalKb)}${newPidSummary}`,
-		);
-		console.log(`  ${renderTopProcesses(sample)}`);
-
-		if (index < totalSamples - 1) {
-			await sleep(intervalSeconds * 1000);
-		}
-	}
-
-	return {
-		samples,
-		settled: pickSettledSample(samples, options.trailingSamples),
-		tracked: currentTracked,
-	};
-}
-
-function restoreStore(path, originalStoreContents) {
-	writeFileSync(path, originalStoreContents);
-}
-
-function writeAutomationStore(path) {
-	if (!existsSync(path)) {
-		throw new Error(`Store not found: ${path}`);
-	}
-
-	const originalStoreContents = readFileSync(path, "utf8");
-	const originalStore = JSON.parse(originalStoreContents);
-	const nextStore = {
-		...originalStore,
-		hotkeys: {
-			hotkeys: {
-				...(originalStore.hotkeys?.hotkeys ?? {}),
-				startStudioRecording: HOTKEYS.startStudioRecording,
-				stopRecording: HOTKEYS.stopRecording,
-			},
-		},
-		recording_settings: {
-			...(originalStore.recording_settings ?? {}),
-			mode: "studio",
-			target: null,
-		},
-	};
-
-	writeFileSync(path, `${JSON.stringify(nextStore, null, 2)}\n`);
-
-	return originalStoreContents;
-}
-
-function modifiersForHotkey(hotkey) {
-	return [
-		hotkey.meta ? "command down" : null,
-		hotkey.ctrl ? "control down" : null,
-		hotkey.alt ? "option down" : null,
-		hotkey.shift ? "shift down" : null,
-	]
-		.filter(Boolean)
-		.join(", ");
-}
-
-function pressHotkey(hotkey) {
-	const keyCode = APPLE_KEY_CODES[hotkey.code];
-
-	if (keyCode === undefined) {
-		throw new Error(`Unsupported hotkey code: ${hotkey.code}`);
-	}
-
-	execFileSync("osascript", [
-		"-e",
-		`tell application "System Events" to key code ${keyCode} using {${modifiersForHotkey(hotkey)}}`,
-	]);
-}
-
-function sleepDisplay() {
-	execFileSync("pmset", ["displaysleepnow"]);
-}
-
-function listOtherCapProcesses(options) {
-	return readProcesses().filter(
-		(processInfo) =>
-			processInfo.command !== options.appCommandPrefix &&
-			(processInfo.command === INSTALLED_APP_COMMAND_PREFIX ||
-				processInfo.command ===
-					`${INSTALLED_APP_COMMAND_PREFIX} --crash-reporter-server=/tmp/socket` ||
-				processInfo.command.startsWith(
-					`${INSTALLED_APP_COMMAND_PREFIX} --crash-reporter-server=`,
-				) ||
-				processInfo.command.endsWith("/target/debug/cap-desktop")),
-	);
-}
-
-async function waitForApp(options) {
-	const deadline = Date.now() + options.launchTimeoutSeconds * 1000;
-
-	while (Date.now() < deadline) {
-		const app = findCapMainProcess(readProcesses(), options.appCommandPrefix);
-
-		if (app) return app;
-
-		await sleep(500);
-	}
-
-	throw new Error(
-		`Cap did not launch within ${options.launchTimeoutSeconds} seconds: ${options.appCommandPrefix}`,
-	);
-}
-
-async function waitForAppExit(child, timeoutSeconds) {
-	const deadline = Date.now() + timeoutSeconds * 1000;
-
-	while (Date.now() < deadline) {
-		if (child.exitCode !== null) return;
-		await sleep(250);
-	}
-}
-
-async function stopChild(child, timeoutSeconds) {
-	if (!child || child.exitCode !== null) return;
-
-	child.kill("SIGTERM");
-	await waitForAppExit(child, timeoutSeconds);
-
-	if (child.exitCode !== null) return;
-
-	child.kill("SIGKILL");
-	await waitForAppExit(child, 2);
-}
-
-async function runAutomatedCycle(cycle, tracked, options) {
-	console.log(`Cycle ${cycle}/${options.cycles}: start recording`);
-	pressHotkey(HOTKEYS.startStudioRecording);
-	await sleep(options.recordingSeconds * 1000);
-
-	if (!options.skipDisplaySleep) {
-		console.log(
-			`Cycle ${cycle}/${options.cycles}: sleep display for ${options.displaySleepSeconds}s`,
-		);
-		sleepDisplay();
-		await sleep(options.displaySleepSeconds * 1000);
-	}
-
-	console.log(`Cycle ${cycle}/${options.cycles}: stop recording`);
-	pressHotkey(HOTKEYS.stopRecording);
-	await sleep(1000);
-	pressHotkey(HOTKEYS.stopRecording);
-	await sleep(3000);
-
-	return collectPhase(
-		`cycle-${cycle}`,
-		options.settleSeconds,
-		options.intervalSeconds,
-		tracked,
-		options,
-	);
-}
-
-async function main() {
-	if (process.platform !== "darwin") {
-		console.error("This soak test only supports macOS.");
-		process.exit(1);
-	}
-
-	const options = parseArgs(process.argv.slice(2));
-
-	if (options.help) {
-		printHelp();
-		return;
-	}
-
-	const existingTargetProcess = findCapMainProcess(
-		readProcesses(),
-		options.appCommandPrefix,
-	);
-	if (existingTargetProcess) {
-		throw new Error(
-			`Quit the target app before running the soak test: ${options.appCommandPrefix}`,
-		);
-	}
-
-	const otherCapProcesses = listOtherCapProcesses(options);
-	if (otherCapProcesses.length > 0) {
-		throw new Error(
-			`Quit other Cap processes before running the soak test: ${otherCapProcesses.map((processInfo) => processInfo.command).join(", ")}`,
-		);
-	}
-
-	let originalStoreContents = null;
-	let child = null;
-	let cleanupStarted = false;
-	const rl = options.manual
-		? createInterface({
-				input: process.stdin,
-				output: process.stdout,
-			})
-		: null;
-
-	const cleanup = async () => {
-		if (cleanupStarted) return;
-		cleanupStarted = true;
-		await stopChild(child, options.stopTimeoutSeconds);
-		if (originalStoreContents !== null) {
-			restoreStore(options.storePath, originalStoreContents);
-		}
-	};
-
-	for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) {
-		process.on(signal, () => {
-			cleanup()
-				.then(() => process.exit(1))
-				.catch((error) => {
-					console.error(error instanceof Error ? error.message : String(error));
-					process.exit(1);
-				});
-		});
-	}
-
-	try {
-		originalStoreContents = writeAutomationStore(options.storePath);
-
-		if (!existsSync(options.appCommandPrefix)) {
-			throw new Error(`App binary not found: ${options.appCommandPrefix}`);
-		}
-
-		child = spawn(options.appCommandPrefix, [], {
-			stdio: "ignore",
-		});
-
-		await waitForApp(options);
-		await sleep(3000);
-
-		let tracked = new Map();
-
-		console.log("Collecting baseline...");
-		const baselinePhase = await collectPhase(
-			"baseline",
-			options.baselineSeconds,
-			options.intervalSeconds,
-			tracked,
-			options,
-		);
-		tracked = baselinePhase.tracked;
-
-		const baseline = baselinePhase.settled;
-		console.log(
-			`Baseline settled total=${formatMb(baseline.grandTotalKb)} cap=${formatMb(baseline.capTotalKb)} ws=${formatMb(baseline.windowServerTotalKb)} media=${formatMb(baseline.mediaTotalKb)}`,
-		);
-
-		const cycleSettledTotals = [];
-
-		for (let cycle = 1; cycle <= options.cycles; cycle += 1) {
-			const phase = options.manual
-				? await rl
-						.question(
-							`Cycle ${cycle}/${options.cycles}: start and stop a recording in Cap, then press Enter.`,
-						)
-						.then(() =>
-							collectPhase(
-								`cycle-${cycle}`,
-								options.settleSeconds,
-								options.intervalSeconds,
-								tracked,
-								options,
-							),
-						)
-				: await runAutomatedCycle(cycle, tracked, options);
-			tracked = phase.tracked;
-
-			const settled = phase.settled;
-			cycleSettledTotals.push(settled.grandTotalKb);
-
-			const previousSettled =
-				cycle === 1
-					? baseline.grandTotalKb
-					: cycleSettledTotals[cycleSettledTotals.length - 2];
-			const cycleDeltaKb = settled.grandTotalKb - previousSettled;
-			const totalDeltaKb = settled.grandTotalKb - baseline.grandTotalKb;
-			const newWebContent = settled.processRows
-				.filter((row) => row.kind === "webkit-webcontent" && row.isNew)
-				.map((row) => row.pid);
-
-			console.log(
-				`Settled cycle ${cycle}: total=${formatMb(settled.grandTotalKb)} cap=${formatMb(settled.capTotalKb)} ws=${formatMb(settled.windowServerTotalKb)} media=${formatMb(settled.mediaTotalKb)} delta-prev=${formatMb(cycleDeltaKb)} delta-baseline=${formatMb(totalDeltaKb)}`,
-			);
-
-			if (newWebContent.length > 0) {
-				console.log(`  new-webcontent=${newWebContent.join(",")}`);
-			}
-		}
-
-		const failures = evaluateCycles(
-			baseline.grandTotalKb,
-			cycleSettledTotals,
-			options,
-		);
-
-		console.log("");
-		console.log("Summary");
-		console.log(
-			`  baseline=${formatMb(baseline.grandTotalKb)} final=${formatMb(cycleSettledTotals[cycleSettledTotals.length - 1] ?? baseline.grandTotalKb)}`,
-		);
-
-		if (failures.length === 0) {
-			console.log("  result=PASS");
-			return;
-		}
-
-		console.log("  result=FAIL");
-
-		for (const failure of failures) {
-			console.log(
-				`  cycle=${failure.cycle} type=${failure.type} value=${formatMb(failure.valueKb)}`,
-			);
-		}
-
-		process.exitCode = 1;
-	} finally {
-		await cleanup();
-		rl?.close();
-	}
-}
-
-main().catch((error) => {
-	console.error(error instanceof Error ? error.message : String(error));
-	process.exit(1);
-});
diff --git a/apps/desktop/scripts/desktop-memory-soak.test.js b/apps/desktop/scripts/desktop-memory-soak.test.js
deleted file mode 100644
index d367a153692..00000000000
--- a/apps/desktop/scripts/desktop-memory-soak.test.js
+++ /dev/null
@@ -1,95 +0,0 @@
-import { describe, expect, it } from "vitest";
-import {
-	buildSample,
-	classifyProcess,
-	DEFAULTS,
-	evaluateCycles,
-	parsePsOutput,
-	pickSettledSample,
-} from "./desktop-memory-soak-lib.js";
-
-describe("desktop-memory-soak", () => {
-	it("classifies Cap and media processes", () => {
-		expect(classifyProcess(DEFAULTS.appCommandPrefix)).toMatchObject({
-			group: "cap",
-			kind: "cap-main",
-		});
-		expect(
-			classifyProcess(
-				`${DEFAULTS.appCommandPrefix} --crash-reporter-server=/tmp/socket`,
-			),
-		).toMatchObject({
-			group: "cap",
-			kind: "cap-crash",
-		});
-		expect(
-			classifyProcess(
-				"/System/Library/Frameworks/WebKit.framework/Versions/A/XPCServices/com.apple.WebKit.WebContent.xpc/Contents/MacOS/com.apple.WebKit.WebContent",
-			),
-		).toMatchObject({
-			group: "cap",
-			kind: "webkit-webcontent",
-		});
-		expect(classifyProcess("/usr/sbin/coreaudiod")).toMatchObject({
-			group: "media",
-			kind: "coreaudiod",
-		});
-		expect(
-			classifyProcess(
-				"/System/Library/PrivateFrameworks/SkyLight.framework/Resources/WindowServer -daemon",
-			),
-		).toMatchObject({
-			group: "system",
-			kind: "window-server",
-		});
-	});
-
-	it("parses ps output and totals tracked processes", () => {
-		const processes = parsePsOutput(`
-1000 1200000 435000000 00:16:39 /System/Library/PrivateFrameworks/SkyLight.framework/Resources/WindowServer -daemon
-2004 400000 441000000 00:02:00 ${DEFAULTS.appCommandPrefix}
-2005 25000 435000000 00:02:00 ${DEFAULTS.appCommandPrefix} --crash-reporter-server=/tmp/socket
-2008 90000 440000000 00:02:00 /System/Library/Frameworks/WebKit.framework/Versions/A/XPCServices/com.apple.WebKit.GPU.xpc/Contents/MacOS/com.apple.WebKit.GPU
-2075 300000 507000000 00:01:55 /System/Library/Frameworks/WebKit.framework/Versions/A/XPCServices/com.apple.WebKit.WebContent.xpc/Contents/MacOS/com.apple.WebKit.WebContent
-431 50000 435000000 00:16:39 /usr/sbin/coreaudiod
-532 20000 435000000 00:16:39 /usr/libexec/cameracaptured
-`);
-
-		const sample = buildSample(processes, new Map(), DEFAULTS);
-
-		expect(sample.capTotalKb).toBe(815000);
-		expect(sample.mediaTotalKb).toBe(70000);
-		expect(sample.windowServerTotalKb).toBe(1200000);
-		expect(sample.grandTotalKb).toBe(2085000);
-		expect(sample.newPids).toEqual([431, 532, 1000, 2004, 2005, 2008, 2075]);
-	});
-
-	it("picks the lowest sample from the trailing settle window", () => {
-		const settled = pickSettledSample(
-			[
-				{ grandTotalKb: 1200 },
-				{ grandTotalKb: 1000 },
-				{ grandTotalKb: 900 },
-				{ grandTotalKb: 950 },
-			],
-			3,
-		);
-
-		expect(settled.grandTotalKb).toBe(900);
-	});
-
-	it("flags cycle ratchet and total growth failures", () => {
-		const failures = evaluateCycles(1000, [1200, 1400, 2200], {
-			...DEFAULTS,
-			maxCycleRatchetMb: 0.1,
-			maxTotalGrowthMb: 0.5,
-		});
-
-		expect(failures).toEqual([
-			{ cycle: 1, type: "cycle-ratchet", valueKb: 200 },
-			{ cycle: 2, type: "cycle-ratchet", valueKb: 200 },
-			{ cycle: 3, type: "cycle-ratchet", valueKb: 800 },
-			{ cycle: 3, type: "total-growth", valueKb: 1200 },
-		]);
-	});
-});
diff --git a/apps/desktop/scripts/desktop-picker-performance.md b/apps/desktop/scripts/desktop-picker-performance.md
deleted file mode 100644
index a8a7f2af909..00000000000
--- a/apps/desktop/scripts/desktop-picker-performance.md
+++ /dev/null
@@ -1,64 +0,0 @@
-# Desktop picker latency
-
-The display and window pickers should reuse healthy selected devices. Restoring saved inputs must not open error dialogs for disconnected devices. Recording still waits for input setup, and missing selections remain saved for reconnection.
-
-## Benchmarks
-
-The ignored native benchmark runs real device discovery, microphone configuration lookups, camera setup, and camera frame delivery. It compares repeated camera setup with reuse and compares microphone lookup strategies in the same process. It opens the specified camera without creating recordings.
-
-```sh
-cd apps/desktop-gpui
-CAP_PICKER_BENCH_CAMERA_ID= cargo test -p cap-desktop-gpui --bin cap-gpui picker_benchmark::native_picker_latency -- --ignored --nocapture
-```
-
-Both debug apps also support `CAP_PICKER_BENCHMARK_OUTPUT=` and `CAP_PICKER_BENCHMARK_DELAY_MS=0`. They open and dismiss six alternating display/window pickers, write timings, and exit. The default delay is 2000 ms. Run them sequentially after compilation has finished.
-
-The Tauri app also takes `CAP_PICKER_BENCHMARK_SAMPLES=` to run more than six picker cycles and `CAP_PICKER_BENCHMARK_CAMERA_CYCLES=` to follow them with camera-window close/reopen cycles (written to `.camera.json`), and `CAP_PICKER_BENCHMARK_ESCAPE=direct` (or `wait:`, for an external driver sending a real Escape keypress) to check the picker is dismissed through the Escape path (written to `.escape.json`). Together with `NSZombieEnabled=YES` this is the overlay soak that guards the vendored `tauri-nspanel` ownership fix: the picker reveal converts its overlay windows to NSPanels on every open, and the camera window is destroyed and recreated under one label, so an over-release in either path shows up as a `message sent to deallocated instance` line or a crash within a few cycles instead of in a user's session.
-
-```sh
-NSZombieEnabled=YES CAP_PICKER_BENCHMARK_OUTPUT=/tmp/picker.json CAP_PICKER_BENCHMARK_SAMPLES=200 CAP_PICKER_BENCHMARK_CAMERA_CYCLES=30 target/debug/cap-desktop
-```
-
-- Tauri measures from the target-mode request through native window creation, frontend initialization, input restoration, and two animation frames with the recording button enabled.
-- GPUI includes pending device discovery and selected-input readiness, then waits for two rendered overlay frames.
-- Sample zero measures the first picker in a fresh process. Later samples measure reopening. These are picker timings, not total process launch times. They are not directly interchangeable across UI implementations.
-
-Use isolated settings for these app runs. GPUI accepts `CAP_GPUI_APP_DATA_DIR`. Build Tauri with a separate `TAURI_CONFIG` identifier and seed only that identifier's application-data `store`. Set the recording mode to `studio` and select the test inputs in that store. Never point a benchmark at customer recordings or an active recording session.
-
-For a Tauri build with bundled frontend assets and no development server:
-
-```sh
-pnpm --filter @cap/desktop build
-TAURI_CONFIG='{"identifier":"so.cap.desktop.picker-benchmark","productName":"Cap Picker Benchmark","build":{"devUrl":null}}' cargo build -p cap-desktop --features tauri/custom-protocol
-```
-
-## What changed
-
-- Startup restoration bypasses the global mutation handler that displays native error dialogs. Explicit device selections retain their normal error handling.
-- Matching simultaneous Tauri requests share pending setup. A different device, configuration, or camera-window request supersedes it.
-- Repeated Tauri selections reuse a feed only when its identity and settings match and frames or audio samples arrived within 250 ms. Stalled feeds continue through setup and recovery.
-- Camera-only mode retains its normal camera setup path, which also handles its different preview routing.
-- GPUI startup lists microphone names without opening every device's audio configuration. Detailed configuration remains available when opening the microphone menu.
-- Tauri microphone details configure only the requested device, avoiding a complete configuration scan for each row.
-- The picker keeps its action label while readiness checks run.
-
-## Local comparison, 2026-09-09
-
-On macOS with five cameras, five microphones, one display, and twelve listed windows; the built-in camera and microphone were selected. The baseline used the original Rust selection/discovery paths from `0c403be8a57f7ba4de67140273708a392c8b4050`. Both variants used the same frontend, timing hooks, settings, and build profile. Runs were sequential with no compilation in progress.
-
-| UI measurement | Before | After |
-| --- | ---: | ---: |
-| Tauri first display picker | 1,921 ms | 955 ms |
-| Tauri reopening, median of five alternating display/window openings | 815 ms | 65 ms |
-| GPUI first display picker | 1,046 ms | 679 ms |
-| GPUI reopening, median of five alternating display/window openings | 28 ms | 24 ms |
-
-All 24 openings reached readiness. GPUI reopening was already fast; its improvement is in discovery during startup. Across the optimized Tauri run, native logs showed one microphone setup and one camera setup for all six openings.
-
-The final native comparison measured median microphone metadata lookup time of 1,579 ms for repeated full scans versus 187 ms for named lookups. Repeated camera setup took 433 ms; checking an already-streaming matching camera took 0.02 ms, with subsequent frames received in every sample. That last number is the feed acknowledgment time, not UI latency or first-frame startup.
-
-An additional Tauri run restored the unavailable `Shure MV7+` and `046d:08e5` selections. All six pickers reached readiness without blocking dialogs, and both selections remained persisted. Cold samples are individual observations, not percentile estimates.
-
-## Validation boundaries
-
-The local measurements exercise macOS hardware and debug Rust builds with bundled production frontend assets. They do not establish Windows hardware latency or release-package behavior. Keep cold samples separate from reopening samples, and preserve device counts and first-frame checks when comparing runs.
diff --git a/apps/desktop/scripts/prepare.js b/apps/desktop/scripts/prepare.js
deleted file mode 100644
index 66df72366f2..00000000000
--- a/apps/desktop/scripts/prepare.js
+++ /dev/null
@@ -1,194 +0,0 @@
-// @ts-check
-
-import * as fs from "node:fs/promises";
-import * as path from "node:path";
-import { fileURLToPath } from "node:url";
-import { shouldBundleGpui } from "../../../scripts/run-gpui-build.mjs";
-
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = path.dirname(__filename);
-
-/**
- * Creates a Microsoft Windows Installer (TM) compatible version from the provided crate's semver version.
- * `major.minor.patch.build`
- *
- * @see {@link https://tauri.app/reference/config/#version-1}
- * @param {string} cargoFilePath
- * @returns {Promise}
- */
-async function semverToWIXCompatibleVersion(cargoFilePath) {
-	const config = await fs.readFile(cargoFilePath, "utf-8");
-	const match = /version\s*=\s*"([\w.-]+)"/.exec(config);
-	if (!match)
-		throw new Error(
-			'Failed to extract version from "Cargo.toml". Have you removed the main crate version by accident?',
-		);
-
-	const ver = match[1];
-	const [core, buildOrPrerelease] = ver.includes("+")
-		? ver.split("+")
-		: ver.split("-");
-	const [major, minor, patch] = core.split(".");
-	let build = 0;
-	if (buildOrPrerelease) {
-		const numMatch = buildOrPrerelease.match(/\d+$/);
-		build = numMatch ? parseInt(numMatch[0], 10) : 0;
-	}
-	const wixVersion = `${major}.${minor}.${patch}${
-		build === 0 ? "" : `.${build}`
-	}`;
-	if (wixVersion !== ver)
-		console.log(`Using wix-compatible version ${ver} --> ${wixVersion}`);
-	return wixVersion;
-}
-/**
- * Deeply merges two objects
- *
- * @param {Object} target
- * @param {Object} source
- * @returns {Object}
- */
-export function deepMerge(target, source) {
-	for (const key of Object.keys(source)) {
-		if (
-			source[key] instanceof Object &&
-			key in target &&
-			target[key] instanceof Object
-		) {
-			Object.assign(source[key], deepMerge(target[key], source[key]));
-		}
-	}
-	return { ...target, ...source };
-}
-
-/**
- * Writes platform-specific tauri configs
- *
- * @param {NodeJS.Platform} platform
- * @param {{} | undefined} configOptions
- */
-export async function createTauriPlatformConfigs(
-	platform,
-	configOptions = undefined,
-) {
-	const srcTauri = path.join(__dirname, "../src-tauri/");
-	const profile = process.argv.includes("--release") ? "release" : "debug";
-	const hostArchitecture = process.arch === "arm64" ? "aarch64" : "x86_64";
-	const hostTargets = {
-		darwin: `${hostArchitecture}-apple-darwin`,
-		win32: `${hostArchitecture}-pc-windows-msvc`,
-		linux: `${hostArchitecture}-unknown-linux-gnu`,
-	};
-	const target = process.env.RUST_TARGET_TRIPLE ?? hostTargets[platform];
-	const extension = platform === "win32" ? ".exe" : "";
-	const sidecarAvailable = target
-		? await fs
-				.access(
-					path.join(srcTauri, "binaries", `cap-gpui-${target}${extension}`),
-				)
-				.then(() => true)
-				.catch(() => false)
-		: false;
-	const developmentWorkspaceAvailable = await fs
-		.access(path.join(__dirname, "../../desktop-gpui/dev.sh"))
-		.then(() => true)
-		.catch(() => false);
-	const includeGpui = shouldBundleGpui(
-		platform,
-		process.env,
-		profile,
-		sidecarAvailable,
-		developmentWorkspaceAvailable,
-	);
-	const externalBin = [
-		"binaries/cap-muxer",
-		"binaries/cap-exporter",
-		"binaries/cap-cli",
-		...(includeGpui ? ["binaries/cap-gpui"] : []),
-	];
-	let baseConfig = {};
-	let configFileName = null;
-
-	console.log(`Updating Platform (${platform}) Tauri config...`);
-	if (platform === "win32") {
-		configFileName = "tauri.windows.conf.json";
-		baseConfig = {
-			...baseConfig,
-			bundle: {
-				externalBin,
-				resources: {
-					"../../../target/ffmpeg/bin/*.dll": "./",
-					"../../../target/native-deps/dxc/*.dll": "./",
-					"../../../target/native-deps/dxc/LICENSE-*.txt": "licenses/dxc/",
-					"../../../target/native-deps/onnxruntime/lib/*.dll": "./",
-				},
-				windows: {
-					wix: {
-						version: await semverToWIXCompatibleVersion(
-							path.join(srcTauri, "Cargo.toml"),
-						),
-					},
-				},
-			},
-		};
-	}
-
-	if (platform === "darwin") {
-		configFileName = "tauri.macos.conf.json";
-		baseConfig = {
-			...baseConfig,
-			bundle: {
-				externalBin,
-				resources: {
-					"../../../target/native-deps/onnxruntime/lib/libonnxruntime.dylib":
-						"onnxruntime/lib/libonnxruntime.dylib",
-				},
-			},
-		};
-	}
-
-	if (platform === "linux") {
-		configFileName = "tauri.linux.conf.json";
-		const existingConfig = await fs
-			.readFile(path.join(srcTauri, configFileName), "utf-8")
-			.then(JSON.parse)
-			.catch((error) => {
-				if (error.code === "ENOENT") return {};
-				throw error;
-			});
-		baseConfig = deepMerge(existingConfig, { bundle: { externalBin } });
-	}
-
-	if (!configFileName) return;
-
-	const mergedConfig = configOptions
-		? deepMerge(baseConfig, configOptions)
-		: baseConfig;
-	await writeFileIfChanged(
-		`${srcTauri}/${configFileName}`,
-		JSON.stringify(mergedConfig, null, 2),
-	);
-}
-
-async function main() {
-	console.log("--- Preparing sidecars and configs...");
-	await createTauriPlatformConfigs(process.platform);
-	console.log("--- Preparation finished");
-}
-
-if (process.argv[1] && path.resolve(process.argv[1]) === __filename) {
-	main().catch((err) => {
-		console.error("\n--- Preparation Failed");
-		console.error(err);
-		console.error("---");
-		process.exitCode = 1;
-	});
-}
-
-async function writeFileIfChanged(filePath, contents) {
-	const currentContents = await fs
-		.readFile(filePath, "utf-8")
-		.catch(() => undefined);
-
-	if (currentContents !== contents) await fs.writeFile(filePath, contents);
-}
diff --git a/apps/desktop/scripts/prepare.test.js b/apps/desktop/scripts/prepare.test.js
deleted file mode 100644
index e43e2816d52..00000000000
--- a/apps/desktop/scripts/prepare.test.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import { describe, expect, it } from "vitest";
-import { createLinuxBundleConfig } from "../../../scripts/linux-bundle-config.mjs";
-import { deepMerge } from "./prepare.js";
-
-describe("Tauri platform release configuration", () => {
-	it("preserves generated Linux shared-library mappings when adding GPUI", () => {
-		const existing = createLinuxBundleConfig(["libavcodec.so.61"]);
-
-		const merged = deepMerge(existing, {
-			bundle: { externalBin: ["binaries/cap-gpui"] },
-		});
-
-		expect(merged.bundle.externalBin).toEqual(["binaries/cap-gpui"]);
-		for (const format of ["deb", "rpm", "appimage"]) {
-			expect(merged.bundle.linux[format]).toEqual(
-				existing.bundle.linux[format],
-			);
-		}
-	});
-
-	it("preserves Windows resource mappings when platform overrides are applied", () => {
-		const merged = deepMerge(
-			{
-				bundle: {
-					externalBin: ["binaries/cap-cli", "binaries/cap-gpui"],
-					resources: { "ffmpeg/*.dll": "./" },
-				},
-			},
-			{ bundle: { windows: { wix: { version: "0.6.0" } } } },
-		);
-
-		expect(merged.bundle.externalBin).toContain("binaries/cap-gpui");
-		expect(merged.bundle.resources).toEqual({ "ffmpeg/*.dll": "./" });
-		expect(merged.bundle.windows.wix.version).toBe("0.6.0");
-	});
-});
diff --git a/apps/desktop/scripts/prodBeforeBundle.js b/apps/desktop/scripts/prodBeforeBundle.js
deleted file mode 100644
index ca477fd70fd..00000000000
--- a/apps/desktop/scripts/prodBeforeBundle.js
+++ /dev/null
@@ -1,74 +0,0 @@
-// @ts-check
-
-import { exec as execCb } from "node:child_process";
-import * as fs from "node:fs/promises";
-import * as path from "node:path";
-import { fileURLToPath } from "node:url";
-import { promisify } from "node:util";
-
-const exec = promisify(execCb);
-
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = path.dirname(__filename);
-
-const targetDir = path.join(__dirname, "../../../target");
-
-async function main() {
-	if (process.platform === "darwin") {
-		const releaseBinary = await findReleaseBinary();
-		if (!releaseBinary) {
-			console.warn("No release binary found for dSYM generation; skipping.");
-			return;
-		}
-
-		await exec(
-			`dsymutil "${releaseBinary.binaryPath}" -o "${path.join(
-				targetDir,
-				releaseBinary.releaseFile,
-			)}.dSYM"`,
-		);
-	}
-}
-
-main();
-
-async function findReleaseBinary() {
-	const dirs = [
-		path.join(targetDir, "release"),
-		process.env.TAURI_ENV_TARGET_TRIPLE
-			? path.join(targetDir, `${process.env.TAURI_ENV_TARGET_TRIPLE}/release`)
-			: null,
-	].filter(Boolean);
-
-	for (let attempt = 0; attempt < 20; attempt++) {
-		for (const releaseDir of dirs) {
-			const releaseFile = await findReleaseFile(releaseDir);
-			if (releaseFile)
-				return { binaryPath: path.join(releaseDir, releaseFile), releaseFile };
-		}
-		await new Promise((resolve) => setTimeout(resolve, 250));
-	}
-
-	return null;
-}
-
-async function findReleaseFile(releaseDir) {
-	if (!(await fileExists(releaseDir))) return null;
-	const releaseFiles = await fs.readdir(releaseDir);
-	for (const name of ["Cap", "cap-desktop"]) {
-		if (releaseFiles.includes(name)) return name;
-	}
-
-	for (const releaseFile of releaseFiles) {
-		if (releaseFile.startsWith("Cap")) return releaseFile;
-	}
-
-	return null;
-}
-
-async function fileExists(path) {
-	return await fs
-		.access(path)
-		.then(() => true)
-		.catch(() => false);
-}
diff --git a/apps/desktop/scripts/stop-editor-performance.md b/apps/desktop/scripts/stop-editor-performance.md
deleted file mode 100644
index 0ddc230c363..00000000000
--- a/apps/desktop/scripts/stop-editor-performance.md
+++ /dev/null
@@ -1,712 +0,0 @@
-# Stop recording to usable editor
-
-Status on 2026-09-10: the user stopped further testing and requested sandbox shutdown and PR publication with the remaining gaps recorded. This is **not** an all-tests-passed result. GPUI v4 native suites passed on macOS (993), Linux (1,052) and Windows (970), with two existing ignores each and passing compilation checks. macOS passed 161 editor tests, 597 recording/recovery tests, 470 Tauri tests plus binding generation; desktop frontend 473, web frontend 3,047 and tooling 64 tests passed, with both frontend TypeScript checks passing. Linux root library/integration scopes, 536 Tauri function tests and three canonical executions passed. Windows completed 1,314 scoped library tests across eight crates; its remaining protocol tests, Tauri, muxer, integration, explicit GPU, canonical, hardware and strict-lint scopes were not run after the capacity guard stopped the lane. Strict GPUI and Linux export Clippy retain unchanged baseline findings. Linux ordinary static-library packaging failed for lack of disk space despite passing direct main-binary function tests. Active test sandboxes were stopped after evidence retention. Cleanup of older stalled restore requests is recorded separately and is not claimed complete here.
-
-The candidate now keeps eligible preparing playback alive after successful publication while ordinary loading completes, then lets the ordinary editor adopt the existing audio generation and consumed-audio clock. Native function tests cover that ownership path, completed PCM reuse, cancellation and stale-candidate disposal. Current application Stop-to-first-audible timing and physically uninterrupted audio/image handoff remain unproven. The user will test the application manually after automated verification. Earlier screenshots and benchmarks below apply to their recorded source snapshots; no new UI run or expanded two-hour benchmark was performed for this final verification.
-
-## Acceptance criteria
-
-Measure from the actual Stop action to capture shutdown, the first presented editor frame, first audible playback, and a successful seek near the end. A window or spinner appearing is not editor readiness.
-
-The earlier under-500-ms p95 target is retained as historical context, not an achieved measurement or the current optimization priority. The current goal is immediate editor feedback with truthful media readiness, including multi-hour recordings. Track capture frame drops, A/V alignment, audio sample counts, output quality, CPU, memory, and disk activity alongside latency. No finalizer percentage or elapsed-time animation may stand in for a confirmed playable prefix.
-
-## Measurements on 2026-09-09
-
-The experiments below record successive source snapshots from September 9–10. “Current” or “final” within a historical stage refers to that stage. Later implementation and verification updates are listed at the end; earlier counts and timings are not added to the final results.
-
-Evidence is retained locally in `.git/stop-editor-20260909`. Originals and disposable benchmark copies are separate. No customer recordings were modified.
-
-The GPUI runs used actual macOS screen capture at 3024 by 1964 and 60 fps. The native microphone was the MacBook Pro Microphone. The five-minute run also enabled system audio.
-
-| Native GPUI baseline                             |   Capture pipelines stopped | Stop to first editor frame |
-| ------------------------------------------------ | --------------------------: | -------------------------: |
-| 15 seconds, screen                               | Not separately instrumented |                 1,001.7 ms |
-| 60 seconds, screen and microphone                |                     38.9 ms |                 1,552.9 ms |
-| 300 seconds, screen, microphone and system audio |                    122.7 ms |                 6,013.5 ms |
-
-A native 60-second candidate recording reached the first editor frame in 937.9 ms, with capture pipelines stopped in 59.1 ms. These native runs captured changing foreground content and are flow observations, not controlled paired percentage comparisons. GPUI's frame marker observes delivery to the editor, not a measured display scanout.
-
-The native Tauri screen-only driver measured 1,686.6 ms baseline and 1,684.7 ms candidate from Stop to a rendered, visible canvas followed by two animation frames. Stop command completion was 139.9 ms and 177.3 ms respectively; neither value represents editor readiness. These are separate 15-second recordings using the root workspace's unoptimized debug build, so they are not release timings and are not comparable to the GPUI build profile.
-
-A Tauri candidate run with both microphone and system audio also completed recording and opened a rendered editor. Its 15-second debug run measured 2,622.0 ms to the presented-frame observer. This exercises the preserved-AAC path in Tauri, but has no matched native audio baseline.
-
-The controlled comparison replays identical preserved recording bytes through `RecoveryManager::remux_if_needed`, alternating baseline and candidate order. Each table entry is the median of three runs. Both executable versions use the GPUI development workspace's optimized dependencies. These are component benchmarks, not packaged release or full Stop-to-editor benchmarks.
-
-| Shared finalization fixture                   |    Baseline |   Candidate | Reduction |
-| --------------------------------------------- | ----------: | ----------: | --------: |
-| Native screen recording, 14.9 seconds         |    548.1 ms |    534.2 ms |      2.6% |
-| Native screen and microphone, 60 seconds      |  1,177.9 ms |    850.5 ms |     27.8% |
-| Two-hour replay, video and AAC audio, 2.40 GB | 47,616.9 ms | 19,499.9 ms |     59.0% |
-
-The two-hour fixture contains actual encoded screen and microphone media replayed to two-hour timestamps. It is not a two-hour capture or hardware soak. Its video is 1280 by 832 at 30 fps. It excludes long cursor and keyboard histories. Three samples do not establish p95 or p99 performance.
-
-An earlier overlapping run reported 18.1 seconds inside finalization and 19.6 seconds for the whole component call. Use the later alternating comparison above for the candidate assessment.
-
-## Initial candidate changes, September 9
-
-- Preserve single-track AAC media by remuxing it to M4A instead of decoding it and encoding it again as Ogg. Detect the actual codec; old files with misleading extensions retain the existing conversion path.
-- On macOS, attempt an independent copy-on-write staging clone, then use the existing exclusive copy fallback. This is not a hard link. Other operating systems retain the copy path.
-- Hash separate files with at most one additional scoped worker when the recovery inputs total at least 32 MiB and multiple CPUs are available. Keep full byte hashes, directory entries, symlink rejection, and the serial fallback if a worker cannot be created.
-- Reuse the editor audio resampler's output allocation across packets. Restore the requested sample capacity for every conversion and flush; keep the same decoder, resampling configuration, samples, and range behaviour.
-- Read fragmented video through a seekable concatenated input when creating a new finalized output. Avoid writing and rereading a recording-sized temporary aggregate. Existing destinations retain the original aggregate path because they can alias an input.
-- Add stage timing and opt-in native benchmark drivers. Retain source snapshots, staged validation, source rechecks, synchronization, transactional publication, and preserved originals.
-
-The recovery unit suite passed 58 tests. The integration suite passed 50 tests, with one existing ignored test. Added coverage verifies decoded AAC samples, microphone/system-audio offsets and device metadata, preserved original bytes, independent cloned files, exclusive destination creation, and large-file changes with restored timestamps. The audio unit suite passed 42 tests, including bit-exact comparisons against fresh resampling buffers at 16, 44.1, 48 and 96 kHz with one, two and six source channels and varying packet sizes. These results do not establish platform or release parity.
-
-Scoped Rust checks passed for `cap-audio`, `cap-recording`, `cap-desktop`, and `cap-desktop-gpui`. Rust formatting and the benchmark JavaScript's Biome check passed. Biome did not process Markdown, so this document was checked manually. Native baseline/candidate Tauri builds and the GPUI candidate build completed.
-
-## Further matched optimization benchmarks
-
-The bounded hashing experiment compares the preceding AAC/clone candidate with the same candidate plus concurrent hashing. Each result is the median of three alternating runs on identical preserved bytes, with builds and capture runs stopped. Evidence is in `optimization-stage-2/results.json`.
-
-| Shared finalization fixture              | Previous candidate | Concurrent hashing | Reduction |
-| ---------------------------------------- | -----------------: | -----------------: | --------: |
-| Native screen recording, 14.9 seconds    |           559.6 ms |           528.0 ms |      5.6% |
-| Native screen and microphone, 60 seconds |           950.4 ms |           843.5 ms |     11.2% |
-| Two-hour replay, video and AAC audio     |        19,943.9 ms |        15,329.0 ms |     23.1% |
-
-An instrumented long run still spent about 1.87 seconds validating staged inputs, 4.13 seconds finalizing video, and 1.81 seconds validating output tracks. Those validations remain. The entire component call took 15.58 seconds in that run. These results do not demonstrate duration-independent stopping or p95 performance.
-
-The resampler allocation experiment compares identical audio bytes through the full production audio loader, using five alternating runs per variant. Hashing the decoded samples happens after the timed load. Every before/after run matched both decoded byte count and SHA-256. Evidence is in `optimization-stage-3/results.json`.
-
-| Full audio loading     | Fresh buffers | Reused buffers | Reduction |
-| ---------------------- | ------------: | -------------: | --------: |
-| Native AAC, 60 seconds |      19.47 ms |       17.97 ms |      7.7% |
-| Legacy Ogg, 60 seconds |      56.29 ms |       55.02 ms |      2.2% |
-| AAC replay, two hours  |   2,063.26 ms |    1,988.66 ms |      3.6% |
-
-The long track still allocates 1,382,703,104 bytes for decoded samples. Buffer reuse reduces temporary allocation work; it does not implement bounded audio loading. The full decoded SHA-256 for that track was `5c5c67688b348b9e4d0e54a42e5021c630a7ab8c49c078c892d620e8f7fcd8c9` in both variants.
-
-The combined candidate completed fresh native screen, microphone and system-audio recordings in GPUI and Tauri. GPUI's 60-second run stopped its capture pipelines in 120.3 ms and delivered the first editor frame in 1,254.5 ms. Its five-second playback run reported 300 frames at 59.8 fps with zero dropped frames. Tauri's 15-second run reported stop-command completion in 329.2 ms and a rendered-editor marker at 2,081.6 ms. These are individual development-build flow checks, with changing capture content and different build profiles; they do not establish a matched native speedup or p95.
-
-## Avoiding the temporary combined video
-
-The finalized output remains the same progressive MP4. The clean finalization path now supplies the original fragment bytes through FFmpeg's seekable custom-input interface instead of writing an intermediate concatenated file. The reader uses a 64 KiB buffer and at most two source file handles during a file transition. It retains read failures even if the demuxer subsequently reports EOF. Custom I/O lifetime and buffer ownership follow the [FFmpeg example](https://ffmpeg.org/doxygen/trunk/avio_read_callback_8c-example.html).
-
-Existing output files retain the previous implementation. This preserves overwrites where the output aliases an input, including hard links; opening that destination directly while reading fragments could otherwise truncate its own input. Interrupted-recording recovery retains its established full-validation path.
-
-The final candidate, including the overwrite fallback, was compared with the previous concurrent-hashing candidate using three alternating runs per fixture. Temporary benchmark copies were removed after each completed subprocess; the original fixtures, logs and binaries remain. The last long candidate output was retained for native playback verification. Evidence is in `optimization-stage-4/guarded-results.json`.
-
-| Shared finalization fixture              | Previous candidate | Seekable fragment input | Reduction |
-| ---------------------------------------- | -----------------: | ----------------------: | --------: |
-| Native screen recording, 14.9 seconds    |          528.35 ms |               489.48 ms |      7.4% |
-| Native screen and microphone, 60 seconds |          763.30 ms |               678.32 ms |     11.1% |
-| Two-hour replay, video and AAC audio     |       15,245.86 ms |            13,593.52 ms |     10.8% |
-
-These remain component medians in development builds, not p95 or full Stop-to-editor measurements. All three final media sets matched the preceding candidate byte for byte in a retained comparison, including the complete MP4 containers. Recording metadata and project configuration also matched. Evidence is in `optimization-stage-4/media-equivalence.json` and `metadata-equivalence.json`.
-
-The encoder suite passed 112 tests, including concatenated read/seek equivalence, large seek offsets, truncated and missing fragments, sticky I/O failures, exact packets/timestamps, and existing-output aliases. Scoped clippy passed with warnings denied. Recovery checks passed 58 unit tests and 50 integration tests, with one existing ignored integration test. Root and GPUI application checks and native builds passed.
-
-With the final candidate, a fresh native 60-second GPUI recording with microphone and system audio stopped its capture pipelines in 110.45 ms and delivered the first editor frame in 923.81 ms. Playback from an explicit 30-second seek reported 300 frames at 60.0 fps with zero dropped frames. A native Tauri recording with the same track types, lasting 15 seconds, reported stop-command completion in 285.06 ms and a rendered-editor marker at 1,686.22 ms in its unoptimized debug build. The retained two-hour output also reopened in GPUI, sought explicitly to 7,194.5 seconds, and played for five seconds at 60.0 fps with zero dropped frames. These are individual native flow observations, not controlled percentage comparisons or p95 measurements. Evidence is in `optimization-stage-4/native-results.json`.
-
-The guarded candidate's retained two-hour media files, recording metadata and project configuration also matched the prior candidate byte for byte. See `optimization-stage-4/guarded-equivalence.json`.
-
-One native driver run initially reused the stage 3 GPUI stdout filename. The completed new log was moved to stage 4, and the original stage 3 events were recovered from the independently written daily diagnostic log. This recovered excerpt is named `optimization-stage-3/gpui-mic-system-60.diagnostic.log`; provenance and the distinction from the overwritten stdout stream are recorded in `optimization-stage-4/log-recovery-provenance.json`. Subsequent native log creation is exclusive. Recording media was unaffected.
-
-## Direct media experiment
-
-A separate two-hour fragmented MP4 was created from the replay's encoded video without re-encoding. Compressed video payload SHA-256 matched the progressive input:
-
-`b194eecf662b211a05c0f55724ad31a2425cb1d1d3dca172e4760add6234a95a`
-
-The production decoder was then opened directly on that file:
-
-| Decoder on macOS       | Probe and first frame | Seek at 3,600 seconds | Seek at 7,199 seconds |
-| ---------------------- | --------------------: | --------------------: | --------------------: |
-| AVAssetReader hardware |              440.4 ms |               46.6 ms |               25.6 ms |
-| FFmpeg hardware        |              163.9 ms |               51.7 ms |               21.8 ms |
-
-Neither required a post-recording remux for reading. This tests already-created media and existing decoders, not a new recorder, editor UI presentation, crash recovery, Windows Media Foundation, or Linux hardware/software decoding.
-
-The same fragmented two-hour file was also opened in the actual GPUI editor and played for five seconds. The app reported 301 rendered frames, 60.0 fps, and zero dropped frames. Audio output and the microphone waveform loaded. The initial `CAP_GPUI_AUTO_SEEK=0.999` run was incorrectly interpreted as a seek near the end of the recording: that driver targets the visible timeline viewport, which can show only the beginning of a long recording. It proves native playback but not native tail playback. The direct decoder and trim/export experiments use explicit timestamps and are unaffected by this correction.
-
-The corrected driver explicitly sought to 7,194.5 seconds, then played for five seconds in the native GPUI editor. Both the progressive output from the concurrent-hashing candidate and the fragmented media experiment reported 300 frames at 59.9 fps with zero dropped frames. Logs confirm the exact requested time. Evidence is in `optimization-stage-3/native-tail-results.json`; this verifies tail playback on macOS, not a two-hour native capture or a p95 latency.
-
-The current Rust exporter successfully rendered a three-second trim from the preserved-AAC candidate and another from 7,195–7,198 seconds of the fragmented two-hour project. Each output contained 90 H.264 frames and a three-second AAC track. Both outputs fully decoded without errors. This is short trim/export coverage, not a complete multi-hour export or visual/aural equivalence test.
-
-After the resampler change, both trims were exported again with the rebuilt exporter and identical settings. Full decoded video and audio SHA-256 hashes matched the preceding candidate's exports in both cases, with no decode errors. Evidence is in `optimization-stage-3/export-validation.json`.
-
-Full audio loading still took approximately 2.05 seconds and the process reached approximately 1.46 GB RSS. A trial using the existing range decoder failed a sample-count comparison near the end of the long replay. Range decoding is not enabled for recorded-track playback by this change. Timestamp discontinuities, AAC priming/padding, and resampling alignment must be resolved before introducing bounded audio loading.
-
-The two-second audio-window experiment took approximately 5 ms per window and used 384 KB of decoded samples, but middle and end windows did not match the full reference on the replay. The same experiment matched every sample at the beginning, middle and end of the original native 60-second AAC track, at 1.2–1.5 ms per window. This distinguishes feasibility from correctness across timestamp discontinuities; it is not a passing long-recording result.
-
-## Longer-term implementation direction
-
-These are design goals, not a claim that arbitrary indexed seeking, bounded total PCM storage or the full recording matrix has been implemented and verified.
-
-The accepted experience is to open the editor as soon as capture has safely stopped and make the beginning playable while remaining preparation continues. A subtle timeline boundary should represent the actual contiguous range ready across display, camera, microphone and system audio, accounting for track offsets. Progress must not be estimated from elapsed time. Playback reaching the boundary must wait without losing audio, advancing the media clock, or presenting incomplete output as complete. Seeking into an unprepared range should prioritize that range or show preparation while preserving the requested position. Full export and recovery requirements still apply.
-
-Produce durable, indexed, editor-readable media during capture. Keep the original encoded media in stable locations. On a clean stop, drain every requested track, flush the remaining media and event tails, commit the final index and project metadata, and open the editor directly on those originals. Whole-recording copying, hashing, transcoding, and remuxing must not remain prerequisites to editing.
-
-Use bounded audio decoding with a small look-ahead buffer and an index that preserves the current sample timeline. Seeking must work anywhere in a long recording without decoding everything before it. Failure to load requested audio must not become a silent successful playback result.
-
-Build cursor/keyboard indexes, thumbnails, and waveform data incrementally. The current stop path serializes complete cursor histories, so the media-only two-hour replay is insufficient to prove that Stop is independent of duration. GPU resources and the editor shell can be prepared during recording; this must be measured for capture contention and frame drops.
-
-Keep clean-stop publication separate from interrupted-recording recovery. A failed drain or incomplete tail must retain the existing failed/recoverable state. Old recording formats continue through their established reader and recovery paths. No crash-recovery validation is removed to obtain a faster timing.
-
-Background jobs must use immutable inputs and must not rename, replace, or delete media underneath an open editor or export. Closing or reopening the app must preserve both the recording and saved edits. Optional consolidation for external compatibility can operate on a separate output when required.
-
-## Progressive audio feasibility
-
-The existing sequential `AudioStream` decoder was compared with the current full `AudioData` decoder over the native 60-second AAC track, its legacy Ogg output, and the two-hour AAC replay. Every chunk's channel count, cumulative sample position and sample bits matched the full reference through EOF. The two-hour decoded SHA-256 remains `5c5c67688b348b9e4d0e54a42e5021c630a7ab8c49c078c892d620e8f7fcd8c9`.
-
-Across three runs, the median time to open and decode the first 250 ms was 0.61 ms for native AAC, 0.74 ms for legacy Ogg, and 4.43 ms for the two-hour AAC replay. The largest returned chunk was 48,000 bytes for these mono tracks. These are warm component observations: full decoding ran first in each process, and sample comparison/hash work is excluded from the accumulated streaming decode time. They do not measure the audio device, editor startup, cold storage, or a production progressive playback path. Evidence is in `progressive-audio-probe/results.json`.
-
-Use `CAP_BENCH_STREAM_AUDIO=1 CAP_BENCH_FULL_AUDIO_ONLY=1` with the audio readiness driver to reproduce this comparison. This sequential decoder avoids the timestamp-to-sample seek mismatch found by the earlier range experiment. It does not yet provide arbitrary seeking or a bounded editor cache. Existing export code also uses `AudioStream`; at this feasibility stage, editor playback still waited for whole-track `AudioLoader` completion.
-
-The same three fixtures were also tested on native Linux, three runs each. Every streamed sample matched the full decoder on that platform. Median first-chunk times were 0.82 ms for native AAC, 1.02 ms for legacy Ogg and 12.31 ms for the two-hour replay, with the same 48,000-byte maximum chunk size. These use the same warm component methodology and do not establish editor startup time. Decoded sample hashes differ between macOS and Linux builds; equivalence is checked against each platform's own full decoder. Linux evidence is in `daytona/long-audio-results.json`.
-
-## Direct fragmented-video decoding
-
-The FFmpeg directory reader previously read every fragment into one allocation, wrote a temporary combined file, and opened that file. It now owns the same seekable virtual input already used by remuxing. Opening retains paths, lengths and one active file handle instead of copying all encoded media. Custom I/O failures remain errors through packet reads and seeks, including when FFmpeg interprets a truncated input as EOF. The input context is destroyed before its custom I/O buffer and callback state.
-
-Shared video metadata loading also accepts fragment directories. On macOS, directories select the existing FFmpeg hardware decoder directly; ordinary files retain their existing AVAssetReader selection. Ordinary project readiness, failure and recovery guards are unchanged. At this stage, direct reading was available, but neither editor yet opened unfinished recordings or moved finalization into the background.
-
-Matched debug-profile decoder runs alternated old and new readers, three runs per variant and fixture. macOS tested both software and actual VideoToolbox decoding; Linux tested software decoding. Each run compared 30 decoded frames at the beginning, middle, near the end and after a backward seek. Visible pixel bytes, timestamps, frame counts and requested hardware selection matched in all 36 macOS runs and all 12 Linux runs. This is sampled frame equivalence, not a complete two-hour decode comparison. A separate generated multi-fragment recording test compares every returned frame and timestamp through EOF and after four seeks.
-
-| Platform and fixture                | Decoder      | Old first frame median | Direct first frame median | Old / direct peak RSS median |
-| ----------------------------------- | ------------ | ---------------------: | ------------------------: | ---------------------------: |
-| macOS, native screen 15 seconds     | Software     |              106.31 ms |                  64.93 ms |            124.86 / 73.60 MB |
-| macOS, native screen 15 seconds     | VideoToolbox |              135.26 ms |                 125.55 ms |           156.04 / 103.79 MB |
-| macOS, native microphone 60 seconds | Software     |              238.71 ms |                  69.34 ms |            205.52 / 71.55 MB |
-| macOS, native microphone 60 seconds | VideoToolbox |              269.64 ms |                 130.43 ms |           236.54 / 104.12 MB |
-| macOS, two-hour replay              | Software     |            1,916.36 ms |                 123.47 ms |          2,307.05 / 57.29 MB |
-| macOS, two-hour replay              | VideoToolbox |            1,463.52 ms |                 190.70 ms |          2,319.83 / 67.99 MB |
-| Linux, native screen 15 seconds     | Software     |              136.11 ms |                 105.14 ms |                 Not measured |
-| Linux, native microphone 60 seconds | Software     |              183.55 ms |                 109.91 ms |                 Not measured |
-
-Timing starts before decoder construction and ends at the first decoded frame, excluding frame hashing. Inputs are warm and builds finish before measurement; three runs do not establish p95 or cold-storage performance. Memory uses decimal MB. Linux two-hour video decoding and Linux hardware decoding were not measured in this comparison.
-
-With the final shared metadata/decoder integration, the GPUI media-readiness driver also read the original fragment directories directly. Metadata loading plus decoder setup plus first frame took 171.80 ms for the 15-second recording, 171.79 ms for the 60-second recording and 264.44 ms for the two-hour replay. All four seek requests returned frames in each case, and durations matched the finalized-file controls. These are single component runs, without an editor window, GPU composition, audio readiness or Stop. Ordinary finalized-file controls continued selecting AVAssetReader hardware decoding.
-
-Evidence is retained in `optimization-stage-5/macos-results.json`, `optimization-stage-5/macos-shared-media-results.json`, and `daytona/stage5/`, with build logs, source manifests and binary hashes. The matched decoder binaries precede the helper's public visibility change and shared metadata integration; the shared-media driver and final checks include those additions.
-
-Final macOS validation passed 114 encoder/remux tests, two decoder tests and 235 rendering tests. Linux passed 118 encoder/remux tests, two decoder tests and 209 rendering tests. Each rendering suite retained five existing ignored tests. Scoped checks and all-targets Clippy with denied warnings passed on both platforms using the repository's Rust 1.88 toolchain; the GPUI dependency check and shared-media driver build also passed using stable Rust. Linux initially lacked the Clippy component; it was installed before the successful run. A separate stable-Rust Clippy attempt reported newly introduced lints in five unchanged encoder tests, so that toolchain result is retained separately from the passing pinned-toolchain checks.
-
-The final macOS binary also finalized another two-hour disposable project in 13,609 ms. Its complete video, AAC audio, recording metadata and project configuration were byte-identical to the preceding guarded candidate. This confirms the shared reader ownership change preserves those outputs; it is a single regression run, not evidence of further finalization speedup. Evidence is in `optimization-stage-5/finalization-replay-2h.json`.
-
-## Required regression matrix
-
-Run the same fixture and native-action drivers in Tauri and GPUI on macOS Intel/Apple Silicon, Windows hardware/software decoder configurations, and Linux X11/Wayland with the supported capture and decoder paths.
-
-Cover short, 5-minute, 1-hour, 2-hour and 8-hour recordings; screen-only, webcam, microphone and system audio; pause/resume, device changes and dropped-input gaps; first and last frames, A/V sync, sample counts, trim/export/reopen; and repeated stop/start cycles.
-
-Inject interruption at media flush, index persistence and metadata publication. Also cover encoder errors, truncated media, a full disk, unavailable output storage, and app close/reopen while ancillary work is running. Originals and diagnostics must survive every failure. Exercise Windows file-sharing restrictions on actual Windows.
-
-Use matched release-equivalent builds, fixed visible capture content, identical settings, repeated cold and warm runs, and concurrent capture-load measurements. Record exact revisions and binary hashes. Any quality, correctness, recovery, or supported-platform regression blocks enabling the new path.
-
-## Daytona function validation
-
-macOS validation ran alongside the Daytona work using the local Apple Silicon build and locked dependencies with Rust stable 1.98.1. The first eight suites passed 864 tests with zero failures: encoder/remux (112), audio (42), recording (477), recovery integration (50), Instant Mode scenarios (61), editor (70), export (32) and GPUI recording/stop (20). There were three existing ignored tests. The project suite added 126 passes, and the A/V matrix added four passing test functions. The first matrix run reported 41 passing scenarios, but one random scenario skipped its video timing check after a 1.19-second runner stall; its audio check passed. A same-seed repeat also skipped that video check after a 1.10-second runner stall, with all other checks passing. Thus 40 scenarios have complete checks and one has audio-only verification. These skipped checks are not counted as verified video behavior; both reports remain retained. Full logs and commands are retained in `macos-function-validation/`. Platform-conditional tests account for differing macOS and Linux suite counts.
-
-The Linux candidate ran on Debian 13 x86_64 in a Daytona container with 4 vCPUs, 8 GiB RAM and a 10 GiB writable filesystem. The source archive contains HEAD `0c403be8a57f7ba4de67140273708a392c8b4050` plus the local candidate; every source file was hashed before upload. Tests used Rust 1.88.0, the committed dependency lockfile, and the repository's FFmpeg/native dependencies installed by `scripts/setup.js`. Debug symbols and incremental compilation were disabled to fit the sandbox. These are native Linux function tests, not UI, physical capture, or release latency tests.
-
-| Suite                                     | Passed | Failed | Ignored |
-| ----------------------------------------- | -----: | -----: | ------: |
-| Encoder/remux library                     |    116 |      0 |       0 |
-| Audio library                             |     42 |      0 |       0 |
-| Project library                           |    126 |      0 |       0 |
-| Recording library on container filesystem |    629 |      3 |       2 |
-| Recovery integration                      |     50 |      0 |       1 |
-| Instant Mode scenarios                    |     61 |      0 |       0 |
-| Editor library                            |     71 |      0 |       0 |
-| Export library                            |     32 |      0 |       0 |
-| A/V sync matrix tests                     |      4 |      0 |       0 |
-| Transactional recovery subset on tmpfs    |     28 |      0 |       0 |
-
-The A/V matrix reported 41 of 41 scenarios passing with no skipped scenarios. Do not add the tmpfs subset to the other rows as if it contained distinct tests.
-
-Three interrupted-publication/rollback cases failed in the candidate's initial recording-library run. Rebuilding with the five modified shared source files replaced by their unchanged HEAD versions also produced recovery failures, although the failing cases varied. Temporary diagnostic instrumentation captured a directory's reported size changing from 21 to 29 during rename; its entry names, file metadata and Unix identities matched. The existing receipt digest includes directory size, so reconciliation conservatively rejected the state and retained the files. The same candidate transactional group passed all 28 tests on tmpfs. No production guard was relaxed to obtain that pass. At that snapshot, the container-filesystem issue remained an inherited compatibility limitation, not a fully green suite or a reason to omit the failures. A later guarded recovery-stamp fix is recorded in the final verification section. Candidate source hashes were checked after both baseline comparison and temporary instrumentation were restored.
-
-The native 15-second screen and 60-second microphone recordings were then finalized on Linux using matched aggregate-input and virtual-input binaries. All other candidate optimizations stayed identical. Builds completed before measurement, the variant order alternated, and each fixture ran three times per variant. All 12 runs succeeded with byte-identical finalized video, audio, recording metadata and project configuration. Each retained original segment tree also matched its input hash manifest, and the source fixtures stayed unchanged.
-
-| Linux finalization fixture    | Aggregate input median | Virtual input median |
-| ----------------------------- | ---------------------: | -------------------: |
-| Native screen, 15 seconds     |              745.10 ms |            723.92 ms |
-| Native microphone, 60 seconds |            1,089.72 ms |          1,068.34 ms |
-
-These are modest observed component improvements on a container with warm inputs, using debug-profile builds with debug symbols disabled. Three runs do not establish p95 or a statistically reliable speedup. They exclude capture stop, editor rendering and playback, and do not measure Linux two-hour finalization. Full output hashes, binary hashes, logs and restored source hashes are retained in `daytona/finalization/`.
-
-Windows creation initially returned a tier-access denial through the API and authenticated dashboard despite the earlier support-confirmed grant. Access subsequently became available on September 10, and the user requested parallel validation on all three systems. The earlier errors and Linux function evidence remain under `daytona/`; the new Windows results are recorded below.
-
-## Shared fixture matrix and progressive audio, September 10
-
-Three platform agents ran concurrently. All used the same immutable unfinished `.cap` inputs, reconstructed from a common chunk archive and verified by path, byte length and SHA-256 before testing. Finalization operated on separate disposable copies.
-
-| Canonical input               | Files |         Bytes |
-| ----------------------------- | ----: | ------------: |
-| Native screen, 15 seconds     |    19 |    46,099,193 |
-| Native microphone, 60 seconds |    40 |   121,129,994 |
-| Two-hour encoded replay       | 3,388 | 2,396,017,929 |
-
-The final shared runtime candidate is `stage6-32768-track-mixer-v3`. Each platform verified all 4,208 source hashes in `platform-matrix-20260910/candidate-v3-manifest.json`. Its overlay archive SHA-256 is `4c6ca640b2879dbebde40d22cbee12c34e6b299345fbac2b9db600618969b61b`. Earlier v2 media runs remain applicable to the unchanged finalizer and decoder. V3 changes only defensive integer arithmetic in the mixer; affected suites and audio hash checks were rerun on every platform. Subsequent benchmark-driver, documentation and GPUI shell changes are separate from this frozen runtime identity.
-
-### Runtime changes and correctness
-
-Recorded audio now decodes sequentially into immutable blocks of 32,768 sample frames. Consumers can request a ready window while full-track consumers await a separate completion notification. Completion reuses the blocks without making another full PCM copy. Waveforms iterate those same samples in their original order. The normal playback path still awaits complete recorded audio, so these window results do not yet establish early audible playback.
-
-The common mixer now handles one track at a time, hoists unchanged gain/channel calculations out of the per-sample loop, and reads contiguous slices where available. It retains the original track accumulation order, offsets, stereo modes and clamp behavior. A comparison against the original algorithm covered 3,024 cases and 2,007,936 output bytes on macOS and Linux. All matched exactly. A separate extreme-cursor probe found an overflow in the slice fast path; v3 fixes it with checked arithmetic and retains the original silent result. The regression test runs on all three systems.
-
-The macOS codec-failure matrix compared empty files, header prefixes, half truncation, final-byte and final-1,024-byte truncation, and a payload-bit change for both native AAC and legacy Ogg. All 12 old/new cases agreed: six successful pairs with identical full decoded samples, and six matching failure pairs. Original inputs stayed unchanged.
-
-| Final v3 affected suites | Audio | Editor | Export | Failed |
-| ------------------------ | ----: | -----: | -----: | -----: |
-| macOS                    |    51 |     70 |     32 |      0 |
-| Linux                    |    51 |     71 |     32 |      0 |
-| Windows                  |    55 |     70 |     30 |      0 |
-
-Scoped checks and all-targets, no-dependency Clippy passed for the affected shared crates on all three systems. The Windows native matrix totals 1,187 distinct passing tests with zero failures and eight existing ignored tests, including unchanged v2 encoder, decoder, project, recording, recovery, Instant and rendering suites. Windows used Server 2025 x64, Rust 1.88, MSVC and the repository's native dependencies. These headless results do not test physical Windows capture, a GPU decoder or its desktop UI. The Linux dependency-lint and container-filesystem failures described above remain separate unresolved baseline limitations.
-
-### Matched audio benchmarks
-
-Both sides use the same current-thread Tokio runtime and include worker startup and completion notification in their decode timer. The baseline reproduces the old `spawn_blocking` plus `Arc`/watch loader. Runtime construction, full PCM hashing and mixing happen outside the decode timer. Each mixing repetition has a `black_box` barrier. The corrected shared evidence harness SHA-256 is `bf526600f10feccf2186d186309ffb6cea2d7b42ea0d96e7ef6e6c98c96082d1`.
-
-These are three alternating pairs using development builds with optimization level 2. macOS retains debug symbols; Linux and Windows omit them. Compare each platform against its own baseline. Older direct-main-thread baseline measurements and unoptimized Linux measurements are retained for provenance but are not substituted into this comparison.
-
-| Two-hour AAC component              |       macOS |       Linux |     Windows |
-| ----------------------------------- | ----------: | ----------: | ----------: |
-| Old background loader, entire track | 1,943.59 ms | 3,287.10 ms | 2,526.91 ms |
-| Block loader, entire track          | 1,956.39 ms | 3,241.20 ms | 2,432.86 ms |
-| First 250 ms of audio available     |     4.97 ms |    16.35 ms |    13.57 ms |
-
-Every paired full PCM count/hash and mixed-output hash matched within its platform. The entire macOS decode was 0.66% slower in this small sample. Peak process RSS was 1,422.43 MB before and 1,434.35 MB after, an observed increase of 11.93 MB. The roughly 1.38 GB decoded source still remains resident; this is not bounded-memory loading. A 48,000-frame block experiment increased RSS by about 45 MB and was rejected. The extra 11.93 MB peak RSS is an explicitly accepted tradeoff. The full-decode timing difference remains visible; neither result is presented as proof of zero regressions.
-
-On native AAC, the original renderer versus the new block renderer mixed 60 seconds in 7.20 versus 1.21 ms on macOS, over five alternating pairs. On Linux the equivalent two-hour-source experiment measured 28.25 versus 1.80 ms over three pairs. Both matched original PCM and mixed-output hashes. The macOS evidence embeds the original helper in the driver; Linux rebuilds the original function in the library, so their ratios are not cross-platform comparisons. With the same optimized renderer on both storage types, blocks have a small access cost: 1.14 versus 1.23 ms on macOS and 1.72 versus 1.83 ms on Linux.
-
-Windows ran all 18 audio comparisons over native AAC, legacy Ogg and the long AAC replay with exact full PCM and mixed-output matches. Its short full-load medians were 24.71 versus 24.11 ms for AAC and 68.53 versus 67.49 ms for Ogg; first decoded windows arrived at 3.42 and 2.96 ms. Its baseline library restores the original mixer body, matching the Linux original-renderer method. Mixing 60 seconds from the long track measured 25.67 versus 1.42 ms, outside the decode timer. Windows process peak memory and CPU were not collected; decoded-buffer size is not a substitute for those metrics.
-
-### Full project media checks
-
-The updated Linux matrix ran 18 paired decoder probes across all three inputs. Decoded frame pixels and timestamps, including middle and tail seeks, matched. First-frame medians for aggregate versus direct input were 137.30 versus 105.08 ms for 15 seconds, 193.86 versus 111.62 ms for 60 seconds, and 2,665.91 versus 112.35 ms for two hours. These builds used the root workspace's unoptimized development profile; they exclude stop, GPU rendering and presentation.
-
-Twelve paired Linux short-project finalizations succeeded with exact output and retained-source checks. The two-hour candidate finalized in 13,317.68 ms on Linux and 14,388.35 ms on macOS in single regression runs. Each retained all 3,386 original segment files exactly. Published video, audio, project configuration and recording metadata matched across these platforms. All public cursor images/events and keyboard files were included; unordered JSON object keys were compared semantically where serialization order differed. There is no new matched two-hour Linux finalization baseline in this matrix.
-
-The finalized two-hour recording also played in the native macOS GPUI editor after an explicit seek to 7,194.5 seconds: 300 frames over five seconds at 59.8 fps, with zero dropped, skipped or starved frames. Logs confirm the real MacBook Pro Speakers output and no mute override. Audible A/V offset was not independently measured.
-
-Windows passed all 18 paired software-decoder probes and all 14 finalization runs. It used a two-vCPU VM and the unoptimized root development profile. First-frame medians were 188.95 versus 93.14 ms for 15 seconds, 315.83 versus 96.61 ms for 60 seconds, and 7,188.98 versus 628.15 ms for two hours. The three long candidate observations ranged from 190.19 to 650.28 ms, so the median alone must not be used as a latency guarantee.
-
-Windows short finalization medians were 945.44 versus 926.54 ms for 15 seconds and 1,414.75 versus 1,247.67 ms for 60 seconds. Its single long pair measured 42,940.06 versus 38,389.64 ms. All paired published segment bytes and parsed metadata/configuration matched; original segment files and original metadata/configuration remained exact. Supplementary untimed checks also compared every public output against macOS, including cursor images and normalized metadata/configuration, for all three fixtures. The long result reinforces that finalization is still too slow to gate a responsive editor.
-
-Evidence is retained in `macos-validation-20260910/`, `daytona/linux-validation-20260910/` and `windows-validation-20260910/`.
-
-The next integration must preserve source reads across publication, gate editor writes during publication, and prevent the audio/video clock from advancing past unprepared samples. No source validation, finalization requirement or recovery guard has been removed to get the component timings above.
-
-### Rejected Windows preview ownership proposal
-
-An evidence-only source-directory lease synchronized file opens with directory relocation. All five standalone tests passed on macOS and Linux, but Windows passed four and rejected the held-handle relocation with `ERROR_ACCESS_DENIED (5)`. The current FFmpeg `AudioStream` likewise blocked parent-directory rename while open, continued to produce exact samples, and released the restriction when dropped. Explicit `FILE_SHARE_DELETE` did not fix the directory rename, although renaming an individual shared file worked.
-
-This agrees with Microsoft's documented restriction on renaming a directory containing open files. The replacement-file POSIX flag does not establish a workaround for that directory rule. See [FILE_RENAME_INFORMATION](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_rename_information). The prototype was never integrated into the application. Its failure rejects that proposed mechanism; it does not change the passing v3 media results. Production publication semantics remain unchanged.
-
-The next design must either keep preview sources in a stable location throughout publication or explicitly release every affected reader while preserving buffered playback and exact decoder state. A path redirect alone is insufficient. Evidence includes `optimization-stage-7/source-lease-probe.rs`, the per-platform results, and Windows `rename-probe.log`/`source-lease-tests.log`.
-
-A second standalone prototype registers cached file handles with the source owner. Before relocating the directory, it closes all registered handles under an exclusive source lock; subsequent reads reopen at the preserved byte position. The identical `revocable-source-probe.rs`, SHA-256 `d62a69df330dff6d1fba36bf37e453f429552422c7a5245efed85dc15f3f8008`, passed all seven tests on macOS, Windows and Linux with Rust 1.88, optimization level 2, overflow checks and denied unused results. Coverage includes four simultaneous readers through 600 moves, successful and failed publication, rollback, seek positions, and changed-length rejection. This supports the filesystem mechanism only. FFmpeg/AVIO integration, exact decoded-output comparisons, publication latency and playback buffering are still required.
-
-## GPUI early loading shell
-
-This early shell change opened the existing `Loading project...` editor after a successful, generation-matched capture acknowledgement. `Phase::Stopping` and its detached task still own finalization and shutdown. Linux first completes the existing capture-visibility restoration protocol. At this shell-only stage, preflight, media readers, editing and saving remained behind successful full finalization, including the existing thumbnail and project configuration work.
-
-Presentation is tracked by recording generation, finalization job and actual window ID. Closing a preparing editor suppresses automatic reopening; explicitly reopening it uses the same readiness gate. Completion races and window-creation failures retain the existing fallback. Failed tracks, low storage, Instant recordings, non-editor preferences and in-editor recording targets keep their existing paths.
-
-The review found and fixed a camera-preview cleanup omission in the initial shell change. Finalization completion now parks the feed even though it no longer reopens or refocuses the editor. GPUI's binary test target also exposed a Stage6 test compilation regression: the waveform refactor removed a constant still used by two tests. The constant is restored inside the test module; runtime audio remains unchanged.
-
-macOS GPUI package check and 128 targeted tests passed: recording 45, session 15, app windows 26, timeline 42. Native extraction harnesses ran the same relevant production function bodies with scaffolding on Linux (35 passed) and Windows (22 passed plus check). They cover readiness, dismissal/reopen, stop outcomes, terminal ownership and restoration acknowledgements. They do not execute a real GPUI observer, compositor or typed capture device. Full native GPUI checks outside macOS were still pending at this shell-only stage; later frozen app suites are recorded below.
-
-Strict stable-toolchain GPUI Clippy with tests reported 30 issues in other code regions, including new `chunks_exact` recommendations and existing documentation/argument-count issues. No warning was suppressed, and no passing full-application Clippy result is claimed. The scoped shared-runtime checks described above remain separate.
-
-The first native shell attempt caught a panic in newly added timing instrumentation: `request_animation_frame` is invalid outside GPUI's render phases. That run is rejected and its isolated source and logs retained. A disposable copy recovered successfully, preserving all 36 original source files exactly and producing a complete decodable video. The instrumentation now uses the supported `window.refresh` call.
-
-A fresh native macOS run captured a synthetic AppKit window for 60 seconds at 60 fps, then used the ordinary Stop and editor playback paths. Microphone and system audio capture were disabled. The binary SHA-256 is `c98f054a08334e029801e94d5de1e07915caf994434d2f820d69a54e0dee994b`.
-
-| Milestone after Stop           | Elapsed time |
-| ------------------------------ | -----------: |
-| Capture shutdown acknowledged  |     37.41 ms |
-| Editor shell created           |     49.68 ms |
-| First frame-cycle upper bound  |     62.60 ms |
-| Finalization completed         |    317.51 ms |
-| Project validated              |    323.68 ms |
-| Editor instance created        |  1,130.83 ms |
-| First recording frame received |  1,180.02 ms |
-
-Playback delivered 301 frames over five seconds at 60.1 fps with zero drops. Full video decoding passed, metadata and configuration parsed, and all 36 originals totaling 13,576,177 bytes were retained. The screenshot shows the existing loading editor with editing/export gated by `project_ready`; recording controls have closed.
-
-This is one native flow, not a matched old/new comparison or a p95 result. The two-frame callback gives a frame-cycle upper bound, not a compositor scanout timestamp. Default audio output was enabled, but this screen-only recording does not verify audible A/V synchronization. The early shell is visible quickly; playable content still waits for finalization and editor setup. Evidence and exact source hashes are in `optimization-stage-7/gpui-shell/implementation-manifest.json`, `native-stop-fixed/verification.json` and `interrupted-recovery-verification.json`.
-
-## Managed source input and publication
-
-The Stage8 input keeps FFmpeg decoder state while the finalizer moves original segments. It closes registered file handles under the source owner lock, then reopens them at their preserved byte positions. Each file retains its identity, length and modification-time checks; ordinary file readers retain their existing paths. Cancellation callbacks run outside that lock. This mechanism is still an optional API; the preparing editor does not use it yet.
-
-Frozen `native-io-v1` passed 190 native media-library tests on macOS, 194 on Linux and 190 on Windows, with scoped check and strict Clippy. Native AAC60, legacy Ogg60 and AAC2h matched every decoded sample through publication, failed moves and rollback. All three canonical video fixtures matched decoded pixels and timestamps, including tail seeks, while the managed decoder stayed alive. macOS included actual VideoToolbox; Windows and Linux used software decoding. Original canonical files remained byte-exact. These component tests do not establish synchronized preparing-editor playback.
-
-The first video timings had a cache-preparation asymmetry: the reference was hash-read before construction, while the disposable candidate copy was only hash-read afterward. Those results remain in the evidence but cannot isolate API overhead. Corrected probes hash-read both inputs outside the timer, use the same probe with both library versions, and balance which decoder opens first. Native hardware cold-start and warm-start samples remain separate.
-
-The v2 reader registers at most 64 files per lock acquisition, sharing repeated parent checks inside each batch while preserving every file snapshot and all reopen checks. On Linux with optimization level 2 and four balanced repetitions, corrected two-hour managed constructor-to-first-frame median improved from 194.21 to 163.22 ms. The ordinary control stayed at 113.43 versus 115.67 ms. Short managed medians were 100.30 versus 101.01 ms for 15 seconds and 108.28 versus 106.29 ms for 60 seconds. These are warm-input component timings, not Stop latency or a p95 result. The measured cancellation response after a separate thread requested cancellation was below 0.72 ms with batching, versus below 0.03 ms before batching.
-
-The optional managed finalizer changes only the original-segment move and its rollback. Its exclusive recovery lock refuses a pending publication receipt without reconciling it behind active readers. Existing publication checks, original hashes, staging, configuration and metadata commit order remain unchanged. Six new tests cover a live 61-second audio decoder through actual finalization, successful publication, every failed publication rename, failed rollback, the wrong project source and interrupted-publication handoff. At this stage, all preview decoder workers had to acknowledge shutdown before ordinary receipt reconciliation or the ordinary editor took ownership. The later successful-publication handoff adds an explicit continuation path for already-admitted readers. Native v2 validation is complete, with the platform limitations below retained.
-
-macOS v2 passed 260 native tests (64 recovery, 54 audio, 139 encoder and 3 video), scoped checks and strict all-target Clippy. Its 48 balanced constructor trials and six full video lifecycles included software and actual VideoToolbox. Full audio samples, video pixels/timestamps and all 3,447 canonical fixture files matched. The two-hour software managed constructor-to-first-frame median improved from 195.29 to 166.78 ms. VideoToolbox opened first improved from 270.41 to 248.19 ms; opened second improved from 206.60 to 165.71 ms. These hardware strata must remain separate.
-
-Linux v2 passed its audio, encoder and video suites; recovery passed 64/64 on tmpfs and 61/64 on the sandbox root filesystem. The root-filesystem failures are triggered by a pre-existing publication receipt guard: a directory allocation size changes from 21 to 29 bytes during rename while its identity, times and recursive children remain unchanged. The original repository HEAD has byte-identical guard functions, and its retained baseline also fails interrupted-publication cases on that filesystem. The new managed handoff test exposes the same guard. No check was relaxed at that stage; this was then an unresolved filesystem-specific recovery limitation, not a clean all-filesystem sign-off. The subsequent guarded stamp fix has its own native results below. Detailed provenance is in `managed-recovery-linux/receipt-guard-provenance.json`.
-
-Windows v2 passed 255 native tests (60 recovery, 58 audio, 131 encoder and 6 video), all four scoped crate checks, media all-target Clippy and recording library Clippy. Full-target recording Clippy hits an unchanged `items_after_test_module` finding in `capture_pipeline.rs`, verified byte-identical to HEAD. The three full video lifecycles and three full audio comparisons passed; the two-hour audio contained 345,675,776 exact samples. All canonical inputs and 4,212 frozen source files remained unchanged.
-
-Windows used one prepared copy per fixture, with both complete input trees hash-verified before and after each batch of eight fresh processes. The same probe and root dev profile (Rust 1.88 MSVC, optimization level 0, debug info 0) ran both runtime versions, balancing library and decoder-opening order. Four repetitions per variant gave managed constructor-to-first-frame medians of 115.52 to 92.21 ms (15 seconds), 130.84 to 113.90 ms (60 seconds), and 479.31 to 363.15 ms (two hours). The two-hour ordinary control varied from 217.18 to 246.64 ms, so cache and small-sample qualifications remain material. These numbers cannot be compared directly with macOS/Linux optimization-level-2 timings. Windows cancellation request-to-return was 0.696–0.911 ms with batching versus 0.048–0.057 ms before; the maximum callback interval was 1.898 ms. This measures input-constructor cancellation, not full worker shutdown. Evidence: `windows-validation-20260910/stage8-managed-recovery-v2/{terminal,prepared-timing-summary,cancellation-results}.json`.
-
-Evidence: `optimization-stage-8/native-io-v1-manifest.json`, `native-io-macos/summary.json`, `native-linux-io/`, `enc-input-v2/`, `managed-recovery-v2-manifest.json`, `managed-recovery-v2-macos/summary.json`, `managed-recovery-linux/linux-stage8-summary.json`, and the native Windows results. At that snapshot, the separate early-editor and progressive-playback contracts described remaining integration work; later sections record their implementation.
-
-### Editor startup diagnostic
-
-The startup driver can now profile stages in a fresh process before normal startup (`--profile-stages-only`) and separately measure font preparation (`--prewarm-fonts`). A missing first preview frame now fails the driver instead of contributing an infinite value that was excluded from summaries.
-
-One initial stage profile took 882.3 ms, including a remaining renderer-layer wait of 663.5 ms. A subsequent ordinary process took 118.3 ms without font prewarming. Four balanced fresh-process comparisons on the same finalized 60-second project measured constructor-to-first-preview medians of 137.15 ms ordinarily and 134.45 ms with fonts prepared beforehand; that separate font preparation took about 12 ms. OS and driver caches were not reset. This does not establish fonts as the initial delay's cause, so no production font-prewarm change was accepted. These measurements exclude Stop, finalization, UI presentation and playback. Evidence: `optimization-stage-8/font-startup/summary.json`.
-
-## Managed decoder worker and lifetime
-
-Stage9 adds an optional managed decoder worker around the shared existing FFmpeg frame-selection loop. Startup returns an owner before waiting for readiness. Cancellation wakes the worker; `stop_and_wait` acknowledges an actual native thread join after its decoder, custom input and cached frames are dropped. Managed decode/seek errors are terminal, and cancelled readiness or shutdown waiters retain cleanup ownership. Ordinary decoder entrypoints preserve their existing frame, cache, offset, hardware fallback and VFR hold behavior.
-
-`RelocatableSource::new_with_owner` retains an external lifetime guard through every source clone and reader. Reader field drop order closes cached files before releasing the last guard. Seven tests include Windows exclusive file opens inside the guard destructor, which would fail if handles remained open. Recording-owned recovery-lock binding was still pending at this stage; this generic source API did not connect the preparing editor by itself. Metadata extraction now exposes the same existing `Video::from_input` and `Audio::from_input` calculations for an already-open input, preserving ordinary path behavior.
-
-The frozen seven-file overlay is `optimization-stage-9/managed-worker-v1-overlay.tar.gz`, SHA-256 `7845c712628f9ad99f8d9bc882bc14e3c1bf1d2539f9c1d4e863bd4b958a18a2`. Both Cargo locks were regenerated by Cargo with no package version, source or checksum drift; only rendering dependency edges changed.
-
-- macOS: 518 tests passed, five existing rendering tests ignored; formatting, six scoped crate checks and strict all-target Clippy passed. The actual worker matched ordinary software and VideoToolbox pixels through a three-second PTS gap, a 0.25-second handle offset, repeated publication and forward/backward/tail/cache requests. Logs confirm hardware was actually used.
-- Windows: 486 tests passed, five existing rendering tests ignored; scoped checks, media/rendering all-target Clippy and recording library Clippy passed. All owner-lifetime, interruptible-constructor and managed-worker cases passed, including the Windows exclusive-sharing teardown assertion. The inherited recording all-target lint remains documented above. Source and canonical fixture hashes match; the owned VM was stopped with caches and evidence preserved.
-- Linux: 431 media/worker tests passed, five existing rendering tests ignored; scoped check and strict all-target Clippy passed. Recovery remained 61/64 on the root filesystem and 64/64 on tmpfs, with the same three documented pre-existing receipt-guard cases. Native Rust formatting also passed after installing the pinned component. Final source and binary provenance is retained in `optimization-stage-9/native-linux/linux-stage9-summary.json`; both owned Linux sandboxes are stopped with their files and caches preserved.
-
-The first missing-fragment test used an incorrect hard-coded target: 9.5 seconds was intact media, while macOS's deleted last fragment began at 9.8 seconds. That failure is retained. The corrected test derives its target from the packet's physical fragment position, PTS and actual renderer frame mapping, and independently asserts the underlying ENOENT/EIO. It then checks terminal decode/seek failure, the same error on a later frame-zero request, and the shutdown acknowledgement. Linux's encoded fragment boundary differs, validating the need for packet-based targeting.
-
-Evidence: `optimization-stage-9/native-macos/summary.json`, `windows-validation-20260910/stage9-summary.json`, `optimization-stage-9/native-linux/`, and `optimization-stage-9/missing-fragment/`. This stage verifies functions and worker lifetimes; it adds no new Stop-to-editor latency or p95 claim. The recording-owned source observer, restricted editor projection and synchronized progressive playback remain to be connected and validated.
-
-## Recording-owned preparing sources
-
-Stage10 adds a private, single-use clean-stop receipt and a retained observer for read-only source access during finalization. Receipt eligibility is bounded and does not change persisted recording data or make a successful Stop fail. The projection checks the exact stopped metadata/configuration, fragment inventory, required tracks, diagnostics and cursor assets. Unsupported layouts fall back to ordinary finalization. Its source readers retain the real recovery lock, follow owned publication/rollback moves, and are revoked when finalization ends. In the Stage10 snapshot, already-running readers still had to be cancelled, joined and dropped before ordinary reconciliation.
-
-The production application did not consume this observer in the initial Stage10 snapshot. The full initial source snapshot, staging, validation, source rechecks, synchronization and transactional publication remain in their existing order. Moving availability ahead of the first snapshot would permit previewing one version of a source while finalization accepts a later version; that reorder was rejected during review. Existing renderer construction also has configuration-loading fallbacks that cannot be used by a restricted preparing preview.
-
-Frozen v1 native validation used identical source hashes and canonical recordings:
-
-| Platform | Recording tests                                 | Native canonical preparing coverage                                                                                                                            |
-| -------- | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| macOS    | 90 recovery and 8 receipt tests passed          | All four video requests on each short fixture; all 2,883,584 microphone frames on the 60-second fixture matched exactly                                        |
-| Windows  | 85 recovery and 8 receipt tests passed          | All four video requests on each short fixture; the same complete microphone sample count matched exactly                                                       |
-| Linux    | 90 recovery and 8 receipt tests passed on tmpfs | Two video requests on the 15-second fixture and three on the 60-second fixture before finalization ended; the complete microphone sample count matched exactly |
-
-Every observed video frame was compared against an independently finalized MP4 through the same software decoder. Final public media bytes, normalized metadata/configuration, retained originals and canonical inputs matched. The actual recovery lock could be reacquired after worker teardown. Linux's remaining video requests were cancelled at finalization completion and are recorded as unobserved, not passed early-preview coverage. These fixed-order functional probes do not measure Stop-to-editor latency, audible playback, speedup or p95.
-
-Scoped compiler and formatting checks passed. macOS passed strict recording Clippy across all targets and a standalone GPUI check. Windows retained its inherited all-target lint qualification while the scoped strict gates passed. Linux strict library/tests Clippy passed; its all-target example failure is byte-identical to HEAD. On the Linux sandbox's regular root filesystem, five existing interrupted-publication receipt cases failed, while the identical binary passed all 90 recovery tests on tmpfs. The exact test bodies and receipt guards are byte-identical to HEAD; this run does not establish a new five-failure baseline or remove that platform qualification.
-
-The original two-hour canonical recording finalized successfully on all three systems, preserving its sources and producing all four finalized-file reference frames. It then declined the test receipt before preparing playback began: its explicit empty `cursors` object deserializes as the legacy cursor representation. A live Stop holds the current representation and its writer omits that empty field. The v1 failure and zero long preparing coverage remain recorded. Test-only v2 removes that one empty field through the actual writer on both disposable comparison copies, verifies unchanged typed metadata/configuration and every media/sidecar byte, and retains a separate hash-linked legacy control. Four new tests passed natively on each platform; they verify the transformation and reject nonempty legacy cursors or unknown fields without writes. No production validation predicate changed.
-
-The normalized two-hour v2 probes passed on all three platforms. Each compared all four requested video seeks (0, 3600, 7194.5 and 1 seconds) against an independently finalized MP4 and all 345,675,776 audio frames bit-for-bit through EOF. Published media, normalized documents, retained originals and canonical hashes matched. Actual worker joins, source release and recovery-lock reacquisition passed. macOS and Linux also produced identical visible pixel hashes and published media/document bytes.
-
-These unoptimized, ordinary-first functional runs are not performance comparisons: source availability was observed at 15,592.17 ms on macOS, 948.55 ms on Linux and 1,546.92 ms on Windows; first returned video frames were at 16,141.58, 1,145.54 and 2,580.97 ms respectively. Cache state, hardware and concurrent preview work differ. No rendered editor frame, audible synchronization, product Stop latency or p95 is established. The full source snapshot still precedes availability; removing that protection has not been accepted.
-
-V2 evidence is retained in `optimization-stage-10/native-macos/assessment-v2-long.json`, `optimization-stage-10/native-linux-v2/assessment-v2-long.json`, and `windows-validation-20260910/stage10/summary-v2.json`. Both Windows test executables and the macOS/Linux v2 executables are retained. The Windows archive contains 1,032 size/hash-verified members, and its owned sandbox is stopped with source, fixtures, outputs and cache preserved.
-
-Evidence: `optimization-stage-10/native-macos/assessment-v1.json`, `windows-validation-20260910/stage10/`, `optimization-stage-10/native-linux/linux-stage10-v1-summary.json`, `optimization-stage-10/canonical-probe-v2/`, and `optimization-stage-10/early-availability-review/`. The original macOS v1 test executable was overwritten by its test-only rebuild; its binary hash, dependency hashes, source snapshot and raw results remain, but that exact executable was not separately retained.
-
-## Owned preparing frame controller
-
-Stage11 adds a separate, read-only frame controller to `cap-editor`. It returns a lifecycle owner before setup awaits; a retained stop handle waits for its actual Tokio task and all native decoder threads. The controller reuses ordinary segment timing, cursor smoothing, zoom uniforms, frame layout and immediate render methods. It never constructs an ordinary `EditorInstance` or loads/writes project configuration. Unsupported presentation, unresolved calibration offsets or inconsistent metadata decline preparation.
-
-Requests are coalesced into one latest pending frame with one decode/render in flight. Lazy initialization is cancelled only when the entire preview stops; an obsolete scrub cannot cancel its decoder. Completed render output is checked for frame number, dimensions and request sequence before delivery. The ordinary three-attempt render retry policy is retained, with ordinary `get_frames` behavior on retry. Source/decoder/cursor errors remain terminal. At most two display/camera segment pairs stay open; eviction waits for actual teardown, and late failures are retained rather than lost with an evicted worker.
-
-Frozen cursor assets share immutable image bytes and retain the ordinary SVG/PNG priority and image-format selection. Existing file loaders delegate to the same new cursor-reader and keyboard-byte parsers; no ordinary parsing or fallback order changed. Keyboard-enabled presentation and camera background blur currently require ordinary loading. The Stage11 validated bundle has no app consumer; the subsequent Stage12 integration is described separately below.
-
-The corrected common v2 candidate passed the native scoped gates on all three systems:
-
-| Platform       | Editor | Project | Rendering | Total passed | Existing ignored |
-| -------------- | -----: | ------: | --------: | -----------: | ---------------: |
-| macOS arm64    |     82 |     130 |       266 |          478 |                5 |
-| Linux x86_64   |     83 |     130 |       239 |          452 |                5 |
-| Windows x86_64 |     82 |     129 |       239 |          450 |                5 |
-
-Formatting, scoped checks and strict all-target Clippy passed. macOS scoped checks also include Tauri and GPUI. The project/rendering results carry forward from v1 because all runtime sources are byte-identical; v2 changes only the native fixture duration and reruns the complete editor suite on every system. Linux uses Mesa llvmpipe through Vulkan; a separate probe of the same production adapter factory selected Microsoft Basic Render Driver through DX12 on Windows. This is software-sandbox coverage on Windows/Linux, not proof across physical GPUs.
-
-The four-second v1 fixture failed before rendering on Linux and Windows: their libx264 encoder produced two fragments, below the test's required three. V2 generates three existing encoder GOPs (currently six seconds), preserving every assertion and requested frame time. All four composed cases then executed and passed on all three systems. The original failures remain recorded. Clippy also caught a test fixture initialization style issue; it was corrected and rerun. Controller tests caught a readiness notification race that could mask the original initialization error with cancellation; the final implementation retains the actual error.
-
-Four composed native tests compare visible RGBA pixels and frame layouts against independently finalized ordinary media. They cover PNG/SVG cursors with explicitly changing cursor samples, nonidentity zoom, independently encoded display/camera with distinct FPS and timing offsets, forward/backward/tail seeks, source relocation, three-clip eviction/reopening and a callback panic followed by native joins and source-owner release. Four additional deterministic native-thread tests cover failure while idle or after a returned frame and dropped terminal waiters, with release barriers proving both joins. These synthetic component tests do not measure Stop latency, audio synchronization, physical multi-clip capture, UI presentation or p95. Hardware decoding is requested but not asserted by the controller test API; the composed comparison uses RGBA. The original shared `.cap` fixtures remain unchanged.
-
-The frozen 15-file v2 bundle is `optimization-stage-11/preparing-controller-v2-overlay.tar.gz`, SHA-256 `78114380b3fba19df63a50e5a177f8c66fbbd1a1fc29397084e6a829e3382e60`; its manifest is `ef1b93c9a4c9c87b5b71a955a504a71d950a4c6dc8fa86bde44b931b6ab0e26b`. Evidence: `optimization-stage-11/native-combined-macos-v2/assessment.json`, `optimization-stage-11/native-linux/assessment-v2.json`, `windows-validation-20260910/stage11/`, `native-preview-macos/summary.json`, and `managed-terminal-tests/`. Exact v1/v2 editor executables are preserved. Stage11's helper compares collected visible bytes, dimensions and layout, but equal truncation of both buffers is not independently excluded by a byte-count assertion. No truncation was observed. Stage12 adds explicit complete-buffer length and stride assertions.
-
-## GPUI preparing image integration
-
-Stage12 connects the recording-owned observer to a GPUI loading window. The consumer requests the composed first image, checks the current recording attempt and window identity before delivery, and retains actual task and native decoder completion across close/reopen. Ordinary project loading waits for every retained consumer for that project. Closing a preview does not cancel recording finalization. The image remains read-only: playback, editing and export still require the ordinary ready editor. Progressive synchronized playback and a playable-range UI remain unfinished.
-
-The GPUI adapter preserves stopped configuration and uses the same initial clip-calibration calculation as ordinary loading. Current camera blur and selected animated-gradient preferences decline this early image. Keyboard presentation still declines; merely recording a keyboard sidecar does not, because GPUI ordinary rendering requires an explicitly configured keyboard overlay. The raw files remain available unchanged to ordinary loading and later user actions.
-
-The frozen Stage12 shared-core native matrix is complete, with the Linux filesystem qualification below. These scoped function and synthetic composed-frame tests exclude app consumers. Platform-specific tests account for the different totals; each platform also retains one ignored manual canonical probe.
-
-| Native platform                           | Editor | Recovery | Receipt | Passing total |
-| ----------------------------------------- | -----: | -------: | ------: | ------------: |
-| macOS                                     |     88 |      101 |       8 |           197 |
-| Linux, same recording executable on tmpfs |     87 |      101 |       8 |           196 |
-| Windows                                   |     86 |       96 |       8 |           190 |
-
-Linux recovery on the regular container filesystem passed 98 tests and failed three with `Conflicting recovery publication state; all files retained`; the same executable passed all 101 on tmpfs. Two failing test bodies and the relevant receipt guards are byte-identical to repository HEAD. The third test was introduced during Stage8 and already exposed the same rootfs limitation there; it is not an inherited HEAD test. The failure names and exact provenance are retained in `native-linux/receipt-source-provenance.json`. This remains a qualified result, not a clean Linux rootfs gate.
-
-Scoped format/check gates passed on all three platforms. Strict recording Clippy passed for lib/tests on macOS and Linux, and lib on Windows; editor all-target Clippy passed on all three. Seven new public-finalizer paired cases cover output/error parity and observed preview admission or decline, and three initial-calibration tests passed. Native composed cases include cursor assets, camera, zoom, relocation, three-clip eviction/reopen, keyboard-sidecar behavior and actual cleanup after callback panic. Full dimensions, stride and buffer length are checked before pixel comparison. macOS also asserts the ordinary AVAssetReader backend and actual BGRA surface parity. Linux ran the cases on software llvmpipe/Vulkan; there is no discrete Windows GPU claim.
-
-All 17 frozen overlay members, 26 Linux runtime members and 82 Windows evidence archive members were independently verified against their SHA256/size manifests, along with the exact retained macOS editor executable. Windows canonical fixtures matched before/after; Linux's three retained audio components matched, and its canonical media sandbox was not resumed. Linux and Windows build VMs were stopped with artifacts retained. Evidence and exact executable/source identities are aggregated in `.git/stop-editor-20260909/optimization-stage-12/native-summary.json`. The later Tauri dependency entry and renderer diagnostics are separate from this frozen source.
-
-On macOS, 39 targeted GPUI lifecycle, finalization, presentation and capture-stop tests also passed. The app compiles with the current stable toolchain. Strict GPUI all-target Clippy reports 28 unique inherited findings: each diagnostic context was checked against HEAD `0c403be8a57f7ba4de67140273708a392c8b4050`. This is a qualified gate, not a clean whole-app Clippy result. Evidence is under `native-gpui-macos/` and `gpui-consumer-review/clippy-provenance.json`.
-
-Four actual GPUI runs used matched builds in baseline/candidate/candidate/baseline order, each recording the same synthetic window scenario for about 60 seconds at 2560×1504. Each row is a distinct recording. Times below are milliseconds from the app's Stop marker; the ordinary-frame column records receipt by the ordinary editor.
-
-| Run          | Capture stopped | Loading shell | Early composed image | Next app cycle for early image | Finalization finished | Ordinary first frame |
-| ------------ | --------------: | ------------: | -------------------: | -----------------------------: | --------------------: | -------------------: |
-| 01 baseline  |            37.9 |          50.5 |                    — |                              — |                 300.3 |              1,067.7 |
-| 02 candidate |            46.1 |          60.6 |       No early image |                              — |                 298.0 |                878.1 |
-| 03 candidate |            43.7 |          58.7 |                185.3 |                          190.4 |                 287.0 |                332.2 |
-| 04 baseline  |            49.2 |          61.6 |                    — |                              — |                 291.9 |                383.2 |
-
-Only one of two candidate runs produced an early image. In run02, sources were available at 64.0 ms, but finalization ended before renderer readiness. The ordinary path proceeded after retained preview cleanup and preflight, reaching its validation marker at 814.5 ms; that interval is not an isolated cleanup measurement. Run03 produced the image at 185.3 ms and reached the next app cycle at 190.4 ms. The app-cycle marker does not independently prove external compositor presentation. Different initialization costs and only two observations per variant prevent p95, significance or universal speedup claims. No two-hour app timing or audio synchronization was measured.
-
-All four runs finalized, sought and played for about five seconds with zero dropped frames in the app logs. Complete post-run decoding compared every published frame and PTS against that run's retained original fragments: all 14,380 matched. Cursor/keyboard sidecars remained byte-identical, and all 192 retained project files were rehashed against the audit manifests. Configuration changes were limited to ordinary duration calibration (at most 4.5 microseconds in these runs); metadata changed only completion status and display path. The audit compares each recording to its own original, not media across runs. Raw results and matched-source/binary provenance are in `gpui-native-stop/summary.json`.
-
-The Tauri consumer is now applied. Its earlier complete native library run passed 446 tests; after the presentation extraction, nine new configuration/adapter-guard tests passed and the 61-test recording scope passed, including five of those nine. These counts must not be added as independent runs or described as a latest full 455-test run. Tauri Rust format/check and strict lib/tests Clippy passed, two command bindings were generated, six frontend files passed Biome, ten lease/socket tests passed, and desktop TypeScript checking passed. Tauri conservatively declines recorded camera and raw keyboard inputs: ordinary Tauri loading automatically creates keyboard presentation from raw events. The new parity tests establish configuration and guard behavior; subsequent genuine Tauri capture evidence and its remaining handoff issue are described below.
-
-A subsequent Tauri change stops an abandoned admission after its response receiver disappears, joining the owned transport without waiting for or cancelling recording finalization. Its ten-test native consumer scope passed, including the new pending-finalization case; formatting, scoped check and strict lib/tests Clippy also passed. The 15-file consumer snapshot is retained in `tauri-applied-v2/manifest.json`. These scoped runs overlap earlier tests.
-
-The opt-in native Tauri pixel/DOM capture harness subsequently passed formatting, scoped check and strict lib/tests Clippy. Its exact retained macOS library executable passed all 459 tests, including three frame-capture/fixture-selection tests. The first launch failed before tests because the nested artifact directory lacked its required Frameworks path; an owned Frameworks symlink fixed the layout, and the same executable then passed. This is harness and library validation; the two native WebView diagnostics below follow this suite. The fresh static frontend build succeeded with all 326 inspected source/config hashes unchanged, and its 693-file public output is retained. Evidence is in `tauri-native-preparation/harness/native-v2.json` and `tauri-native-preparation/frontend-result.json`.
-
-Two subsequent native Tauri diagnostic captures, 15 and 120 seconds, finalized successfully. All 895 and 7,169 decoded frames respectively matched each run's own retained source fragments in pixels and PTS; project/source trees were unchanged during verification. Both captured ordinary RGBA frame zero, but neither produced preparing RGBA or a visible preparing canvas. The parity verifier correctly reports incomplete. DOM observations therefore do not establish a seamless preview handoff. These unoptimized debug runs are functional diagnostics, not release latency benchmarks. The private log override passed its three native tests and scoped binary check/strict Clippy; normal log paths are unchanged. Evidence: `tauri-native-run/verification-matrix.json` and both `untimed*/benchmark.json` results.
-
-Source tracing explains the missing Tauri admission: `clean_capture::prepare` returns `None` on macOS/Windows, but the new preparing finalizer required the resulting Linux-only generation to be present. A correction giving actual recording finalizations their own checked, monotonically allocated identity is now applied; formatting, scoped check, strict Tauri lib/tests Clippy and all 461 native library tests passed, including allocation, duplicate, exhaustion and stale/recovery admission cases. The updated native executable then passed a genuine 120-second capture: preparing and ordinary frame zero matched all 3,358,368 visible RGBA bytes, dimensions and layout, and both canvases were observed visible. All 7,157 published frames and PTS matched the retained original fragments; all 66 original files were retained and the project tree stayed unchanged during audit. Generic crash-recovery requests, genuine clean-stop receipts, source ownership, current-attempt checks and failure handling remain guarded. Evidence is in `tauri-native-run/untimed-120s-v2/`.
-
-The corrected capture observed a live preparing canvas, then its retained image, then the ordinary canvas without a sampled blank state. A remaining size transient prevents a seamless-handoff claim: the preparing image measured 787.11 by 462 CSS pixels, the first ordinary image grew to 803 by 471.31, and it settled back after about 103 ms. The first visible preparing sample was approximately 725.7 ms after Stop; the benchmark ordinary-frame marker was 1,606.7 ms. These are unoptimized, instrumented functional observations, not release or p95 results, and DOM samples do not independently establish compositor presentation. The 569 native source, 326 frontend source/config and 693 embedded asset hashes remained unchanged through this capture.
-
-A further 120-second native layout diagnostic reproduced the transient and established its immediate cause. At first ordinary visibility, the actual container was already 835 by 494 pixels and all parent, toolbar and timeline geometry was at its final size. The accepted canvas alone retained 803 by 471.31 dimensions for 109 ms before settling to 787.11 by 462. The preparing/ordinary frame-zero pixels matched exactly again; all 7,171 published frames and PTS matched their original fragments, and all 26,930,830 original source bytes were retained. Native/frontend/asset hashes and owned-process shutdown passed. The additional bounded DOM geometry instrumentation makes this an untimed functional diagnostic. Evidence: `tauri-native-run/native-v3-assessment.json` and `untimed-120s-layout-v3/layout-analysis.json`.
-
-The first sizing fix passed 17 related frontend tests and desktop TypeScript, but its actual 120-second native v4 capture still showed the same 109 ms size transient. It therefore failed the intended visual outcome. Preparing and ordinary frame-zero pixels matched all 3,358,368 visible bytes; all 7,092 published video frames and PTS matched their retained originals, and all 26,559,920 original bytes remained unchanged. Source, binary, embedded assets and shutdown checks passed. The next refinement keeps initial geometry eager through one animation-frame remeasurement, preserving later 100 ms resize debouncing and cancelling pending work on teardown. Its subsequent native verification is recorded below. Evidence: `tauri-native-run/native-v4-assessment.json` and `tauri-initial-bounds-fix/first-paint-refinement/`.
-
-The refined v5 candidate passed 21 related frontend tests, desktop TypeScript and the private static/native builds. Its genuine 120-second capture used identical preparing and first ordinary bounds of 787.109375 by 462 pixels, with no later canvas-size transition in the following 1,001 ms of bounded DOM observations. Frame-zero RGBA parity passed. All 7,068 published video frames and PTS matched retained originals, all 26,426,138 original source bytes remained intact, the project tree stayed unchanged during verification, and owned processes shut down after finalization. This establishes the intended sizing outcome for this native case; it remains an unoptimized, instrumented functional check, with no audio/camera or external compositor/p95 claim. Evidence: `tauri-native-run/untimed-120s-bounds-v5/layout-analysis.json`, `parity.json` and `verification.json`.
-
-Fresh Windows validation of the current 1,356-file source freeze passed 770 native tests, with six existing/manual tests ignored. The native adapter was Microsoft Basic Render Driver through DX12. Scoped checks and strict encoder/audio/video/project/rendering/editor Clippy passed. Recording library Clippy passed; its test target retains an inherited `items_after_test_module` finding in a file byte-identical to HEAD. Both canonical 15-second screen and 60-second microphone probes passed: four video requests per recording matched independently finalized media, all 2,883,584 microphone PCM frames matched bit-for-bit through EOF, outputs/documents matched, originals stayed unchanged, and source release plus lock reacquisition passed. These are opt0 function diagnostics, not app latency or p95 evidence. Tauri compilation encountered compiler allocation failures with two jobs; the one-job native library check and test executable build later passed, but the storage reserve prevented that test execution. Expanded two-hour validation is paused under the narrower editor goal. Evidence: `platform-capacity/windows-fresh/current-shared-short-assessment.json`.
-
-Fresh Linux validation of the same source freeze passed 782 unique native tests, with the same six existing/manual tests ignored. The adapter was Mesa llvmpipe through Vulkan. Scoped formatting, checks and strict Clippy passed. All 101 recovery cases passed on the default root filesystem and again with the same binary on tmpfs; the duplicate run is excluded from the total. All three previously failing filesystem cases explicitly passed in both scopes. An initial receipt filter matched no tests and is retained as non-evidence; the corrected filter passed all eight intended cases. The 73-file evidence archive was downloaded and every member verified. Canonical integration runs remain separate from these unit fixtures. Evidence: `platform-capacity/linux-fresh/native-evidence/assessment.json`.
-
-The current Linux standard canonical 15-second and 60-second probes subsequently passed publication, retained-source, cancellation, actual-join and recovery-lock checks. All 2,883,584 microphone PCM frames matched bit-for-bit through EOF. Preparing video coverage was partial: finalization ended after two of four requested screen seeks and three of four microphone-recording seeks. Every returned frame matched its independently finalized software reference; the remaining requests were cancelled. No delay was added to force those requests to complete, and these results do not establish four-seek canonical parity. Evidence: `platform-capacity/linux-fresh/canonical-short-evidence/assessment.json`.
-
-A separate eight-file renderer diagnostic patch was applied after the frozen native matrix and matched GPUI runs. Its format/check, strict rendering all-target Clippy and 15 preparing-preview tests passed on macOS. A fresh 15-second native capture reached the ordinary first frame at 388.02 ms and played 300 frames at 60.0 fps with zero reported drops. All 895 decoded frames and PTS matched its retained originals; sidecars and source hashes were preserved. It produced no early image: finalization ended at 236.94 ms while preparing layer construction continued until 319.72 ms.
-
-That diagnostic measured 83.74 ms for managed decoder readiness, 4.09 ms for graphics constants and 176.42 ms for layer construction. The largest layer costs were the shared compositing pipeline (70.77 ms), first font-system scan (54.38 ms) and image layer (32.84 ms). These nested, instrumented timings identify work to investigate; they are not independent hardware timings or a matched speedup. No rendering phases occurred before Stop in this process. The exact diagnostic binary and 564 source hashes are retained under `renderer-readiness-diagnostics/summary.json`. No font warmup or initialization optimization has been accepted, and these later diagnostics do not change the provenance of the four reported timings. The instant, playable-editor goal is still in progress.
-
-An experimental follow-up omits the image/text/caption/keyboard layer bundle only for the checked preparing renderer. Existing ordinary constructors retain the complete bundle and original preparation/render order. Unsupported project or prepared-text inputs produce an explicit error before restricted rendering. On macOS, all 88 editor and 269 rendering library tests passed, with five existing rendering tests ignored; scoped checks also covered export and Tauri, and strict editor/rendering all-target Clippy passed after removing four unused imports from the extraction. Two additional native tests now pass on Apple M4 Max/Metal: ordinary image, text, caption and keyboard output remains visible, full/restricted frame-zero pixels and layout match, and late unsupported inputs leave the GPU target unchanged. Seven existing native preparing-preview tests also passed. The first boundary-test attempt used a segmented-text-only inspection method on ordinary batched text; that test assertion was corrected while retaining its rendered-pixel check, and both attempts are preserved under `preparing-overlay-boundary/native-macos/`. A fresh matched comparison is recorded below. No cross-platform or speedup acceptance is inferred from this local experiment; skipping early initialization can defer costs to ordinary loading.
-
-A fresh GPUI comparison isolates the optional overlay bundle change: both variants already include the preparing consumer and renderer diagnostics. Both opt2 executables were built from the same isolated source paths, with equal dependency profiles, features, locks, external inputs and assets. Only the documented four-path renderer/editor delta differs. Post-matrix source, binary and harness verification passed before any replay-test additions; an unused Tauri scaffold change in the original checkout is separately recorded and excluded from the GPUI dependency graph.
-
-| Fresh run                 | Early composed image | Early image app cycle | Recording finished | Ordinary first frame |
-| ------------------------- | -------------------: | --------------------: | -----------------: | -------------------: |
-| 01 full layers            |       No early image |                     — |           295.6 ms |             368.0 ms |
-| 02 omitted overlay layers |       No early image |                     — |           282.4 ms |             849.7 ms |
-| 03 omitted overlay layers |             177.3 ms |              183.3 ms |           295.5 ms |             349.8 ms |
-| 04 full layers            |             184.3 ms |              190.4 ms |           298.1 ms |             340.6 ms |
-
-The 849.7 ms observation remains part of the result. Its preparing layer construction took 523.6 ms, dominated by several GPU pipeline constructors; none of the omitted overlay constructors ran. Finalization safely relocated the source and ended the job, but ordinary loading waited for the retained preparing task to return from synchronous construction and join its native workers. Ordinary validation occurred at 681.3 ms. The logs establish this ordering, not the precise worker-exit timestamp or shader-cache causality. Both variants completed five seconds of ordinary playback with zero reported dropped frames. All 14,379 published frames and PTS matched their respective retained original fragments (3,595, 3,594, 3,595 and 3,595 frames); sidecars and all project trees remained unchanged during verification. Separate same-source composition replays subsequently passed for all four recordings on Apple M4 Max/Metal with FFmpeg hardware decoding: every visible pixel, dimensions, stride and layout matched the ordinary full renderer at frame zero. Decoder workers joined, and project/source trees stayed unchanged. These replays use a retained pinned Rust 1.88 opt0 test executable, separately qualified from the stable opt2 measured apps. The initial nonmember-workspace failure and paused rebuild are retained; neither changes the measured binaries or their completed source audit. These recordings contain no cursor motion, so motion coverage belongs to the earlier dedicated native tests. This four-observation matrix establishes neither a reliable speedup nor p95. Exact phases and provenance are under `preparing-overlay-benchmark/phase-assessment.json` and `source-after-matrix.json`.
-
-A separate optimized macOS diagnostic over the immutable two-hour canonical input completed successfully. It uses the public preparing path, a test-only clean-stop receipt on a validated writer-normalized copy, and the current restricted preparing renderer. The exact three runtime source hashes match its retained build manifest; the earlier description of this binary as using full layers was incorrect. T0 precedes finalizer worker spawn; source-copy/hash/projection preflight warms the input before T0. It does not execute native recorder shutdown, app presentation or audible playback.
-
-| Two-hour diagnostic milestone        | Time from T0 |
-| ------------------------------------ | -----------: |
-| Preparing sources observed available |   1,166.0 ms |
-| First composed RGBA frame            |   2,443.6 ms |
-| Preparing finalization returned      |  12,441.6 ms |
-| Preview native workers joined        |  12,444.2 ms |
-
-All first-frame pixels and layout matched the ordinary finalized-media compositor; published media bytes and normalized documents matched the ordinary run. Canonical originals, source/native/binary identities and lock availability after joins were verified. This diagnostic did not repeat PCM decoding; complete PCM comparison belongs to the earlier Stage10 evidence. Its subsequent ordinary finalization measured 11,560.5 ms, but this one ordered pair, with different concurrent work and warmed state, is not a matched no-regression performance result.
-
-Initial analysis consumed 397.7 ms, including 307.8 ms for 3,383 fragment-duration probes, all returning None. Initial whole-source snapshotting consumed 676.2 ms; hash groups contained 1.273 and 1.123 GB, so gross group imbalance does not explain the delay. Projection took 91.4 ms, primarily repeated completeness checks. After availability, managed decoder startup took 604.8 ms, graphics constants 91.4 ms, retained preparing layers 567.0 ms and RGBA output 12.1 ms. Nested/overlapping phases must not be summed as isolated costs. The next optimizations must preserve the existing integrity checks and duration fallback behavior. Raw common-origin phases, exact build qualification and results are in `two-hour-composed-diagnostic/isolated-preparation/evidence/two-hour-run-v2/assessment.json`. This single optimized function diagnostic establishes neither actual two-hour Stop/UI latency nor p95, and the instant/playable-editor goal remains incomplete.
-
-## Drivers
-
-From `apps/desktop-gpui`, build the drivers with `cargo build --example studio-finalization-benchmark --example media-readiness-benchmark --example audio-readiness-benchmark`. The finalization driver takes a disposable unfinished Studio project; it mutates that copy. The readiness drivers take media paths and are read-only. The audio driver's default mode reproduces the old background loader; `CAP_BENCH_PROGRESSIVE_AUDIO=1` selects the block loader. Both emit their execution and timing methodology. `CAP_BENCH_MIX_AUDIO=1` adds a current-renderer comparison with a barrier after every repetition. Hashing and mixing remain outside the decode timer.
-
-`CAP_BENCH_FULL_AUDIO_ONLY=1` skips the range experiment. Without it, the driver exits unsuccessfully if decoded ranges differ from the full-track reference. `CAP_BENCH_STREAM_AUDIO=1` also checks every sequential chunk against that reference. Preserve failed range experiments as failures; the known two-hour timestamp-seeking mismatch must not be mistaken for passing progressive-window coverage. Progressive windows use sequential sample positions instead.
-
-The debug Tauri driver requires the explicit arguments `--stop-editor-benchmark --allow-real-recording`, both `CAP_STOP_EDITOR_BENCHMARK_OUTPUT` and `CAP_STOP_BENCH_LOG_DIR`, and a private app identifier beginning `so.cap.desktop.stop-editor-benchmark.` with a nonempty suffix. Output and log paths must be fresh private siblings under an existing canonical directory. `CAP_STOP_BENCH_SECONDS` selects 1–86,400 seconds (default 15); `CAP_STOP_BENCH_MIC` and `CAP_STOP_BENCH_SYSTEM_AUDIO` opt into audio. Environment variables alone cannot activate recording. Keep the private identifier and recordings directory isolated from the user library. Its injected editor observer waits for a completed render in the existing frame statistics, a visible editor canvas, and two animation frames. A timeout is a failed benchmark, not a successful editor-open measurement. The initial observer only watched worker messages and missed Tauri's direct-canvas renderer; that incomplete run is excluded.
-
-Existing GPUI drivers include `CAP_GPUI_AUTO_RECORD=studio:60`, `CAP_GPUI_AUTO_NO_MIC=1`, `CAP_GPUI_AUTO_SYSTEM_AUDIO=1`, `CAP_GPUI_AUTO_EDITOR`, and `CAP_GPUI_AUTO_PLAYBACK`. `CAP_GPUI_AUTO_SEEK` targets a fraction of the visible timeline viewport. The new `CAP_GPUI_AUTO_SEEK_TIME=7194.5` targets seconds into the recording and logs the clamped time passed to the ordinary seek method. Use explicit time for long-recording tail checks. Keep app data and recordings isolated from the user's library.
-
-## Preparing playback integration on 2026-09-10
-
-The active goal was narrowed and resumed through the app: immediate editor presentation, equivalent early footage, actual playable-range feedback, and retained preview/playhead/playing intent through ordinary-editor handoff. Main was subsequently synchronized to `284ae24a79bd0813743f51e6219d11ae0042d38f`, preserving the local candidate and all evidence. Neither the goal nor native screenshot acceptance is complete.
-
-The shared preparing controller uses actual composed frames and completed required audio to admit a contiguous playable range. It freezes at that range, retains the latest seek response, cancels abandoned audio-start requests, and joins media workers before handing a take-once completed PCM cache to the ordinary loader. Required audio that cannot be proven equivalent keeps playback unavailable. Cached metadata permits only the finalizer's existing clearing of audio gap summaries; it cannot relabel paths, devices or start times.
-
-The Tauri backend now exposes window/epoch/job-scoped state and playback commands, publishes actual status changes, and includes the joined snapshot in the ordinary editor response. Closing a window releases preparing audio after cleanup. A replacement preparing request retires the previous session after its join. The frontend owns resuming ordinary playback after its target frame is actually drawn; that integration and user-intent supersession are still being validated.
-
-Tauri audio admission uses the ordinary timing-repair calculation against the projected final metadata and an actual bounded recording-log snapshot. Only cleanly stopped audio writers can reach this path. A missing log matches ordinary loading; unreadable, changing, nonregular, invalid UTF-8 or over-4-MiB logs conservatively defer required audio to ordinary loading. Preserved M4A requires the same AAC/no-video probe as finalization; transcodes and changed filenames are not admitted. These conservative limits must not be presented as universal early audible playback.
-
-The latest combined macOS editor library suite passed all 116 tests, including full PCM equality through gap-cleared handoff, corrupt-audio refusal, composed image equality, source release, rename and cancellation of an old playback handle without stopping its replacement. Current scoped Tauri compilation and all 16 preparing adapter/audio/lifecycle tests passed, as did 14 tests selected by the finalization filter. Shared editor strict all-target Clippy passed. The filtered runs overlap; their counts must not be summed into a unique platform total. GPUI scoped compilation and 165 focused preparing, recording, session, window and timeline tests passed. The final Tauri frontend passed 86 tests across eight files and desktop TypeScript. Scoped Biome passed for the initial 25 handwritten files and the six-file transcript/clip correction. Those panels now use the same ownership queue; recording/import waits for an acknowledged pause and declines a superseded request. Guarded handoff starts return a receipt for their exact playback handle; late cleanup cannot stop a newer ordinary playback. The queue retains ownership during failure cleanup and transfers ownership after successful handoff.
-
-Windows passed 68 native audio tests with the shared 60-second fixture: 64 shared tests plus four existing Windows latency tests. All decoded samples and EOF matched. The older wrapper expected 64 and flagged the count despite the native executable exiting successfully; that wrapper result and the corrected source-qualified count are both retained.
-
-The initial Linux/Windows screenshot builds use a retained source-v1 snapshot plus an explicitly recorded Clone correction and required real build assets. They predate the final controller integration. Linux Tauri completed an actual 15-second X11 capture and opened its ordinary editor; that short run did not present a preparing frame. The first external desktop-video recorder failed because it inherited the app's native-library search path. A corrected run produced a verified actual desktop video and editor screenshot; the user accepted Linux and requested no further Linux screenshots. Linux GPUI also built successfully from its qualified seed source. Both owned Linux VMs are stopped with source, media and build evidence retained.
-
-Windows GPUI genuinely opens the preparing editor. Its capture also exposed a persistent outline matching the hidden main window, and a white/washed-out preview. The initial rendering failures are retained; their runtime-layout cause and corrected results are recorded below. An independently invoked native export-preview reproduced washed-out output before GPUI presentation and then exited with an access violation during or after teardown; its generated JPEG does not make that diagnostic successful. The original recording media and project remain unchanged. A fresh real Stop reproduced the outline with 772 native trace records: the main window was hidden 26 seconds before editor creation, with no later show event, move/resize loop or held mouse button at editor creation. Show/hide clears the artifact diagnostically, but that does not establish a production fix.
-
-The integrated macOS GPUI build uses a separate 2,326-file hash-verified snapshot because concurrent crop changes invalidated the preceding shared-checkout build's provenance. That preceding binary was retained and never launched. A genuine 60-second capture opened the shell on the next presentation cycle at 88 ms. Finalization finished at 199 ms before preparing rendering returned a frame, so the early-play hook did not run. Ordinary playback rendered 299 frames over five seconds at 59.8 fps with zero drops. This proves immediate chrome and ordinary fallback for that run, not playback during processing. All 3,594 decoded frames and PTS matched retained fragments, cursor/keyboard sidecars matched byte-for-byte and the full project tree remained unchanged during verification.
-
-The new Tauri frontend and native builds are source- and asset-hash qualified. The initial native launch exited before recording because newly merged startup code honors the shared GPUI preference even for a private Tauri identifier. It preserved the user's running GPUI. An explicit debug Stop-benchmark-only branch now skips that startup selector and its shared marker handling; release behavior and user settings are unchanged. The failed launch remains recorded.
-
-The subsequent actual 120-second Tauri run preserved all 7,131 decoded frames and PTS, sidecars and 19,106,595 bytes of original media. Stop returned at 172 ms and the ordinary frontend frame event arrived at 1,549 ms. Actual UI Space playback and native screenshots confirmed about 60 fps, with 603 rendered frames, zero skips and no starvation in the observed interval. Preparing correctly declined because recorded clicks require late ordinary auto-zoom settings; this is ordinary fallback proof, not early-frame or playback-handoff proof.
-
-The final 86-test frontend rebuilt in 26.5 seconds with all 345 source hashes unchanged and 696 retained assets. Its native build also includes the explicit handoff start-frame selection after awaited music loading, so late old playhead events cannot change the approved target. A genuine 15-second Stop smoke on that build returned at 194 ms and delivered the ordinary frontend frame event at 577 ms. Actual full playback and replay from the end passed; the replay screenshot shows 0:03.01. All 899 published decoded frames and PTS matched retained originals, and the source/project audit passed. These single debug runs use different recordings and are not a performance comparison.
-
-A broader Tauri library run passed 468 tests and failed the existing upload scheduling assertion at 78.3 ms versus its 50 ms threshold. The entire upload file is byte-identical to current main. The isolated recheck through Cargo passed without source or threshold changes. A preceding direct-binary recheck lacked Cargo's runtime library paths and executed no tests; its loader failure is retained. The final serial run passed all 469 tests in 6.64 seconds. These concurrency and runtime-path qualifications remain with the broad gate.
-
-Windows Tauri's first launch failed the private logger's canonical-path guard; the next exposed a frontendDist Windows-drive URL interpretation issue. Both failures are retained. A relative asset path to the same 693 verified seed assets fixed the configuration; the unchanged-source native rebuild passed in 90 seconds. Its genuine 59.59-second recording opened the editor and actual Play advanced to 0:27.56 before pausing. The captured region was covered by the GPUI editor, so the recording contains that window. The native desktop video retains both the initial disabled editor chrome and the completed editor. Finalization took about 397 ms and the ordinary preview arrived about 3.8 seconds after editor document start; no preparing frame was observed. This remains a seed-build run, not validation of the latest progressive handoff. Current Windows function validation is being refreshed against the final common source manifest; the refreshed Linux results follow below. Storage, software-GPU, build-profile and source-version limitations remain explicit; no screenshot is a release performance result or a zero-regression guarantee.
-
-Evidence is under `optimization-stage-13/preparing-playback-combined`, `tauri-playback-integration`, `tauri-audio-admission`, `gpui-playback-integration`, and `linux-native-ui`, with Windows artifacts under `optimization-stage-12/windows-native-ui`.
-
-The standalone absolute-color diagnostic uses the exact existing native rendering libraries and does not edit production source. On both macOS and Windows, known RGBA bars survive GPU upload/readback, identity compositing and full composition exactly at all 24 sampled interiors. CPU YUV conversion matches the scalar reference; GPU conversion differs by at most one channel unit. The exact Windows recording software-decodes and composites in normal color on both systems, with actual native workers joined. A second diagnostic loads the original project configuration and isolates shadow and screen motion blur: all four variants render in normal color on both platforms, at the same 1168-by-702 output geometry as the failed export. Native CPU YUV and scalar RGBA outputs match byte-for-byte. These probes explicitly force software decoding and omit real cursor sidecars and recording timing metadata; the ordinary Windows decoder fallback is still under investigation. Earlier preparing-versus-ordinary equality alone cannot rule out both paths sharing a color bug. Evidence: `optimization-stage-13/windows-color-diagnostic/`, `windows-color-diagnostic-v4/`, and `optimization-stage-12/windows-native-ui/color-probe-v3/` and `color-probe-v4/`.
-
-The outline's scoped native diagnostic replays also remain separate from product verification. A temporary hook on the task-owned GPUI main thread invoked the actual content-affinity setter and nonclient activation pair; both succeeded, preserved hidden state and produced byte-identical before/after desktop images. The hook was removed after each operation. The native affinity getter succeeded and confirmed zero. Hidden-window paint and forced GPUI repaint messages also failed to reproduce the border. These negative results do not justify a visibility, theme or affinity patch; the real editor-opening transition remains under investigation.
-
-The final Linux v3 source snapshot verified all 2,331 file hashes before and after native validation. The shared library scope passed 531 unique tests: audio 63, rendering 244, editor 115, recovery 101 and receipt 8; five existing rendering tests stayed ignored. The final Tauri library executable passed 528 tests with zero failures, filtering only the binding-writing export test to preserve frozen source. This gives 1,059 unique shared and Tauri library passes, excluding overlapping filtered runs and the separate native fixture cases. The same recovery binary also passed all 101 tests on tmpfs; that duplicate run is not added to the total.
-
-Linux's matched 15- and 60-second canonical runs compared every observed video frame against independently finalized software-decoded media. Actual end-of-stream cancelled outstanding later seek requests: the observed requests were 0 and 7 seconds on the short fixture, and 0, 30 and 58 seconds on the longer fixture. All 2,883,584 audio frames matched bit-for-bit through EOF. Required worker joins, source release, output/configuration checks and all 59 original files (167,229,187 bytes) passed. The actual renderer selected llvmpipe through Vulkan. These are native function results, not additional UI screenshots or physical-GPU coverage.
-
-Scoped Linux compilation and strict shared Clippy passed. Tauri strict Clippy exposed one equivalent optional-value condition, rewritten with `is_none_or`; macOS formatting and scoped Tauri compilation then passed, as did the current Linux scoped Tauri check. The remaining three Tauri Clippy warnings are in the upload file, whose full bytes match current HEAD. Initial storage failures and reserve stops are retained separately from source/test failures. The final native Tauri build succeeded after audited removal of obsolete or duplicated owned compiler artifacts. Evidence: `optimization-stage-13/current-linux-functions/` and `native-current-v2/`.
-
-The next color probe kept managed decoders alive through rendering, then awaited their actual joins. On macOS, software YUV420p and native VideoToolbox NV12 produced identical corresponding composed output. On Windows, both requested hardware settings resolved to FFmpeg software decoding; both produced identical normal-color output and clean joins. A further ordinary-factory diagnostic creates the renderer before the decoder, matching export initialization order. On macOS, actual AVAssetReader texture-backed NV12 and the FFmpeg VideoToolbox path again produce identical corresponding PNGs. Ordinary handles expose no join API, so those runs record handle drop without claiming a worker join. Their initial standalone dynamic-library loader failures are retained; actual tests passed with the verified native-library search path. All these probes still omit actual cursor sidecars and recording timing metadata. Evidence: `windows-color-diagnostic-v5/`, `windows-color-diagnostic-v6/` and the Windows `color-probe-v5/` directory.
-
-The additional same-thread Windows affinity replay verified successful hidden-window transitions from 0 to 17 to 0, with an unconditional final restore to 0 and successful removal of every temporary hook. All desktop captures remained byte-identical. Repeated hides and genuine reopen-from-Recents also stayed clear. Those probes used an expanded main window and do not rule out the original compact recording-to-editor sequence. The visible outline was still unresolved at this probe stage; the later Main-frame module and its source-qualified native checks are recorded below.
-
-The compact visible-affinity sequence later reproduced the exact outline: enabling exclusion while visible, hiding, then repeated hidden clears changed exactly 3,048 pixels along the original client rectangle. A matched comparison with `DwmFlush` remained clear in its immediate captures, but a later capture showed the outline again. This leaves delayed composition and inspection ordering unresolved. The same run exposed a safety issue with a proposed read-before-write guard: the hidden getter returned success and zero, while the subsequently visible window still reported exclusion enabled. That guard was rejected before any production edit. Removing the new early clear also needs an early-close check because the preparing editor can re-show the protected main window before finalization reaches Idle.
-
-The actual Windows exporter was run again on two disposable copies differing only in `cursor.hide`. Both native processes exited successfully, but both images were incorrect: the original remained washed out, while the hidden-cursor variant had white and green/magenta corruption. Hiding the cursor does not establish or fix the cause. The ordinary-factory v6 diagnostic then rendered normal output on Windows with both default MediaFoundation-failure-to-FFmpeg fallback and forced FFmpeg. Both resolved to software YUV420p and produced equal decoded/output bytes. The full-library v7 probe uses actual recording metadata and sidecars through `cap_export::preview::render_preview`; both macOS and Windows processes passed and rendered normal color, with equal corresponding outputs for both decoder preferences. All input and disposable-project bytes remained unchanged. Evidence: `same-thread-window-probe-v3/`, `same-thread-window-probe-v4/`, `gpui-export-cursor-ab-v3/`, `color-probe-v6/`, `color-probe-v7/`, and `optimization-stage-13/windows-color-diagnostic-v7/`.
-
-The shader runtime layout explains the color discrepancy. The production Windows renderer selects bundled DXC only when both `dxcompiler.dll` and `dxil.dll` are beside the executable, or beside its parent when the executable directory is named `deps`. The retained test executables, standalone GPUI output and retained CLI directory lacked that pair; they loaded FXC. The successful v7 diagnostic had the pair and loaded DXC. Copying the exact verified runtime pair beside the unchanged executables corrected the isolated overlay, cursor/ripple and editor PNG tests. Full corrected rendering passed 244 tests with five existing ignored tests; full corrected editor passed all 114 tests. Together with audio 67, recovery 96 and receipts 8, this gives 529 unique current Windows shared library passes. All 2,331 frozen source hashes and retained executable hashes remained unchanged. The original two rendering and five editor failures remain recorded as runtime-layout failures, rather than being erased or weakened. The actual adapter is Microsoft Basic Render Driver through DX12, not a physical GPU. Evidence: `optimization-stage-13/native-current-windows-v3/`.
-
-The same runtime correction restored full-color native GPUI playback in the unchanged app. Module receipts and the app log confirm the exact adjacent DXC/DXIL libraries were loaded. Real Play/Pause advanced the original footage from 0:37 through 1:04. The retained core-playback snapshot reports 3,489 rendered frames, one skipped frame and zero starvation; GPUI paint submission on this software desktop was about 4.6 fps, so this is not a visible 60 fps claim. That ordinary reopen was outline-free because the main window had been shown and hidden during reopening. It does not prove the Stop outline is fixed. The unchanged CLI also returns a correctly colored JPEG after the runtime correction, but still exits with `0xc0000005`; that diagnostic remains failed. Evidence: `optimization-stage-12/windows-native-ui/runtime-module-audit-v1/`, `runtime-module-audit-v2/` and `gpui-dxc-playback-v1/`.
-
-A further real 19.017-second Stop reproduced the outline using only real input, desktop video and a subsequent desktop capture, with no window-state queries, hooks or DWM probes during the flow. Capture stop took 81.8 ms and remux 134.1 ms; the 837 captured frames and originals were retained. These are single diagnostic observations, not performance comparisons. Separate compact-window replays reproduced the outline after either one actual hidden affinity clear or two back-to-back clears. Duplicate-clear removal alone is therefore not a demonstrated fix. No production window-style, visibility or affinity change has been applied. Evidence: `gpui-native-v7/`, `same-thread-window-probe-v6a/` and `same-thread-window-probe-v7b/`.
-
-An additional native GPUI Stop with DXC loaded retained the same desktop outline over correctly colored footage. App logs confirm a manual Stop and a validated 23.767-second recording with 1,030 frames; the initially observed 0:04 was the paused playhead, not automatic recording termination. Capture shutdown took 78.94 ms and remux 152.86 ms. A subsequent hidden-Main `SetWindowPos` using `SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE` returned success, but the before, 600 ms and six-second desktop captures remained byte-identical. A frame refresh alone does not fix the outline. The outline extends outside the video preview on the actual desktop; it is not merely a border painted into the displayed footage. Evidence: `gpui-dxc-stop-v1/` and `hidden-frame-changed-v1/`.
-
-The current Windows canonical 15- and 60-second cases subsequently passed all eight requested video comparisons against independently finalized software references. All 2,883,584 microphone audio frames matched bit-for-bit through EOF; the separate managed-audio EOF test also passed. Actual worker joins, source release, lock reacquisition, outputs, configuration and original-file audits passed. The 2,331 source hashes and retained test executables remained unchanged. These are functional equivalence results; they do not turn the unresolved outline or CLI exit failure into passes. Windows Tauri scoped compilation and strict library/test Clippy subsequently passed; native library test execution remains separate under the recorded storage limit. Evidence: `optimization-stage-13/native-current-windows-v3/`.
-
-The requested upstream Zed review is pinned to `86b2cf96623a12ae3f524c3780b6bcce4443ed23`. Its complete inspected Windows backend has no capture-affinity calls or `SW_HIDE`; application hide is empty, while minimize and destruction use separate paths. Cap's local GPUI working patch adds native caption/edge styles and custom client insets absent from both current upstream and the July 19 fork ancestor. Both default to DirectComposition. These findings identify a Cap-specific frame/lifecycle difference, not an upstream workaround already proven for this recording flow. Primary sources: [Zed window styles](https://github.com/zed-industries/zed/blob/86b2cf96623a12ae3f524c3780b6bcce4443ed23/crates/gpui_windows/src/window.rs#L471-L494) and [Windows application hide](https://github.com/zed-industries/zed/blob/86b2cf96623a12ae3f524c3780b6bcce4443ed23/crates/gpui_windows/src/platform.rs#L592-L599). Exact source snapshots, hashes, comparisons and the unapplied diagnostic-only frame patch are under `optimization-stage-13/zed-upstream-comparison/`.
-
-A fresh native run with the existing `GPUI_DISABLE_DIRECT_COMPOSITION=1` setting initially appeared outline-free. The later desktop capture instead showed the entire hidden main client region as a solid white rectangle. Floating controls also lost transparency, producing black rectangles in this recording. This alternative is rejected: it changes the artifact and introduces visible capture differences. It does not fix the settled result, and no production rendering mode was changed.
-
-The matched fresh default process restored normal composition and reproduced the outline. A subsequent reversible test on only the idle hidden Main cleared `WS_CAPTION`; Windows automatically cleared only the associated `WS_EX_WINDOWEDGE` bit. With a frame refresh, the outline disappeared while visibility, bounds and composition stayed unchanged. Restoring the exact original styles restored the outline. Both cleared captures matched each other byte-for-byte; the before and both restored captures also matched byte-for-byte. The first attempt stopped on that native coupled-style change and restored the baseline before a corrected diagnostic explicitly recognized it. This proves the visible artifact depends on the native caption/edge representation, but does not yet prove its trigger or justify changing visible-window appearance. No product source was changed. Evidence: `optimization-stage-12/windows-native-ui/hidden-frame-style-v1/` and `hidden-frame-style-v2/`.
-
-Current Windows scoped compilation for the shared audio, rendering, editor and recording crates passed. Strict library/test Clippy retained a Windows-only `items_after_test_module` finding in `capture_pipeline.rs`, whose full bytes match HEAD and the frozen manifest (`fdee8cb040177fe55cda42e7b595361d6becb87b955e5c8836ba1e0e99c07e7a`). It is recorded as an inherited lint qualification; the file and lint threshold were left unchanged. Tauri scoped compilation and strict library/test Clippy also passed. The native Tauri test run remains a separate gate.
-
-A bounded native API observer then captured an actual 21.550-second GPUI recording and manual Stop that reproduced the outline. Its 11 committed records contained eight `DefWindowProcW(WM_NCACTIVATE)` calls before recording start and none at Stop. Their common caller and varying message parameters do not identify them as Cap’s synthetic theme redraw pair. All three affinity writes requested zero: one at start and two at Stop. The active Virtual Display Driver explains the existing streamed-display exclusion bypass. The two Stop clears were about 0.870 ms apart. Successful API returns with stale last-error values were not treated as failures. The observer’s warmed disposable-window test preserved return values and last-error behavior; teardown restored exact import pointers and protections with zero dropped or in-flight records. Its inert pinned module was removed by safely exiting the owned idle process. This rules out an observed direct theme redraw at Stop in this run; no speculative theme guard was applied. Evidence: `optimization-stage-12/windows-native-ui/api-observer-gpui-v2/`.
-
-A subsequent hidden-Main nonclient policy experiment returned `S_OK` for `DWMNCRP_DISABLED` and removed the outline. Immediate and six-second captures matched byte-for-byte. Restoring `DWMNCRP_USEWINDOWSTYLE` returned `S_OK`, re-enabled nonclient rendering and restored a capture byte-identical to the baseline. Process/window identity, styles, extended styles, visibility, iconic state and outer bounds remained exact across all captures; client bounds were not recorded in this probe. The later restored capture differs and is retained. The original raw policy enum was not readable: restoring `USEWINDOWSTYLE` follows the source-default inference, and the owned idle process subsequently exited to clear diagnostic state. This proves the policy can remove the observed artifact without changing window styles. It does not yet validate automatic hide/show handling, visible appearance or a production fix. Evidence: `optimization-stage-12/windows-native-ui/hidden-nc-policy-v1/`.
-
-The resulting local GPUI candidate installs a native subclass on only the Main window. It restores the normal nonclient policy before show-related default handling, reconciles actual visibility after `WM_WINDOWPOSCHANGED`, and removes its subclass before forwarding destruction. It retains styles, bounds, capture-affinity calls and default message handling. Review removed a premature post-`WM_SHOWWINDOW` reconciliation and added show restoration before forwarding `WM_WINDOWPOSCHANGED` when earlier notification is suppressed. The shared GPUI fork is unchanged. The exact Windows module is `623fd5404020c0eeb63038bf29fd2922cad205826ee39a97dda25662e3f2f082`; macOS GPUI workspace formatting and scoped compilation passed with source/lock hashes unchanged. Those checks exclude Windows code paths; exact-module native Windows validation is pending. Evidence: `optimization-stage-13/windows-hidden-frame-production/`.
-
-The current Windows Tauri test binary initially failed before the Rust harness with loader status `0xc0000139`. Its missing Common Controls activation manifest caused this fixture-runtime failure. An external manifest did not resolve it. A retained derivative with the exact `tauri-build` application manifest embedded by Microsoft’s resource tool launched successfully; all original executable code/data sections and the untouched original executable were retained and verified. That run passed 437 tests and failed eight at the same closed-listener timeout helper. Four independently bound-and-closed Windows loopback ports correctly returned `WSAECONNREFUSED` after 2.003–2.019 seconds, beyond the helper’s two-second deadline; a fresh-process targeted rerun reproduced the timeout. The resulting test-only change allows five seconds on Windows, retains two seconds elsewhere, and preserves the required connection failure and retry logic. It changes no production listener behavior. Root workspace formatting and Tauri compilation passed with the edited source hash unchanged. Native targeted and full-suite reruns are pending; original loader and timeout failures remain retained. Evidence: `optimization-stage-13/native-current-windows-v3/loopback-report.json` and `frame-ws-test-deadline/`.
-
-The Windows Tauri test-only v4 rerun subsequently passed all eight formerly failing cases individually and all 445 library tests in the full suite, with only binding generation filtered. Combined with the 529 shared tests, this is 974 unique Windows library passes; the eight canonical video comparisons and 2,883,584 PCM EOF frames are separate integration evidence. All 2,331 source hashes in the frozen shared/Tauri v4 scope remained exact. This scope does not include the later GPUI Main-frame candidate, whose native checks are separate. No production behavior or assertion condition was changed to obtain this result.
-
-The exact GPUI Main-frame module passed a disposable native Windows test covering already-hidden and visible installation, duplicate installation, wrong-thread rejection, minimize/restore/maximize/move/resize, outer/client rectangle and style parity, forwarded message results/last-error state, and subclass removal before forwarding destruction. Explicit `SW_SHOWNORMAL` and `SWP_NOSENDCHANGING` cases confirmed restoration before underlying show handling. The initial standalone executable lacked Common Controls activation and failed before `main`; the retained v2 used the exact existing GPUI application manifest, compiled without diagnostics and passed. The production GPUI dependency already enables that manifest, so no application manifest change is required. Actual GPUI recording/Stop testing of this exact module is the next gate. Evidence: `optimization-stage-13/windows-hidden-frame-harness-v2/native-smoke-v2/`.
-
-The first actual GPUI recording with the exact Main-frame module passed the previously failing Stop transition. Installation occurred while Main was visible, before recording hid it and before the existing Stop affinity calls. The temporary installation hook was removed before capture. The 28.185-second recording opened a correctly colored editor with no Main outline in either the immediate image or the pure settled desktop capture; a later observation remained clear after three minutes. Direct native measurements kept the original outer rectangle `[339,164,685,605]`, client rectangle `[347,165,677,597]`, caption and extended style bits, while the hidden noniconic Main reported nonclient rendering disabled. Closing the editor restored a normally framed visible Main. The launcher’s first attempt failed on a PowerShell argument cast before sending any installation command; that failure and successful cleanup were retained before correction. This is a native app diagnostic using the earlier GPUI executable plus the exact new module, not a rebuilt current-controller app. Further lifecycle and current-app build verification remain pending. Evidence: `optimization-stage-13/windows-hidden-frame-harness-v2/native-gpui-v1/`; screenshots: `optimization-stage-12/windows-native-ui/gpui-input-HiddenFrame07-desktop.png` and `pure-capture-HiddenFrameSettled01-desktop.png`.
-
-## Main-frame lifecycle and remaining audio readiness work
-
-The exact Windows Main-frame module passed a second genuine manual Stop after editor reopen, compact/expanded layout changes, minimize/restore, caption movement and a System-to-Dark-to-System theme round trip. Both the immediate and 55-second settled repeat screenshots remained free of the Main outline. Visible framing, styles, outer/client bounds and normal restoration were preserved. The two task-owned recordings contain 1,691 and 1,412 independently decoded video frames with no FFprobe failure. They were screen-only recordings, so this is window lifecycle and recording-integrity evidence, not A/V or progressive-playback proof. The owned GPUI process exited normally, removing the diagnostic module. Actual Main fullscreen behavior remains untested; the compact/expanded button is a layout toggle. Full receipts are under `optimization-stage-13/windows-hidden-frame-harness-v2/ASSESSMENT.txt`.
-
-The audio goal audit found two separate constraints. GPUI had required an absent timing log and zero timing repairs, whereas the ordinary editor and Tauri accept valid timing data. GPUI now uses the same bounded regular-file/UTF-8/4-MiB log snapshot reader as Tauri and derives ordinary repairs from expected finalized metadata. Existing source paths, preserved AAC/container checks, cancellation and required-track semantics are unchanged. Scoped format/check and six native focused tests pass. The copied log reader is byte-identical to Tauri. Tests cover missing/valid/invalid logs, nonzero timing repairs, immutable snapshots and symlink refusal; no actual early-play app handoff is claimed. Evidence: `optimization-stage-13/gpui-audio-timing-admission/assessment.json`.
-
-The larger remaining constraint is in the shared playback controller: each required audio track must reach successful decoded EOF before its entire clip is admitted. A two-hour clip therefore cannot currently reveal a within-clip playable prefix. The initial video image is independent of that audio gate. The ordinary loader discards an audio track on a later decode error; earlier valid samples cannot be unheard, so partial playback must retain explicit failure handling rather than pretend the tail was validated. Neither a file hash nor packet-only preflight proves complete audio decoding. The full source audit and actual-app evidence boundaries are retained under `optimization-stage-13/preparing-audio-goal-audit/`.
-
-A bounded input API is now prepared in `cap-audio`: a nonblocking window read distinguishes pending samples, known absence, successful completed audio and errors. Pending windows report only the source-frame range they actually retain; they never claim EOF or advertise additional uncopied blocks as playable. PCM blocks are shared by Arc, and the ordinary full-track decoder/result path is unchanged. A separate review caught and corrected a race between successful result publication and sender closure. Tests exercise publication, dropped/error producers, short tails, empty/large ranges, exact sample mixing across block boundaries, and retained-block ownership. The reviewed API passed macOS formatting, scoped Cargo check, strict scoped Clippy and 69 default library tests. The separately requested matched 60-second fixture EOF test also passed, giving 70 unique audio test passes; its original 1,230,339-byte input SHA remained unchanged. Those are function checks, not Stop-to-editor benchmarks or Linux/Windows validation of this latest delta. Evidence: `optimization-stage-13/preparing-audio-windows-v1/assessment.json`. This remains input-side groundwork: the production playback controller still uses its completed-audio gate. Connecting a bounded output producer, deriving readiness from genuinely rendered output, preserving the output resampler across growth and proving the actual playing handoff are outstanding.
-
-Current Windows app compilation is held until this shared audio scope settles, to avoid rebuilding stale sources. The exact validated frontend assets and both app build plans are retained. The old Windows function VM is stopped. The Tauri build plan uses an explicitly documented isolated output-type-only manifest adjustment to avoid redundant static/CDylib artifacts in the constrained VM; that debug UI proof will not establish packaged-release or performance equivalence. No recording source, accepted fixture or application manifest in the shared checkout was changed for capacity preparation.
-
-One scoped unchanged-CLI diagnostic under ProcDump produced a valid full-color 1,168-by-702 JPEG and an observed CLI process exit code of zero. No unhandled exception dump was produced. Two first-chance COM exceptions were handled during the known Media Foundation-to-FFmpeg fallback. The executable, source project and intended adjacent shader DLL hashes were unchanged. This single non-reproduction does not resolve the previously intermittent exit-time access violation, and no crash stack or live module inventory was captured. An earlier attempt failed before rendering because ProcDump changed JSON argument quoting; an argv-only probe established the corrected transport before this run. Both attempts remain retained under `optimization-stage-12/windows-native-ui/cli-unhandled-dump-v1/` and `cli-unhandled-dump-v2/`.
-
-## Partial audio playback integration
-
-The shared preparing controller now admits a growing audio prefix within a single recording clip. A separate mixer checks every required source range before producing samples, retains ordinary calibrated offsets, timing repairs, gain and stereo mixing, and permits trailing silence only after successful EOF. Its output producer preserves the resampler across pending input and uses a bounded two-second ring. Ordinary editor mixing and output-buffer selection remain unchanged. Tests compare nonzero output samples with the ordinary path at 44.1 and 48 kHz, across channel layouts, sample formats, fractional seeks, preroll and the long-recording output mode.
-
-The callback starts with a zero consumption allowance. The controller installs the combined audio/video playable prefix before playback and grows that allowance on the same source generation. Unavailable samples produce hardware silence without advancing the media clock or acknowledging playback. Timestamped consumed spans account for queued latency and starvation; video follows the reported audible position. The last displayed image and its snapshot position remain separate from that live clock. One headless test starts before synthetic EOF, consumes exactly 4,800 frames under the initial prefix, verifies silent callbacks while held, then compares all 70,000 frames after growth without replacing the source. This is real output-control and callback execution using synthetic decoded input, not a new capture benchmark.
-
-Independent review corrected failed-stream retirement, post-spawn error ownership, initial latency pre-skipping and cleanup ownership after a timeout. A failed device stream is retired on the control thread because a stopped callback cannot process a removal command. Healthy streams retain generation-specific removal so a stale preparing request cannot stop an ordinary replacement. Output cleanup observes both actual producer-thread completion and callback-source removal. The controller retains its ticket until cleanup succeeds. Test-only construction errors and a weak silence-only long-mode fixture were corrected; failed attempts remain in the evidence.
-
-The final partial-audio snapshot before the successful-publication handoff passed 143 macOS Rust 1.88.0 editor tests after the cleanup ownership correction. The audio suite passed 69 default tests, and the separately requested matched 60-second native AAC fixture passed comparison through decoded EOF. Its original 1,230,339-byte SHA remains `05f898aca4373a8678a3487766858e2a97cdcdd72d101f54a6980440460da808`. Formatting, scoped compilation and strict Clippy for both libraries and their tests passed. Repeated and overlapping focused suites are not additional unique passes. Receipts and before/after source manifests are under `optimization-stage-13/preparing-audio-output-v1/`; independent reviews are under `preparing-audio-stream-retirement/` and `preparing-partial-audio-clock/`.
-
-Those partial-audio checks did not establish native application Stop-to-first-audible timing, Windows/Linux parity or uninterrupted ordinary-editor handoff. In that snapshot, an incomplete managed source was cancelled/joined and decoded again by ordinary loading; only completed tracks crossed the cache boundary. That implementation limitation motivated the successful-publication handoff below. Device-buffered audio cannot be retracted merely by removing a callback source. Windows retains its existing zero-latency estimate; the pinned CPAL WASAPI playback timestamp is not sufficient evidence for changing that policy. Physical endpoint/loopback timing and actual application presentation remain separate from function-test coverage.
-
-## Successful-publication playback handoff
-
-The final candidate records successful publication without reopening source admission: the observer still ends and rejects new leases. A controller that was already admitted for the same successful job can keep its existing readers and audio output alive while preparation finishes and ordinary loading reuses completed PCM. Recovery-lock ownership stays with the original readers until actual cleanup joins release them. Failure, close and supersession continue to stop and join owned work.
-
-The ordinary candidate commits adoption only against a matching presented frame and current playback intent. It then follows the existing consumed-audio clock and audio generation. Pause or seek can invalidate and replace a pending candidate, and cleanup of an uncommitted or stale candidate cannot shut down its predecessor or successor. Existing explicit ordinary pause/seek/restart paths stop and join the adopted owner before installing a replacement source.
-
-The GPUI v4 callback also permits new frames from the already-admitted, same-job preparing session after successful publication; failure, cancellation and supersession still reject delivery. Its added admission regression test is included in the three GPUI v4 suites.
-
-The macOS editor suite below includes native fixture and headless output tests for PCM reuse, candidate disposal, moving-frame handoff, cancellation and panic completion. These tests do not measure a physical audio endpoint or prove that a real application window presents an uninterrupted, aligned audio/image transition.
-
-## Current automated verification before manual testing
-
-The rows below distinguish completed native test scopes from checks left unrun when the user ended automated testing and requested PR publication. GPUI uses the matching v4 source on macOS, Linux and Windows. Root Rust inputs are unchanged across the v2–v4 source manifests; subsequent deltas are the GPUI fixes and generated Tauri bindings. The older three-platform table remains historical evidence and is not added to these counts.
-
-| Scope                               | Result                                      | Qualification                                                                                                                                                          |
-| ----------------------------------- | ------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| macOS editor library                | 161 passed                                  | Native handoff and headless audio ownership tests included                                                                                                             |
-| macOS recording/recovery            | 597 passed                                  | 535 library, 12 real-subprocess muxer and 50 recovery integration tests; three library ignores and one external-fixture integration ignore                             |
-| macOS Tauri                         | 470 passed, plus one binding-generator test | Generated bindings were then used by frontend validation                                                                                                               |
-| macOS GPUI v4                       | 993 passed                                  | Two existing picker/screenshot benchmark tests ignored; all-target compilation passed                                                                                  |
-| Linux GPUI v4                       | 1,052 passed                                | Two existing ignores; native compilation and source/runtime/binary integrity checks passed                                                                             |
-| Windows GPUI v4                     | 970 passed                                  | Two existing ignores; native compilation and source/runtime/binary integrity checks passed                                                                             |
-| Desktop frontend                    | 473 passed in 47 files                      | Final generated bindings included; TypeScript passed                                                                                                                   |
-| Web frontend                        | 3,047 passed, 28 skipped                    | 219 passing test files and six skipped files; TypeScript passed                                                                                                        |
-| Tooling                             | 64 passed                                   | Separate function-test scope                                                                                                                                           |
-| Linux root libraries                | Listed suites passed                        | Audio 69, editor 160, encoder 150, video decoder eight, project 130, rendering 244, recording 690, export 32 and muxer protocol seven                                  |
-| Linux integration follow-up         | Enabled requested scopes passed             | Real muxer/OOP, recovery, sync, pipeline, rendering and synthetic scopes passed; three explicit GPU correctness tests and the separate 60-second audio EOF case passed |
-| Windows shared libraries            | 1,314 passed                                | Audio 73, editor 159, encoder 138, decoder 11, project 129, rendering 244, recording 530 and export 30; nine default-suite ignores                                     |
-| Linux Tauri library                 | 530 passed                                  | Binding writer filtered; native library/bin check and strict library/test/bin Clippy passed                                                                            |
-| Linux Tauri main binary             | Six passed                                  | Exact main source and 107 unchanged dependency artifacts; direct compiler invocation after ordinary Cargo staticlib packaging exhausted disk                           |
-| Linux canonical follow-up           | Three executions passed                     | 15-/60-second recording scenarios plus the separate audio EOF case; this repeats the earlier audio EOF test and is not three additional unique unit tests              |
-| Windows remaining root/Tauri scopes | **Not run; testing stopped**                | Protocol check passed; protocol tests, Tauri, muxer, integrations, explicit GPU, canonical, hardware and remaining strict gates are incomplete                         |
-
-The final macOS editor and Tauri all-target strict Clippy gate passed, as did recording library/test strict Clippy. Strict GPUI Clippy did **not** pass on any of the three platforms. macOS v4 emitted 28 diagnostic blocks representing 27 distinct primary spans, including one repeated crop diagnostic. All 27 match v3; three additional unchanged `editor_frame0` spans from the v3 JSON were not emitted in the v4 text and are not classified as resolved. Linux emitted 23 errors and Windows 28. Every emitted primary excerpt and surrounding context was verified unchanged against HEAD and the initial adopted source. Linux's platform-specific `explicit_auto_deref` and Windows' `infallible_destructuring_match` also match that baseline. No new diagnostic context was found, and no suppression was added. Passing tests and compilation do not convert these strict-lint failures into green gates. Linux export strict Clippy also retains two test-only baseline diagnostics: an irrefutable `let` pattern on Linux and `field_reassign_with_default`. Their entire source files match HEAD and the initial adopted snapshot. No later strict export pass supersedes that receipt.
-
-The Linux integration follow-up passed nine muxer unit tests, 12 OOP tests, 50 recovery integrations, four sync tests, 61 instant-mode scenarios, five segmented-pipeline tests, two rendering integration tests and 28 synthetic tests. Three offscreen GPU tests and one audio EOF case were executed separately from their default suites. Empty platform targets, hardware exclusions and external-fixture/benchmark ignores are not counted as executed tests. The follow-up initially stopped on an unsuccessful 15-second canonical finalization probe (`exit 101`). A fresh native lane subsequently passed both the 15- and 60-second canonical recording scenarios and repeated the audio EOF test using the exact retained current binaries. Original fixtures, sources, native inputs and executable hashes remained unchanged. The first failed attempt remains evidence; the later result establishes successful retry execution, without claiming a cause for the first failure or complete seek-frame coverage from the summary alone. The repeated audio case is not an additional unique pass. Windows remaining root and Tauri scopes were not run before the user stopped further testing.
-
-Linux Tauri has 536 executed function-test passes in total: 530 from its normal Cargo-built library harness and six from the main-binary harness. The ordinary Cargo binary-test build failed while creating `libcap_desktop_lib.a` with `ENOSPC`. The six main tests then passed using a reconstructed direct Rust 1.88 invocation, the exact main source and 107 unchanged dependency artifacts, including the completed ordinary Rust library output. No source or Cargo manifest was changed. Strict Tauri Clippy subsequently passed for library, tests and binary targets. This closes those function-test scopes; the ordinary static-library packaging build remains failed and is not relabelled as a successful standard Cargo or release-package build.
-
-The Windows shared-library total comprises 232 unchanged-source passes inherited from the preceding VM (audio 73 and editor 159) and 1,082 newly executed passes (encoder 138, video decoder 11, project 129, rendering 244, recording 530 and export 30). The inherited suites were not rerun or counted twice. Their strict audio/editor gates had passed. The new protocol compilation check passed, but its test build did not start: the lane stopped at the 1.6-GB preflight with 1,581,453,312 bytes free. The remaining protocol tests, Tauri, muxer, integrations, explicit GPU correctness cases, canonical fixtures, hardware cases and remaining strict Clippy gates were not run for this final scope. The user then explicitly ended testing; older successful runs do not fill these gaps. Source, runtime, fixture and executable integrity checks passed at the stop. All eight executables and 50 logs are retained; the overall shared-phase receipt remains `passed: false` because the requested phase was incomplete.
-
-The earlier empty-output muxer crashes and filesystem-sensitive recovery failure retain their original failure evidence. Their focused Linux/Windows fix snapshots are historical; the current Linux recording library and real OOP/recovery results above provide later matching-root-source coverage. Current Windows recording-library passes do not complete the unrun real-helper/integration scopes; the older 27-test fix snapshot remains qualified historical evidence.
-
-Counts describe their listed scopes, not globally unique tests across operating systems. Earlier editor runs, focused frontend subsets, previous platform totals and repeated retries are not additional passes. Canonical 15-/60-second fixture scenarios remain separate from unit counts. No final-candidate physical audio-endpoint timing, continuous handoff UI test, new capture benchmark or expanded two-hour run is claimed. Manual testing should use a fresh candidate and include playback while preparation finishes, seeking, pausing and closing/reopening the editor.
-
-Current receipts are under `.git/codex-build/session-support/01a08773-a817-7de1-988e-ab9078f33c12/`: `macos-final-editor-v2-tests`, `macos-final-recording-tests`, `macos-final-tauri-tests`, `macos-final-tauri-bindings`, `macos-final-gpui-tests-v4`, their check/Clippy results, `gpui-clippy-v4-baseline-comparison.json`, `gpui-v4-platform-clippy-triage-v1/assessment.json`, `final-source-v2/linux-root-progress.json`, the captured `resume-progress-v1/{linux-root,linux-root-latest,windows-root-latest,linux-tauri-latest}.json` receipts, `linux-tauri-replacement-v1/linux-tauri-canonical-v1-latest.json`, `linux-tauri-main-test-v1/{progress,clippy-progress}.json`, `linux-tauri-bin-triage-v1/assessment.json`, `linux-export-clippy-triage-v1/assessment.json`, `windows-root-replacement-v1/shared-progress.json`, `windows-shared-retained-v1/receipt.json`, `windows-inherited-root-retained-v1/receipt.json`, `desktop-tests-final-bindings-v1.log`, `web-tests-postreview.log`, `tooling-tests.log`, and the final frontend typecheck logs. Interpret mutable polling filenames using the hashes retained with this report candidate. Further platform testing was stopped at the user’s request. Active test sandboxes were stopped and task resource removal was requested after local evidence retention. Three older restore requests rejected stop/delete because the provider reports a state change in progress; cleanup remains qualified until those requests are cleared. Receipts are in `final-sandbox-shutdown-v2/` and `final-sandbox-cleanup-v1/`; the earlier stopped-sandbox statement applies only to its historical run.
-
-### Earlier partial-audio verification snapshot, September 10
-
-In the earlier frozen partial-audio snapshot, the enabled app suites passed on all three operating systems. That broader run was not all green; its failures motivated the later fixes:
-
-| Platform |                     Tauri app suite | GPUI app suite | Broader native results                                               |
-| -------- | ----------------------------------: | -------------: | -------------------------------------------------------------------- |
-| macOS    | 468 passed, plus binding generation |     992 passed | 2,854 passed, zero failures                                          |
-| Windows  |                          445 passed |     969 passed | 2,880 reported passes, three empty-output muxer failures             |
-| Linux    |                          528 passed |   1,051 passed | 3,099 passed on the normal filesystem, four failures described below |
-
-Counts are per platform and selected native suites, not globally unique tests across operating systems. Repeated checks are not additional passes. Windows' reported passes include one loopback test that returned early because no output device existed; this is not physical loopback proof. Two canonical recording scenarios per operating system are recorded separately from the table. The explicitly requested ignored audio-EOF test is included once in each native total. Manual device, benchmark and external-fixture ignores remain documented in the individual receipts.
-
-That verification-only phase changed no production source or test assertions. The common 2,337-input source archive has SHA-256 `7f82cd885259e9100e1fa32e5a54ab2597015e21029bf99d6c78029c97d1794d`; its manifest has SHA-256 `4a5b7ebb67f54e6e22678488a9592d6fc51f6953cdd42f36de199baf31021e4a`. macOS additionally requires 24 platform-specific source files, and both app test setups require two exact committed MP4 fixtures. The Windows root-workspace source manifest differs only in GPUI-specific files, which the separate Windows GPUI gate for that snapshot covered. Later unrelated sharing/reupload and development-launcher edits in the shared checkout are excluded. These results apply only to that frozen candidate. The subsequent combined build adopts additional sharing/reupload and launcher changes as well as the recovery, muxer and handoff fixes.
-
-The desktop frontend passed all 460 tests across 47 files, TypeScript compilation and Biome on all 40 frozen touched frontend files. Another 28 packaging-function tests passed on macOS; they are not native Linux execution. Scoped native compilation and formatting passed. Strict editor/audio library-and-test Clippy passed on all three platforms. Linux Tauri strict Clippy in that earlier snapshot reported three existing findings in unchanged `upload.rs`: unused `SegmentUploader::spawn`, unused `Control::complete`, and a redundant `Bytes` conversion. The binding-writing test was filtered on Windows/Linux and explicitly executed on the isolated macOS copy; generated bindings were byte-identical.
-
-Both preserved 15- and 60-second `.cap` fixtures were replayed on every platform. macOS and Windows observed all eight requested video frames and matched their independent ordinary-finalized references exactly. Linux observed five of eight requests before finalization ended the preparing session; every observed frame matched, but three cancelled requests are not frame-equivalence coverage. All three platforms matched every one of the 2,883,584 decoded audio frames through EOF on the 60-second fixture. Source, published-media, normalized-document, lock and worker-join checks passed. Original fixture hashes stayed unchanged. These are functional comparisons, not display-latency or audible-endpoint measurements.
-
-The three OOP muxer failures in that earlier Windows/Linux run were `respawning_subprocess_reports_clean_exit_when_no_crash`, `subprocess_spawns_and_finishes_cleanly_without_packets`, and `subprocess_survives_finish_after_init_only`. Actual packet-producing muxer tests passed in that run. The helper, protocol, calling OOP module, integration tests and all 89 transitive helper lock entries matched HEAD `284ae24a79bd0813743f51e6219d11ae0042d38f` before the later fix. The standalone Windows initialize/start/finish replay with no packets also crashed before the fix. Its minidump places exception `0xC0000094` inside the loaded `avformat-61.dll` at offset `0x4c8f2`. Native disassembly divides the byte-position-derived numerator by zero immediately before formatting representation bandwidth, matching FFmpeg 7.1's unguarded final DASH bitrate calculation ([pinned source](https://github.com/FFmpeg/FFmpeg/blob/n7.1/libavformat/dashenc.c#L834)). The small dump omits the divisor's heap page and has no complete symbolized internal stack; zero numerator registers rule out quotient overflow. Linux's Rust wrapper reports a non-successful child exit without retaining the signal. macOS passes all nine OOP tests with an ARM64 helper loading FFmpeg 7.1 / libavformat 61.7.100; that does not clear the failing x86 platform cases. No trailer, bitrate, library or assertion was changed during that diagnostic phase. The subsequent reviewed helper fix and added regression tests have their own passing native receipts above.
-
-The fourth failure in that earlier normal-filesystem Linux run was `recovery::transactional_recovery_tests::interrupted_rollback_reconciles_and_relaunches_at_every_rename_boundary`. That library suite reported 685 passes and one failure on the sandbox root filesystem. On tmpfs, that rollback test passes, while two executable-launch tests fail because the mount is noexec. Across these controls, 686 distinct recording-library tests pass, making 3,100 distinct passing names across all documented Linux filesystem scopes; this union is not a green normal-filesystem run. The retained older executable and current executable each reproduce the root-filesystem failure in all three alternating runs. Before the fix, the stamp, reconciliation function and failing test matched HEAD. A separate four-rename diagnostic reproduced directory size changing from 42 to 54 bytes without content or timestamp changes on rootfs; tmpfs remained stable. This supports an existing filesystem-sensitive guard but does not capture the exact differing field in the failed journal. No receipt format or recovery validation was changed during that diagnostic phase. The later guarded stamp fix was independently tested on the normal filesystem, as recorded above.
-
-Setup corrections are retained separately from product failures. Windows hardware compatibility passed its complete 13-test enabled suite in the existing Administrator desktop session, with seven hardware-specific ignores; the original SYSTEM/session-0 capture-support failure remains in the logs. Linux GPUI passed one complete 1,051-test invocation using the original Cargo test executable name and a stable, task-owned Xvfb display. Initial display/reset and renamed-executable failures are retained. The virtual display was stopped afterward; no application UI or screenshots were produced. Three explicitly executed offscreen GPU correctness tests passed per platform; Windows used WARP and Linux used llvmpipe, so this does not establish physical-GPU coverage. Linux's final 32-test export suite passed with the frozen root Rust 1.88 graph and unchanged source/lock, after downloading one already-pinned development dependency.
-
-That snapshot supplied source-bound regression evidence and concrete failures, not packaged-release clearance or a no-regressions guarantee. The final candidate now implements the successful-publication handoff, but its physical audible transition and application presentation remain unverified.
-
-Receipts live under `optimization-stage-13/current-macos-automated-v2/`, `native-partial-audio-windows-v1/extended-assessment.json`, `windows-gpui-automated-v1/`, `partial-audio-linux-v1/`, `partial-audio-gpui-linux-v1/`, `windows-integration-failure-audit/`, and `current-frontend-tests/`. Sources, original media, exact native executables, failed attempts and diagnostic evidence are retained.
-
-All four sandboxes used for that historical test run were stopped normally after evidence verification. The older sandbox with a pending restore remains archived with a requested start; its 60-minute idle-stop and auto-archive policies were verified, and auto-delete is disabled. That receipt recorded no remaining test process at the time; it is not a current operational-state claim. The consolidated historical receipt is `optimization-stage-13/automated-test-handoff-final.json`.
diff --git a/apps/desktop/src-tauri/.gitignore b/apps/desktop/src-tauri/.gitignore
deleted file mode 100644
index b21bd681d99..00000000000
--- a/apps/desktop/src-tauri/.gitignore
+++ /dev/null
@@ -1,7 +0,0 @@
-# Generated by Cargo
-# will have compiled files and executables
-/target/
-
-# Generated by Tauri
-# will have schema files for capabilities auto-completion
-/gen/schemas
diff --git a/apps/desktop/src-tauri/Cargo.toml b/apps/desktop/src-tauri/Cargo.toml
deleted file mode 100644
index 5aff2e93396..00000000000
--- a/apps/desktop/src-tauri/Cargo.toml
+++ /dev/null
@@ -1,196 +0,0 @@
-[package]
-name = "cap-desktop"
-version = "0.6.2"
-description = "Beautiful screen recordings, owned by you."
-authors = ["you"]
-edition = "2024"
-
-[lints]
-workspace = true
-
-[lib]
-name = "cap_desktop_lib"
-crate-type = ["lib", "cdylib", "staticlib"]
-
-[build-dependencies]
-tauri-build = { version = "2.1.0", features = [] }
-
-[target.'cfg(target_os = "macos")'.build-dependencies]
-swift-rs = { version = "1.0.6", features = ["build"] }
-
-[dependencies]
-tauri = { workspace = true, features = [
-    "macos-private-api",
-    "protocol-asset",
-    "tray-icon",
-    "image-png",
-] }
-tauri-specta = { version = "=2.0.0-rc.20", features = ["derive", "typescript"] }
-tauri-plugin-dialog = "2.2.0"
-tauri-plugin-fs = "2.2.0"
-tauri-plugin-global-shortcut = "2.2.0"
-tauri-plugin-http = "=2.5.2"
-tauri-plugin-notification = "2.2.0"
-tauri-plugin-os = "2.2.0"
-tauri-plugin-process = "2.2.0"
-tauri-plugin-shell = "2.2.0"
-tauri-plugin-single-instance = { version = "2.2.0", features = ["deep-link"] }
-tauri-plugin-store = "2.2.0"
-tauri-plugin-updater = "2.9.0"
-tauri-plugin-oauth = { git = "https://github.com/FabianLars/tauri-plugin-oauth", branch = "v2" }
-tauri-plugin-window-state = "2.2.0"
-tauri-plugin-positioner = "2.2.0"
-tauri-plugin-deep-link = "2.2.0"
-tauri-plugin-clipboard-manager = "2.2.1"
-tauri-plugin-opener = "2.2.6"
-
-serde = { workspace = true }
-serde_json = "1.0.111"
-specta.workspace = true
-specta-typescript = "0.0.7"
-tokio = { workspace = true, features = ["signal"] }
-uuid = { version = "1.10.0", features = ["v4"] }
-image = { version = "0.25.2", default-features = false, features = ["rayon", "bmp", "dds", "exr", "ff", "gif", "hdr", "ico", "jpeg", "png", "pnm", "qoi", "tga", "tiff", "webp"] }
-futures-intrusive = "0.5.0"
-anyhow.workspace = true
-futures = { workspace = true }
-axum = { version = "0.8.9", features = ["ws", "macros"] }
-tracing.workspace = true
-tempfile = "3.9.0"
-ffmpeg.workspace = true
-chrono = { version = "0.4.31", features = ["serde"] }
-regex = "1.10.4"
-rodio = "0.19.0"
-png = "0.17.13"
-device_query = "4.0.1"
-base64 = "0.22.1"
-reqwest = { version = "0.12.24", features = ["json", "stream", "multipart"] }
-dotenvy_macro = "0.15.7"
-global-hotkey = "0.7.0"
-rand = "0.8.5"
-cpal.workspace = true
-keyed_priority_queue = "0.4.2"
-sentry.workspace = true
-clipboard-rs = "0.2.2"
-whisper-rs = "0.11.0"
-lazy_static = "1.4.0"
-log = "0.4.20"
-semver = "1"
-
-cap-audio = { path = "../../../crates/audio" }
-cap-camera = { path = "../../../crates/camera", features = ["serde", "specta"] }
-cap-camera-effects = { path = "../../../crates/camera-effects" }
-cap-utils = { path = "../../../crates/utils" }
-cap-project = { path = "../../../crates/project" }
-cap-rendering = { path = "../../../crates/rendering" }
-cap-editor = { path = "../../../crates/editor" }
-cap-media = { path = "../../../crates/media" }
-cap-flags = { path = "../../../crates/flags" }
-cap-recording = { path = "../../../crates/recording" }
-cap-timestamp = { path = "../../../crates/timestamp" }
-cap-export = { path = "../../../crates/export" }
-cap-automation = { path = "../../../crates/automation" }
-cap-cli-install = { path = "../../../crates/cli-install", features = ["specta"] }
-cap-enc-ffmpeg = { path = "../../../crates/enc-ffmpeg" }
-cap-media-info = { path = "../../../crates/media-info" }
-scap-targets = { path = "../../../crates/scap-targets" }
-scap-screencapturekit = { path = "../../../crates/scap-screencapturekit" }
-scap-direct3d = { path = "../../../crates/scap-direct3d" }
-
-flume.workspace = true
-tracing-subscriber = "0.3.19"
-tracing-appender = "0.2.3"
-dirs = "6.0.0"
-relative-path = "1.9.3"
-cap-fail = { version = "0.1.0", path = "../../../crates/fail" }
-tokio-stream = { version = "0.1.17", features = ["sync"] }
-md5 = "0.7.0"
-tokio-util = "0.7.15"
-tokio-tungstenite = "=0.24.0"
-wgpu.workspace = true
-pollster = "0.4"
-bytemuck = "1.23.1"
-kameo = "0.17.2"
-tauri-plugin-sentry = "0.5.0"
-thiserror.workspace = true
-bytes = "1.10.1"
-async-stream = "0.3.6"
-lz4_flex = "0.11"
-sanitize-filename = "0.6.0"
-tracing-futures = { version = "0.2.5", features = ["futures-03"] }
-tracing-opentelemetry = "0.32.0"
-opentelemetry = "0.31.0"
-opentelemetry-otlp = "0.31.0"                                                 #{ version = , features = ["http-proto", "reqwest-client"] }
-opentelemetry_sdk = { version = "0.31.0", features = ["rt-tokio", "trace"] }
-sysinfo = "0.35"
-workspace-hack = { version = "0.1", path = "../../../crates/workspace-hack" }
-aho-corasick.workspace = true
-
-
-[target.'cfg(target_os = "macos")'.dependencies]
-block2 = "0.6.1"
-core-graphics = "0.24.0"
-core-foundation = "0.10.0"
-objc2-app-kit = { version = "0.3.0", features = [
-    "NSWindow",
-    "NSResponder",
-    "NSHapticFeedback",
-    "NSWorkspace",
-    "NSRunningApplication",
-] }
-objc2 = "0.6.0"
-objc2-foundation = { version = "0.3.0", features = [
-    "NSNotification",
-    "NSString",
-    "NSThread",
-] }
-cocoa = "0.26.0"
-objc = "0.2.7"
-swift-rs = "1.0.6"
-tauri-nspanel = { git = "https://github.com/ahkohd/tauri-nspanel", branch = "v2" }
-cidre = { workspace = true }
-cap-camera-ffmpeg = { path = "../../../crates/camera-ffmpeg" }
-
-[target.'cfg(not(all(target_os = "macos", target_arch = "x86_64")))'.dependencies]
-parakeet-rs = "0.3.4"
-
-[target.'cfg(target_os = "linux")'.dependencies]
-libappindicator = "0.9.0"
-gtk = "0.18"
-gdkwayland-sys = "0.18.2"
-wayland-sys = { version = "0.31.7", features = ["client", "dlopen"] }
-ashpd = { version = "0.11.0", default-features = false, features = ["tokio"] }
-notify-rust = "4.11"
-
-[target.'cfg(target_os= "windows")'.dependencies]
-windows = { workspace = true, features = [
-    "Foundation",
-    "Foundation_Collections",
-    "Globalization",
-    "Graphics_Imaging",
-    "Media_Ocr",
-    "Storage_Streams",
-    "Win32_Foundation",
-    "Win32_System",
-    "Win32_Storage_FileSystem",
-    "Win32_System_Power",
-    "Win32_System_Threading",
-    "Win32_System_WinRT",
-    "Win32_UI_WindowsAndMessaging",
-    "Win32_Graphics_Gdi",
-] }
-windows-sys = { workspace = true }
-winreg = "0.55"
-webview2-com = "0.38.0"
-windows-core = "0.61.2"
-
-[target.'cfg(unix)'.dependencies]
-nix = { version = "0.29.0", features = ["fs"] }
-
-[dev-dependencies]
-tauri = { workspace = true, features = ["test"] }
-wgpu = { workspace = true, features = ["noop"] }
-
-[[test]]
-name = "gpu_device_health"
-path = "src/gpu_device_health.rs"
diff --git a/apps/desktop/src-tauri/Info.plist b/apps/desktop/src-tauri/Info.plist
deleted file mode 100644
index dd740dcf952..00000000000
--- a/apps/desktop/src-tauri/Info.plist
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-	CFBundleDocumentTypes
-	
-		
-			CFBundleTypeExtensions
-			
-				cap
-			
-			CFBundleTypeIconFile
-			icon.icns
-			CFBundleTypeName
-			Cap Recording
-			CFBundleTypeRole
-			Editor
-			LSHandlerRank
-			Default
-			LSTypeIsPackage
-			
-		
-	
-	NSCameraUsageDescription
-	Cap uses your camera to record you in your Caps
-	NSMicrophoneUsageDescription
-	Cap uses your microphone to record you in your Caps
-	NSScreenCaptureUsageDescription
-	Cap captures your screen as part of recording your Caps
-	NSCameraUseContinuityCameraDeviceType
-	
-
-
diff --git a/apps/desktop/src-tauri/assets/wix-banner.bmp b/apps/desktop/src-tauri/assets/wix-banner.bmp
deleted file mode 100644
index 3fcc7467861..00000000000
Binary files a/apps/desktop/src-tauri/assets/wix-banner.bmp and /dev/null differ
diff --git a/apps/desktop/src-tauri/assets/wix-dialog.bmp b/apps/desktop/src-tauri/assets/wix-dialog.bmp
deleted file mode 100644
index 36625dc9f46..00000000000
Binary files a/apps/desktop/src-tauri/assets/wix-dialog.bmp and /dev/null differ
diff --git a/apps/desktop/src-tauri/build.rs b/apps/desktop/src-tauri/build.rs
deleted file mode 100644
index b76325a59e7..00000000000
--- a/apps/desktop/src-tauri/build.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-#[path = "../../../scripts/diagnostic-build.rs"]
-mod diagnostic_build;
-
-fn main() {
-    diagnostic_build::emit();
-    if std::env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("windows")
-        && std::env::var("CARGO_CFG_TARGET_ENV").as_deref() == Ok("msvc")
-    {
-        // Export preview command dispatch can exhaust the default 1 MiB UI stack before reaching a Tokio worker.
-        println!("cargo:rustc-link-arg-bin=cap-desktop=/STACK:16777216");
-    }
-    tauri_build::build();
-}
diff --git a/apps/desktop/src-tauri/capabilities/default.json b/apps/desktop/src-tauri/capabilities/default.json
deleted file mode 100644
index 3c4d5646057..00000000000
--- a/apps/desktop/src-tauri/capabilities/default.json
+++ /dev/null
@@ -1,73 +0,0 @@
-{
-	"$schema": "../gen/schemas/desktop-schema.json",
-	"identifier": "default",
-	"description": "Capability for the main window",
-	"windows": ["*"],
-	"permissions": [
-		"fs:default",
-		"fs:allow-resource-read",
-		"fs:allow-resource-read-recursive",
-		"fs:write-all",
-		"fs:read-all",
-		"fs:allow-appdata-read",
-		"fs:allow-appdata-write",
-		"fs:allow-picture-read-recursive",
-		{
-			"identifier": "fs:scope",
-			"allow": [
-				{ "path": "$APPDATA/**" },
-				{ "path": "$HOME/**" },
-				{ "path": "$RESOURCE/**" }
-			]
-		},
-		"core:path:allow-resolve-directory",
-		"core:path:default",
-		"core:event:default",
-		"core:menu:default",
-		"core:resources:allow-close",
-		"core:window:default",
-		"core:window:allow-close",
-		"core:window:allow-destroy",
-		"core:window:allow-hide",
-		"core:window:allow-show",
-		"core:window:allow-center",
-		"core:window:allow-minimize",
-		"core:window:allow-unminimize",
-		"core:window:allow-maximize",
-		"core:window:allow-unmaximize",
-		"core:window:allow-set-size",
-		"core:window:allow-set-focus",
-		"core:window:allow-start-dragging",
-		"core:window:allow-set-position",
-		"core:window:allow-set-theme",
-		"core:window:allow-set-progress-bar",
-		"core:window:allow-set-effects",
-		"core:window:allow-set-ignore-cursor-events",
-		"core:window:allow-set-visible-on-all-workspaces",
-		"core:window:deny-set-visible-on-all-workspaces",
-		"core:window:allow-set-content-protected",
-		"core:window:allow-set-always-on-bottom",
-		"core:window:allow-set-always-on-top",
-		"core:webview:default",
-		"core:webview:allow-create-webview-window",
-		"core:app:allow-version",
-		"shell:default",
-		"core:image:default",
-		"dialog:default",
-		"store:default",
-		"process:default",
-		"oauth:allow-start",
-		"updater:default",
-		"notification:default",
-		"deep-link:default",
-		{
-			"identifier": "http:default",
-			"allow": [
-				{ "url": "http://*" },
-				{ "url": "https://*" },
-				{ "url": "http://localhost:*" }
-			]
-		},
-		"clipboard-manager:allow-write-text"
-	]
-}
diff --git a/apps/desktop/src-tauri/examples/desktop-display-transport-benchmark.rs b/apps/desktop/src-tauri/examples/desktop-display-transport-benchmark.rs
deleted file mode 100644
index f7449e2f940..00000000000
--- a/apps/desktop/src-tauri/examples/desktop-display-transport-benchmark.rs
+++ /dev/null
@@ -1,421 +0,0 @@
-use std::{
-    collections::HashMap,
-    path::{Path, PathBuf},
-    sync::Arc,
-    time::{Duration, Instant},
-};
-
-use cap_desktop_lib::frame_ws::{WSFrame, WSFrameFormat, create_watch_frame_ws};
-use cap_editor::{
-    EditorFrameOutput, FrameLayout, Playback, PlaybackRenderOutputFormat, PlaybackSkipReason,
-    PlaybackTelemetry, PlaybackTelemetryEvent, Renderer, finish_renderer_layers_creation,
-    start_renderer_layers_creation,
-};
-use cap_project::{
-    ProjectConfiguration, RecordingMeta, RecordingMetaInner, StudioRecordingMeta,
-    TimelineConfiguration, TimelineSegment, XY,
-};
-use cap_rendering::{GpuOutputFormat, ProjectRecordingsMeta, RenderVideoConstants, Video};
-use tokio::sync::{mpsc, watch};
-
-#[derive(Default)]
-struct Summary {
-    warmup_ms: f64,
-    submitted_frames: u64,
-    rendered_frames: u64,
-    callback_frames: u64,
-    dropped_by_renderer: u64,
-    skipped_frames: u64,
-    send_failures: u64,
-    bytes_from_callback: u64,
-    output_formats: HashMap,
-    skip_reasons: HashMap,
-}
-
-impl Summary {
-    fn record_event(&mut self, event: PlaybackTelemetryEvent) {
-        match event {
-            PlaybackTelemetryEvent::WarmupComplete { elapsed, .. } => {
-                self.warmup_ms = elapsed.as_secs_f64() * 1000.0;
-            }
-            PlaybackTelemetryEvent::FrameSubmitted { .. } => {
-                self.submitted_frames += 1;
-            }
-            PlaybackTelemetryEvent::FrameSkipped {
-                skipped, reason, ..
-            } => {
-                self.skipped_frames += u64::from(skipped);
-                *self.skip_reasons.entry(reason).or_insert(0) += u64::from(skipped);
-            }
-            PlaybackTelemetryEvent::RendererFrame { output_format, .. } => {
-                self.rendered_frames += 1;
-                *self.output_formats.entry(output_format).or_insert(0) += 1;
-            }
-            PlaybackTelemetryEvent::RendererPrepared { .. } => {}
-            PlaybackTelemetryEvent::RendererDropped { .. } => {
-                self.dropped_by_renderer += 1;
-            }
-            PlaybackTelemetryEvent::RendererSendFailed { .. } => {
-                self.send_failures += 1;
-            }
-            PlaybackTelemetryEvent::AudioSegmentsResolved { .. }
-            | PlaybackTelemetryEvent::AudioPipelineReady { .. }
-            | PlaybackTelemetryEvent::ClockStarted { .. } => {}
-        }
-    }
-
-    fn record_callback_frame(&mut self, bytes: usize) {
-        self.callback_frames += 1;
-        self.bytes_from_callback = self.bytes_from_callback.saturating_add(bytes as u64);
-    }
-}
-
-fn arg_value<'a>(args: &'a [String], flag: &str) -> Option<&'a str> {
-    args.iter()
-        .position(|arg| arg == flag)
-        .and_then(|idx| args.get(idx + 1))
-        .map(String::as_str)
-}
-
-fn parse_resolution(args: &[String]) -> XY {
-    let Some(value) = arg_value(args, "--resolution") else {
-        return XY::new(1920, 1080);
-    };
-
-    match value {
-        "full" => XY::new(1920, 1080),
-        "half" => XY::new(1248, 702),
-        "quarter" => XY::new(480, 270),
-        custom => {
-            let Some((width, height)) = custom.split_once('x') else {
-                return XY::new(1920, 1080);
-            };
-            match (width.parse::(), height.parse::()) {
-                (Ok(width), Ok(height)) if width > 0 && height > 0 => XY::new(width, height),
-                _ => XY::new(1920, 1080),
-            }
-        }
-    }
-}
-
-async fn load_recording(
-    recording_path: &Path,
-) -> Result<
-    (
-        RecordingMeta,
-        Box,
-        ProjectConfiguration,
-        Arc,
-    ),
-    String,
-> {
-    let recording_meta = RecordingMeta::load_for_project(recording_path)
-        .map_err(|e| format!("Failed to load recording meta: {e}"))?;
-
-    let RecordingMetaInner::Studio(meta) = &recording_meta.inner else {
-        return Err("Not a studio recording".to_string());
-    };
-    let meta = meta.clone();
-    let mut project = recording_meta.project_config();
-
-    if project.timeline.is_none() {
-        let timeline_segments = match meta.as_ref() {
-            StudioRecordingMeta::SingleSegment { segment } => {
-                let display_path = recording_meta.path(&segment.display.path);
-                let duration = match Video::new(&display_path, 0.0) {
-                    Ok(video) => video.duration,
-                    Err(_) => 5.0,
-                };
-                vec![TimelineSegment {
-                    recording_clip: 0,
-                    start: 0.0,
-                    end: duration,
-                    timescale: 1.0,
-                    name: None,
-                    speed_audio_mode: None,
-                    hide_cursor: None,
-                    volume: None,
-                }]
-            }
-            StudioRecordingMeta::MultipleSegments { inner } => inner
-                .segments
-                .iter()
-                .enumerate()
-                .filter_map(|(i, segment)| {
-                    let display_path = recording_meta.path(&segment.display.path);
-                    let duration = match Video::new(&display_path, 0.0) {
-                        Ok(video) => video.duration,
-                        Err(_) => 5.0,
-                    };
-                    (duration > 0.0).then_some(TimelineSegment {
-                        recording_clip: i as u32,
-                        start: 0.0,
-                        end: duration,
-                        timescale: 1.0,
-                        name: None,
-                        speed_audio_mode: None,
-                        hide_cursor: None,
-                        volume: None,
-                    })
-                })
-                .collect(),
-        };
-
-        if !timeline_segments.is_empty() {
-            project.timeline = Some(TimelineConfiguration {
-                segments: timeline_segments,
-                transitions: Vec::new(),
-                zoom_segments: Vec::new(),
-                scene_segments: Vec::new(),
-                style_segments: Vec::new(),
-                image_segments: Vec::new(),
-                mask_segments: Vec::new(),
-                text_segments: Vec::new(),
-                caption_segments: Vec::new(),
-                keyboard_segments: Vec::new(),
-                audio_segments: Vec::new(),
-                camera3d_segments: Vec::new(),
-            });
-        }
-    }
-
-    let recordings = Arc::new(
-        ProjectRecordingsMeta::new(&recording_meta.project_path, meta.as_ref())
-            .map_err(|e| format!("Failed to create recordings meta: {e}"))?,
-    );
-
-    Ok((recording_meta, meta, project, recordings))
-}
-
-#[tokio::main]
-async fn main() {
-    tracing_subscriber::fmt()
-        .with_env_filter(
-            tracing_subscriber::EnvFilter::from_default_env()
-                .add_directive(tracing::Level::INFO.into()),
-        )
-        .init();
-
-    ffmpeg::init().expect("Failed to initialize FFmpeg");
-
-    let args: Vec = std::env::args().collect();
-    let recording_path = arg_value(&args, "--recording-path")
-        .map(PathBuf::from)
-        .expect("Usage: desktop-display-transport-benchmark --recording-path  [--fps ] [--frames ] [--resolution full|half|quarter|x] [--startup-delay-ms ]");
-    let fps = arg_value(&args, "--fps")
-        .and_then(|s| s.parse().ok())
-        .unwrap_or(60);
-    let target_frames = arg_value(&args, "--frames")
-        .and_then(|s| s.parse().ok())
-        .unwrap_or(300u64);
-    let startup_delay_ms = arg_value(&args, "--startup-delay-ms")
-        .and_then(|s| s.parse().ok())
-        .unwrap_or(3000u64);
-    let resolution_base = parse_resolution(&args);
-
-    let (recording_meta, meta, project, recordings) = match load_recording(&recording_path).await {
-        Ok(recording) => recording,
-        Err(e) => {
-            eprintln!("{e}");
-            std::process::exit(1);
-        }
-    };
-
-    let render_constants = match RenderVideoConstants::new(
-        &recordings.segments,
-        recording_meta.clone(),
-        (*meta).clone(),
-    )
-    .await
-    {
-        Ok(constants) => Arc::new(constants),
-        Err(e) => {
-            eprintln!("Failed to create render constants: {e}");
-            std::process::exit(1);
-        }
-    };
-
-    let (frame_watch_tx, frame_watch_rx) = watch::channel(None);
-    let (ws_port, ws_shutdown_token) =
-        create_watch_frame_ws(frame_watch_rx, Default::default()).await;
-
-    println!("DISPLAY_WS_URL=ws://127.0.0.1:{ws_port}");
-    println!(
-        "DISPLAY_BENCHMARK_READY fps={fps} frames={target_frames} resolution={}x{} startup_delay_ms={startup_delay_ms}",
-        resolution_base.x, resolution_base.y
-    );
-
-    tokio::time::sleep(Duration::from_millis(startup_delay_ms)).await;
-
-    let layers_rx = start_renderer_layers_creation(&render_constants, &project);
-    let force_ffmpeg_for_editor = cfg!(target_os = "windows")
-        || std::env::var_os("CAP_EDITOR_FORCE_FFMPEG_DECODER").is_some();
-    let segment_medias =
-        match cap_editor::create_segments(&recording_meta, meta.as_ref(), force_ffmpeg_for_editor)
-            .await
-        {
-            Ok(segments) => Arc::new(segments),
-            Err(e) => {
-                eprintln!("Failed to create segments: {e}");
-                std::process::exit(1);
-            }
-        };
-    let layers_rx = finish_renderer_layers_creation(layers_rx).await;
-
-    let (telemetry, mut telemetry_rx) = PlaybackTelemetry::channel();
-    let (frame_tx, mut frame_rx) = mpsc::unbounded_channel::();
-
-    let frame_cb = Box::new(move |output: EditorFrameOutput, _: FrameLayout| {
-        let ws_frame = match output {
-            EditorFrameOutput::Nv12(frame) => {
-                let ws_format = match frame.format {
-                    GpuOutputFormat::Nv12 => WSFrameFormat::Nv12 { full_range: false },
-                    GpuOutputFormat::Rgba => WSFrameFormat::Rgba,
-                };
-                let metadata_bytes = match frame.format {
-                    GpuOutputFormat::Nv12 => 28,
-                    GpuOutputFormat::Rgba => 24,
-                };
-                let data = frame.data.into_vec();
-                let bytes = data.len() + metadata_bytes;
-                let ws_frame = WSFrame {
-                    data: Arc::new(data).into(),
-                    width: frame.width,
-                    height: frame.height,
-                    stride: frame.y_stride,
-                    frame_number: frame.frame_number,
-                    target_time_ns: frame.target_time_ns,
-                    format: ws_format,
-                    created_at: Instant::now(),
-                };
-                let _ = frame_tx.send(bytes);
-                ws_frame
-            }
-            EditorFrameOutput::Rgba(frame) => {
-                let bytes = frame.data.len() + 24;
-                let ws_frame = WSFrame {
-                    data: frame.data.into(),
-                    width: frame.width,
-                    height: frame.height,
-                    stride: frame.padded_bytes_per_row,
-                    frame_number: frame.frame_number,
-                    target_time_ns: frame.target_time_ns,
-                    format: WSFrameFormat::Rgba,
-                    created_at: Instant::now(),
-                };
-                let _ = frame_tx.send(bytes);
-                ws_frame
-            }
-            #[cfg(target_os = "macos")]
-            EditorFrameOutput::Surface(_) => return,
-        };
-        frame_watch_tx
-            .send(Some(Arc::new(ws_frame.into_packed())))
-            .ok();
-    });
-
-    let renderer = match Renderer::spawn_with_telemetry(
-        render_constants.clone(),
-        frame_cb,
-        layers_rx,
-        Some(telemetry.clone()),
-    ) {
-        Ok(renderer) => Arc::new(renderer),
-        Err(e) => {
-            eprintln!("Failed to start renderer: {e}");
-            std::process::exit(1);
-        }
-    };
-
-    let (_project_tx, project_rx) = watch::channel(project);
-    let audio_output = Arc::new(cap_editor::AudioOutput::new());
-    let playback = Playback {
-        renderer: renderer.clone(),
-        render_constants,
-        start_frame_number: 0,
-        project: project_rx,
-        segment_medias,
-        music: cap_editor::MusicTracks::new(),
-        audio_output,
-        telemetry: Some(telemetry),
-    };
-
-    let playback_handle = match playback.start(fps, resolution_base).await {
-        Ok(handle) => handle,
-        Err(e) => {
-            eprintln!("Failed to start playback: {e:?}");
-            std::process::exit(1);
-        }
-    };
-
-    let start = Instant::now();
-    let timeout = Duration::from_secs_f64(target_frames as f64 / fps as f64 + 15.0);
-    let deadline = tokio::time::sleep(timeout);
-    tokio::pin!(deadline);
-
-    let mut summary = Summary::default();
-
-    loop {
-        if summary.submitted_frames >= target_frames {
-            break;
-        }
-
-        tokio::select! {
-            event = telemetry_rx.recv() => {
-                if let Some(event) = event {
-                    summary.record_event(event);
-                } else {
-                    break;
-                }
-            }
-            bytes = frame_rx.recv() => {
-                if let Some(bytes) = bytes {
-                    summary.record_callback_frame(bytes);
-                }
-            }
-            _ = &mut deadline => {
-                break;
-            }
-        }
-    }
-
-    let measured_elapsed = start.elapsed().as_secs_f64();
-
-    playback_handle.stop();
-    tokio::time::sleep(Duration::from_millis(250)).await;
-
-    while let Ok(event) = telemetry_rx.try_recv() {
-        summary.record_event(event);
-    }
-    while let Ok(bytes) = frame_rx.try_recv() {
-        summary.record_callback_frame(bytes);
-    }
-
-    renderer.stop().await;
-    ws_shutdown_token.cancel();
-
-    let rendered_fps = summary.rendered_frames as f64 / measured_elapsed.max(0.001);
-    let mb_sent = summary.bytes_from_callback as f64 / 1_000_000.0;
-    let mb_per_sec = mb_sent / measured_elapsed.max(0.001);
-
-    println!(
-        "DISPLAY_BENCHMARK_RESULT submitted={} rendered={} callback={} renderer_dropped={} skipped={} send_failures={} rendered_fps={rendered_fps:.1} payload_mb={mb_sent:.1} payload_mb_per_sec={mb_per_sec:.1} warmup_ms={:.1}",
-        summary.submitted_frames,
-        summary.rendered_frames,
-        summary.callback_frames,
-        summary.dropped_by_renderer,
-        summary.skipped_frames,
-        summary.send_failures,
-        summary.warmup_ms
-    );
-
-    if !summary.skip_reasons.is_empty() {
-        println!("DISPLAY_BENCHMARK_SKIP_REASONS={:?}", summary.skip_reasons);
-    }
-    if !summary.output_formats.is_empty() {
-        println!(
-            "DISPLAY_BENCHMARK_OUTPUT_FORMATS={:?}",
-            summary.output_formats
-        );
-    }
-}
diff --git a/apps/desktop/src-tauri/icons/Square107x107Logo.png b/apps/desktop/src-tauri/icons/Square107x107Logo.png
deleted file mode 100644
index 2fc5a7a6f95..00000000000
Binary files a/apps/desktop/src-tauri/icons/Square107x107Logo.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/Square142x142Logo.png b/apps/desktop/src-tauri/icons/Square142x142Logo.png
deleted file mode 100644
index 4fea3c2440b..00000000000
Binary files a/apps/desktop/src-tauri/icons/Square142x142Logo.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/Square150x150Logo.png b/apps/desktop/src-tauri/icons/Square150x150Logo.png
deleted file mode 100644
index 4779a865b78..00000000000
Binary files a/apps/desktop/src-tauri/icons/Square150x150Logo.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/Square284x284Logo.png b/apps/desktop/src-tauri/icons/Square284x284Logo.png
deleted file mode 100644
index acc87c24769..00000000000
Binary files a/apps/desktop/src-tauri/icons/Square284x284Logo.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/Square30x30Logo.png b/apps/desktop/src-tauri/icons/Square30x30Logo.png
deleted file mode 100644
index ed468adbd76..00000000000
Binary files a/apps/desktop/src-tauri/icons/Square30x30Logo.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/Square44x44Logo.png b/apps/desktop/src-tauri/icons/Square44x44Logo.png
deleted file mode 100644
index a46dd14926c..00000000000
Binary files a/apps/desktop/src-tauri/icons/Square44x44Logo.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/Square71x71Logo.png b/apps/desktop/src-tauri/icons/Square71x71Logo.png
deleted file mode 100644
index e1474dd94c0..00000000000
Binary files a/apps/desktop/src-tauri/icons/Square71x71Logo.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/Square89x89Logo.png b/apps/desktop/src-tauri/icons/Square89x89Logo.png
deleted file mode 100644
index a2aff6fdef4..00000000000
Binary files a/apps/desktop/src-tauri/icons/Square89x89Logo.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/StoreLogo.png b/apps/desktop/src-tauri/icons/StoreLogo.png
deleted file mode 100644
index 10caf46016f..00000000000
Binary files a/apps/desktop/src-tauri/icons/StoreLogo.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png b/apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index ba19ac5104d..00000000000
Binary files a/apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png b/apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png
deleted file mode 100644
index be9ba4d006c..00000000000
Binary files a/apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png b/apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png
deleted file mode 100644
index ba19ac5104d..00000000000
Binary files a/apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png b/apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index 17fbfc0c898..00000000000
Binary files a/apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png b/apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png
deleted file mode 100644
index 17759564502..00000000000
Binary files a/apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png b/apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png
deleted file mode 100644
index 17fbfc0c898..00000000000
Binary files a/apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png b/apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index bd570f63110..00000000000
Binary files a/apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png b/apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png
deleted file mode 100644
index 1b77945007e..00000000000
Binary files a/apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png b/apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png
deleted file mode 100644
index bd570f63110..00000000000
Binary files a/apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png b/apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index 885d4f2e4fb..00000000000
Binary files a/apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png b/apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png
deleted file mode 100644
index f543e05bf6e..00000000000
Binary files a/apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png b/apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png
deleted file mode 100644
index 885d4f2e4fb..00000000000
Binary files a/apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png b/apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index 7479093a104..00000000000
Binary files a/apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png b/apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png
deleted file mode 100644
index d06e450592b..00000000000
Binary files a/apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png b/apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png
deleted file mode 100644
index 7479093a104..00000000000
Binary files a/apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/icon.icns b/apps/desktop/src-tauri/icons/icon.icns
deleted file mode 100644
index 0e34c203e22..00000000000
Binary files a/apps/desktop/src-tauri/icons/icon.icns and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@1x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@1x.png
deleted file mode 100644
index 7d34df52915..00000000000
Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@1x.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@2x-1.png b/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@2x-1.png
deleted file mode 100644
index 73c63d85b97..00000000000
Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@2x-1.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@2x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@2x.png
deleted file mode 100644
index 73c63d85b97..00000000000
Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@2x.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@3x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@3x.png
deleted file mode 100644
index a71697a2e67..00000000000
Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@3x.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@1x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@1x.png
deleted file mode 100644
index 0fd83a9d2c5..00000000000
Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@1x.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@2x-1.png b/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@2x-1.png
deleted file mode 100644
index 74deb21e810..00000000000
Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@2x-1.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@2x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@2x.png
deleted file mode 100644
index 74deb21e810..00000000000
Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@2x.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@3x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@3x.png
deleted file mode 100644
index 761b732cef6..00000000000
Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@3x.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@1x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@1x.png
deleted file mode 100644
index 73c63d85b97..00000000000
Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@1x.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@2x-1.png b/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@2x-1.png
deleted file mode 100644
index 1e46db6cd64..00000000000
Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@2x-1.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@2x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@2x.png
deleted file mode 100644
index 1e46db6cd64..00000000000
Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@2x.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@3x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@3x.png
deleted file mode 100644
index d1303e0ce7c..00000000000
Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@3x.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-512@2x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-512@2x.png
deleted file mode 100644
index a89ebff3b8e..00000000000
Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-512@2x.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-60x60@2x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-60x60@2x.png
deleted file mode 100644
index d1303e0ce7c..00000000000
Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-60x60@2x.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-60x60@3x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-60x60@3x.png
deleted file mode 100644
index ca5f908bdc7..00000000000
Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-60x60@3x.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-76x76@1x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-76x76@1x.png
deleted file mode 100644
index d60dc4fa209..00000000000
Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-76x76@1x.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-76x76@2x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-76x76@2x.png
deleted file mode 100644
index 325aa1a7526..00000000000
Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-76x76@2x.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png
deleted file mode 100644
index 0ab8ebc8372..00000000000
Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/linux/so.cap.desktop-tray-default-symbolic.svg b/apps/desktop/src-tauri/icons/linux/so.cap.desktop-tray-default-symbolic.svg
deleted file mode 100644
index e2bd5f67136..00000000000
--- a/apps/desktop/src-tauri/icons/linux/so.cap.desktop-tray-default-symbolic.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
-	
-
diff --git a/apps/desktop/src-tauri/icons/linux/so.cap.desktop-tray-instant-symbolic.svg b/apps/desktop/src-tauri/icons/linux/so.cap.desktop-tray-instant-symbolic.svg
deleted file mode 100644
index 579dcfd0aa3..00000000000
--- a/apps/desktop/src-tauri/icons/linux/so.cap.desktop-tray-instant-symbolic.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
-	
-
diff --git a/apps/desktop/src-tauri/icons/linux/so.cap.desktop-tray-screenshot-symbolic.svg b/apps/desktop/src-tauri/icons/linux/so.cap.desktop-tray-screenshot-symbolic.svg
deleted file mode 100644
index f54b7f06f14..00000000000
--- a/apps/desktop/src-tauri/icons/linux/so.cap.desktop-tray-screenshot-symbolic.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
-	
-
diff --git a/apps/desktop/src-tauri/icons/linux/so.cap.desktop-tray-stop-symbolic.svg b/apps/desktop/src-tauri/icons/linux/so.cap.desktop-tray-stop-symbolic.svg
deleted file mode 100644
index 127c60a62fb..00000000000
--- a/apps/desktop/src-tauri/icons/linux/so.cap.desktop-tray-stop-symbolic.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
-	
-	
-
diff --git a/apps/desktop/src-tauri/icons/linux/so.cap.desktop-tray-studio-symbolic.svg b/apps/desktop/src-tauri/icons/linux/so.cap.desktop-tray-studio-symbolic.svg
deleted file mode 100644
index 2f096179a26..00000000000
--- a/apps/desktop/src-tauri/icons/linux/so.cap.desktop-tray-studio-symbolic.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
-	
-
diff --git a/apps/desktop/src-tauri/icons/macos/icon.png b/apps/desktop/src-tauri/icons/macos/icon.png
deleted file mode 100644
index 15fca4afa51..00000000000
Binary files a/apps/desktop/src-tauri/icons/macos/icon.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/tray-default-icon-instant.png b/apps/desktop/src-tauri/icons/tray-default-icon-instant.png
deleted file mode 100644
index af33c96c656..00000000000
Binary files a/apps/desktop/src-tauri/icons/tray-default-icon-instant.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/tray-default-icon-screenshot.png b/apps/desktop/src-tauri/icons/tray-default-icon-screenshot.png
deleted file mode 100644
index 42980c4bac0..00000000000
Binary files a/apps/desktop/src-tauri/icons/tray-default-icon-screenshot.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/tray-default-icon-studio.png b/apps/desktop/src-tauri/icons/tray-default-icon-studio.png
deleted file mode 100644
index 27aa4ad59c7..00000000000
Binary files a/apps/desktop/src-tauri/icons/tray-default-icon-studio.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/icons/tray-stop-icon.png b/apps/desktop/src-tauri/icons/tray-stop-icon.png
deleted file mode 100644
index f2995afa2ef..00000000000
Binary files a/apps/desktop/src-tauri/icons/tray-stop-icon.png and /dev/null differ
diff --git a/apps/desktop/src-tauri/sounds/screenshot.ogg b/apps/desktop/src-tauri/sounds/screenshot.ogg
deleted file mode 100644
index 40e297b416e..00000000000
Binary files a/apps/desktop/src-tauri/sounds/screenshot.ogg and /dev/null differ
diff --git a/apps/desktop/src-tauri/src/api.rs b/apps/desktop/src-tauri/src/api.rs
deleted file mode 100644
index c468376396f..00000000000
--- a/apps/desktop/src-tauri/src/api.rs
+++ /dev/null
@@ -1,492 +0,0 @@
-//! TODO: We should investigate generating this with OpenAPI.
-//! This will come part of the EffectTS rewrite work.
-
-use serde::{Deserialize, Serialize};
-use serde_json::json;
-use specta::Type;
-use std::collections::HashMap;
-use tauri::AppHandle;
-use tracing::{instrument, trace};
-
-use crate::web_api::{AuthedApiError, ManagerExt};
-
-#[derive(Debug, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct MultipartUploadInitiateResponse {
-    pub upload_id: String,
-    pub provider: Option,
-}
-
-#[instrument(skip(app))]
-pub async fn upload_multipart_initiate(
-    app: &AppHandle,
-    video_id: &str,
-    replace_existing: bool,
-) -> Result {
-    let resp = app
-        .authed_api_request("/api/upload/multipart/initiate", |c, url| {
-            c.post(url)
-                .header("Content-Type", "application/json")
-                .json(&serde_json::json!({
-                    "videoId": video_id,
-                    "contentType": "video/mp4",
-                    "replaceExisting": replace_existing
-                }))
-        })
-        .await
-        .map_err(|err| format!("api/upload_multipart_initiate/request: {err}"))?;
-
-    if !resp.status().is_success() {
-        let status = resp.status().as_u16();
-        let error_body = resp
-            .text()
-            .await
-            .unwrap_or_else(|_| "".to_string());
-        return Err(format!("api/upload_multipart_initiate/{status}: {error_body}").into());
-    }
-
-    resp.json::()
-        .await
-        .map_err(|err| format!("api/upload_multipart_initiate/response: {err}").into())
-}
-
-#[instrument(skip(app, upload_id))]
-pub async fn upload_multipart_presign_part(
-    app: &AppHandle,
-    video_id: &str,
-    upload_id: &str,
-    part_number: u32,
-    md5_sum: Option<&str>,
-) -> Result {
-    #[derive(Deserialize)]
-    #[serde(rename_all = "camelCase")]
-    pub struct Response {
-        presigned_url: String,
-    }
-
-    let mut body = serde_json::Map::from_iter([
-        ("videoId".to_string(), json!(video_id)),
-        ("uploadId".to_string(), json!(upload_id)),
-        ("partNumber".to_string(), json!(part_number)),
-    ]);
-
-    if let Some(md5_sum) = md5_sum {
-        body.insert("md5Sum".to_string(), json!(md5_sum));
-    }
-
-    let resp = app
-        .authed_api_request("/api/upload/multipart/presign-part", |c, url| {
-            c.post(url)
-                .header("Content-Type", "application/json")
-                .json(&serde_json::json!(body))
-        })
-        .await
-        .map_err(|err| format!("api/upload_multipart_presign_part/request: {err}"))?;
-
-    if !resp.status().is_success() {
-        let status = resp.status().as_u16();
-        let error_body = resp
-            .text()
-            .await
-            .unwrap_or_else(|_| "".to_string());
-        return Err(format!("api/upload_multipart_presign_part/{status}: {error_body}").into());
-    }
-
-    crate::upload::lifecycle::cancellable(resp.json::())
-        .await?
-        .map_err(|err| format!("api/upload_multipart_presign_part/response: {err}").into())
-        .map(|data| data.presigned_url)
-}
-
-#[derive(Debug, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub struct UploadedPart {
-    pub part_number: u32,
-    pub etag: String,
-    pub size: usize,
-    #[serde(skip)]
-    pub total_size: u64,
-    #[serde(skip)]
-    pub object_identity: Option,
-}
-
-#[derive(Serialize, Debug, Clone)]
-#[serde(rename_all = "camelCase")]
-pub struct S3VideoMeta {
-    #[serde(rename = "durationInSecs")]
-    pub duration_in_secs: f64,
-    pub width: u32,
-    pub height: u32,
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub fps: Option,
-}
-
-#[derive(Debug, PartialEq, Eq)]
-pub(crate) enum MultipartCompletion {
-    Completed(Option),
-    ReplacementRestartRequired,
-}
-
-fn replacement_restart_required(status: u16, body: &str, replace_existing: bool) -> bool {
-    #[derive(Deserialize)]
-    struct ErrorBody {
-        code: String,
-    }
-
-    replace_existing
-        && status == 409
-        && serde_json::from_str::(body)
-            .is_ok_and(|body| body.code == "REPLACEMENT_RESTART_REQUIRED")
-}
-
-#[instrument(skip_all)]
-pub async fn upload_multipart_complete(
-    app: &AppHandle,
-    video_id: &str,
-    upload_id: &str,
-    parts: &[UploadedPart],
-    meta: Option,
-    replace_existing: bool,
-) -> Result, AuthedApiError> {
-    match upload_multipart_complete_outcome(app, video_id, upload_id, parts, meta, replace_existing)
-        .await?
-    {
-        MultipartCompletion::Completed(identity) => Ok(identity),
-        MultipartCompletion::ReplacementRestartRequired => {
-            Err("Replacement upload must be restarted; local files retained".into())
-        }
-    }
-}
-
-#[instrument(skip_all)]
-pub(crate) async fn upload_multipart_complete_outcome(
-    app: &AppHandle,
-    video_id: &str,
-    upload_id: &str,
-    parts: &[UploadedPart],
-    meta: Option,
-    replace_existing: bool,
-) -> Result {
-    #[derive(Serialize)]
-    #[serde(rename_all = "camelCase")]
-    pub struct MultipartCompleteRequest<'a> {
-        video_id: &'a str,
-        upload_id: &'a str,
-        parts: &'a [UploadedPart],
-        #[serde(flatten)]
-        meta: Option,
-        replace_existing: bool,
-    }
-
-    #[derive(Deserialize)]
-    pub struct Response {
-        #[serde(rename = "objectIdentity")]
-        object_identity: Option,
-    }
-
-    trace!("Completing multipart upload");
-
-    let resp = app
-        .authed_api_request("/api/upload/multipart/complete", |c, url| {
-            c.post(url)
-                .header("Content-Type", "application/json")
-                .json(&MultipartCompleteRequest {
-                    video_id,
-                    upload_id,
-                    parts,
-                    meta,
-                    replace_existing,
-                })
-        })
-        .await
-        .map_err(|err| format!("api/upload_multipart_complete/request: {err}"))?;
-
-    if !resp.status().is_success() {
-        let status = resp.status().as_u16();
-        let error_body = crate::upload::lifecycle::cancellable(resp.text())
-            .await?
-            .unwrap_or_else(|_| "".to_string());
-        if replacement_restart_required(status, &error_body, replace_existing) {
-            return Ok(MultipartCompletion::ReplacementRestartRequired);
-        }
-        return Err(format!("api/upload_multipart_complete/{status}: {error_body}").into());
-    }
-
-    crate::upload::lifecycle::cancellable(resp.json::())
-        .await?
-        .map_err(|err| format!("api/upload_multipart_complete/response: {err}").into())
-        .map(|data| MultipartCompletion::Completed(data.object_identity))
-}
-
-#[derive(Debug, Serialize)]
-#[serde(rename_all = "lowercase")]
-pub enum PresignedS3PutRequestMethod {
-    #[allow(unused)]
-    Post,
-    Put,
-}
-
-#[derive(Debug, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub struct PresignedS3PutRequest {
-    pub video_id: String,
-    pub subpath: String,
-    pub method: PresignedS3PutRequestMethod,
-    #[serde(flatten)]
-    pub meta: Option,
-}
-
-#[derive(Debug, Deserialize, Clone)]
-#[serde(rename_all = "camelCase")]
-pub struct SignedUploadTarget {
-    pub url: String,
-    #[serde(default)]
-    pub headers: HashMap,
-}
-
-#[instrument(skip(app))]
-pub async fn upload_signed(
-    app: &AppHandle,
-    body: PresignedS3PutRequest,
-) -> Result {
-    #[derive(Deserialize)]
-    #[serde(rename_all = "camelCase")]
-    pub struct Response {
-        presigned_put_data: SignedUploadTarget,
-    }
-
-    let resp = app
-        .authed_api_request("/api/upload/signed", |client, url| {
-            client.post(url).json(&body)
-        })
-        .await
-        .map_err(|err| format!("api/upload_signed/request: {err}"))?;
-
-    if !resp.status().is_success() {
-        let status = resp.status().as_u16();
-        let error_body = resp
-            .text()
-            .await
-            .unwrap_or_else(|_| "".to_string());
-        return Err(format!("api/upload_signed/{status}: {error_body}").into());
-    }
-
-    crate::upload::lifecycle::cancellable(resp.json::())
-        .await?
-        .map_err(|err| format!("api/upload_signed/response: {err}").into())
-        .map(|data| data.presigned_put_data)
-}
-
-#[instrument(skip(app))]
-pub async fn upload_signed_batch(
-    app: &AppHandle,
-    video_id: &str,
-    subpaths: &[String],
-) -> Result, AuthedApiError> {
-    #[derive(Deserialize)]
-    struct Response {
-        urls: std::collections::HashMap,
-    }
-
-    let resp = app
-        .authed_api_request("/api/upload/signed/batch", |client, url| {
-            client.post(url).json(&serde_json::json!({
-                "videoId": video_id,
-                "subpaths": subpaths,
-            }))
-        })
-        .await
-        .map_err(|err| format!("api/upload_signed_batch/request: {err}"))?;
-
-    if !resp.status().is_success() {
-        let status = resp.status().as_u16();
-        let error_body = resp
-            .text()
-            .await
-            .unwrap_or_else(|_| "".to_string());
-        return Err(format!("api/upload_signed_batch/{status}: {error_body}").into());
-    }
-
-    crate::upload::lifecycle::cancellable(resp.json::())
-        .await?
-        .map_err(|err| format!("api/upload_signed_batch/response: {err}").into())
-        .map(|data| data.urls)
-}
-
-#[instrument(skip(app))]
-pub async fn desktop_video_progress(
-    app: &AppHandle,
-    video_id: &str,
-    uploaded: u64,
-    total: u64,
-) -> Result<(), AuthedApiError> {
-    let resp = app
-        .authed_api_request("/api/desktop/video/progress", |client, url| {
-            client.post(url).json(&json!({
-                "videoId": video_id,
-                "uploaded": uploaded,
-                "total": total,
-                "updatedAt": chrono::Utc::now().to_rfc3339()
-            }))
-        })
-        .await
-        .map_err(|err| format!("api/desktop_video_progress/request: {err}"))?;
-
-    if !resp.status().is_success() {
-        let status = resp.status().as_u16();
-        let error_body = resp
-            .text()
-            .await
-            .unwrap_or_else(|_| "".to_string());
-        return Err(format!("api/desktop_video_progress/{status}: {error_body}").into());
-    }
-
-    Ok(())
-}
-
-#[derive(Serialize, Deserialize, Type, Debug, Clone, Default)]
-#[serde(rename_all = "camelCase")]
-pub struct OrganizationBrandColors {
-    pub primary: Option,
-    pub secondary: Option,
-    pub accent: Option,
-    pub background: Option,
-}
-
-fn default_organization_role() -> String {
-    "member".to_string()
-}
-
-#[derive(Serialize, Deserialize, Type, Debug, Clone)]
-#[serde(rename_all = "camelCase")]
-pub struct Organization {
-    pub id: String,
-    pub name: String,
-    pub owner_id: String,
-    #[serde(default = "default_organization_role")]
-    pub role: String,
-    #[serde(default)]
-    pub can_edit_brand: bool,
-    #[serde(default)]
-    pub icon_url: Option,
-    #[serde(default)]
-    pub brand_colors: OrganizationBrandColors,
-}
-
-pub(crate) async fn prepare_recording_segments(
-    app: &AppHandle,
-    video_id: &str,
-    segments: &[crate::upload::preparation::Segment],
-) -> Result>, AuthedApiError> {
-    #[derive(Deserialize)]
-    struct Response {
-        version: u32,
-        prepared: Vec,
-    }
-
-    let response = app
-        .authed_api_request("/api/recording/prepare", |client, url| {
-            client
-                .post(url)
-                .timeout(std::time::Duration::from_secs(20))
-                .json(&serde_json::json!({ "videoId": video_id, "segments": segments }))
-        })
-        .await?;
-    if matches!(response.status().as_u16(), 404 | 405) {
-        return Ok(None);
-    }
-    if !response.status().is_success() {
-        return Err(format!(
-            "Optional recording preparation unavailable ({})",
-            response.status()
-        )
-        .into());
-    }
-    let response: Response = crate::upload::lifecycle::cancellable(response.json()).await??;
-    if response.version != 1 || response.prepared.len() > 32 {
-        return Ok(None);
-    }
-    Ok(Some(response.prepared))
-}
-
-pub async fn verify_recording_complete(
-    app: &AppHandle,
-    video_id: &str,
-    verification: &cap_recording::upload_verification::UploadVerification,
-) -> Result, AuthedApiError> {
-    let response = app
-        .authed_api_request("/api/upload/recording-complete", |client, url| {
-            client
-                .post(url)
-                .timeout(std::time::Duration::from_secs(45))
-                .json(&serde_json::json!({
-                    "videoId": video_id,
-                    "verification": verification,
-                }))
-        })
-        .await?;
-    let status = response.status();
-    let response: serde_json::Value =
-        crate::upload::lifecycle::cancellable(response.json()).await??;
-    if status == reqwest::StatusCode::CONFLICT
-        && response.get("status").and_then(serde_json::Value::as_str) == Some("reupload-required")
-    {
-        return Err(AuthedApiError::ReuploadRequired);
-    }
-    if !status.is_success() {
-        return Err(format!(
-            "Recording verification is unavailable ({status}); local recording retained"
-        )
-        .into());
-    }
-    verification
-        .verified_receipt(video_id, &response)
-        .map_err(AuthedApiError::from)
-}
-
-pub async fn fetch_organizations(app: &AppHandle) -> Result, AuthedApiError> {
-    let resp = app
-        .authed_api_request("/api/desktop/organizations", |client, url| client.get(url))
-        .await
-        .map_err(|err| format!("api/fetch_organizations/request: {err}"))?;
-
-    if !resp.status().is_success() {
-        let status = resp.status().as_u16();
-        let error_body = resp
-            .text()
-            .await
-            .unwrap_or_else(|_| "".to_string());
-        return Err(format!("api/fetch_organizations/{status}: {error_body}").into());
-    }
-
-    resp.json()
-        .await
-        .map_err(|err| format!("api/fetch_organizations/response: {err}").into())
-}
-
-#[cfg(test)]
-mod replacement_completion_tests {
-    use super::*;
-
-    #[test]
-    fn restart_requires_replacement_conflict_and_exact_structured_code() {
-        let restart = r#"{"code":"REPLACEMENT_RESTART_REQUIRED","error":"Restart upload"}"#;
-        assert!(replacement_restart_required(409, restart, true));
-        assert!(!replacement_restart_required(409, restart, false));
-        for status in [200, 400, 401, 403, 404, 500, 503] {
-            assert!(!replacement_restart_required(status, restart, true));
-        }
-        for body in [
-            "REPLACEMENT_RESTART_REQUIRED",
-            r#"{"error":"REPLACEMENT_RESTART_REQUIRED"}"#,
-            r#"{"code":"OTHER_CONFLICT"}"#,
-            r#"{"code":"replacement_restart_required"}"#,
-            r#"{"code":null}"#,
-            r#"{"code":1}"#,
-            "{}",
-            "invalid JSON",
-        ] {
-            assert!(!replacement_restart_required(409, body, true));
-        }
-    }
-}
diff --git a/apps/desktop/src-tauri/src/audio.rs b/apps/desktop/src-tauri/src/audio.rs
deleted file mode 100644
index 6087a9ad6ce..00000000000
--- a/apps/desktop/src-tauri/src/audio.rs
+++ /dev/null
@@ -1,95 +0,0 @@
-use cap_audio::DecodedAudio;
-
-#[path = "recording_start_sound.rs"]
-mod recording_start_sound;
-
-pub use recording_start_sound::StartCue;
-
-pub fn prime_recording_start_sound() -> StartCue {
-    recording_start_sound::prime(AppSounds::StartRecording.get_sound_bytes())
-}
-
-pub async fn play_recording_start_sound(cue: StartCue, gate: cap_recording::RecordingStartGate) {
-    recording_start_sound::play(cue, gate).await;
-}
-
-fn play_audio(bytes: &'static [u8]) {
-    use rodio::{Decoder, OutputStream, Sink};
-    use std::io::Cursor;
-
-    std::thread::spawn(move || {
-        if let Ok((_, stream)) = OutputStream::try_default() {
-            let file = Cursor::new(bytes);
-            let source = Decoder::new(file).unwrap();
-            let sink = Sink::try_new(&stream).unwrap();
-            sink.append(source);
-            sink.sleep_until_end();
-        }
-    });
-}
-
-#[allow(dead_code)]
-pub enum AppSounds {
-    StartRecording,
-    StopRecording,
-    Screenshot,
-    Notification,
-}
-
-impl AppSounds {
-    pub fn play(&self) {
-        let bytes = self.get_sound_bytes();
-        play_audio(bytes);
-    }
-
-    fn get_sound_bytes(&self) -> &'static [u8] {
-        match self {
-            AppSounds::StartRecording => include_bytes!("../sounds/start-recording.ogg"),
-            AppSounds::StopRecording => include_bytes!("../sounds/stop-recording.ogg"),
-            AppSounds::Screenshot => include_bytes!("../sounds/screenshot.ogg"),
-            AppSounds::Notification => include_bytes!("../sounds/action.ogg"),
-        }
-    }
-}
-
-pub fn get_waveform(audio: &DecodedAudio) -> Vec {
-    cap_audio::waveform_peaks(audio.sample_slices(), audio.channels())
-}
-
-const WAVEFORM_PEAKS_PER_SECOND: f64 = 10.0;
-const WAVEFORM_SILENCE_DB: f32 = -60.0;
-
-/// Playback reads each track at source time plus its timing repair offset
-/// (`SegmentAudioTimingRepair`), so the peaks are shifted the same way; the
-/// editor then only has to add the user's clip offset.
-pub fn align_waveform_to_playback(peaks: Vec, timing_offset_secs: f32) -> Vec {
-    let shift = (f64::from(timing_offset_secs) * WAVEFORM_PEAKS_PER_SECOND).round() as isize;
-    if shift > 0 {
-        peaks.into_iter().skip(shift.unsigned_abs()).collect()
-    } else if shift < 0 {
-        std::iter::repeat_n(WAVEFORM_SILENCE_DB, shift.unsigned_abs())
-            .chain(peaks)
-            .collect()
-    } else {
-        peaks
-    }
-}
-
-#[cfg(test)]
-mod waveform_alignment_tests {
-    use super::align_waveform_to_playback;
-
-    #[test]
-    fn shifts_peaks_by_the_timing_repair_offset() {
-        let peaks = vec![-10.0, -20.0, -30.0, -40.0];
-        assert_eq!(
-            align_waveform_to_playback(peaks.clone(), 0.2),
-            vec![-30.0, -40.0]
-        );
-        assert_eq!(
-            align_waveform_to_playback(peaks.clone(), -0.1),
-            vec![-60.0, -10.0, -20.0, -30.0, -40.0]
-        );
-        assert_eq!(align_waveform_to_playback(peaks.clone(), 0.02), peaks);
-    }
-}
diff --git a/apps/desktop/src-tauri/src/audio_library.rs b/apps/desktop/src-tauri/src/audio_library.rs
deleted file mode 100644
index 561b9673696..00000000000
--- a/apps/desktop/src-tauri/src/audio_library.rs
+++ /dev/null
@@ -1,165 +0,0 @@
-use std::path::PathBuf;
-
-use cap_enc_ffmpeg::remux::get_media_duration;
-use serde::{Deserialize, Serialize};
-use specta::Type;
-use tauri::{AppHandle, Manager, path::BaseDirectory};
-
-use crate::editor_window::WindowEditorInstance;
-
-const AUDIO_IMPORT_EXTENSIONS: &[&str] = &["ogg", "m4a", "mp3", "wav", "aac", "flac"];
-
-/// Built-in music tracks bundled as Tauri resources under `assets/music/{id}.mp3`.
-/// `id` doubles as the bundled file stem so the resource path is derivable.
-const AUDIO_LIBRARY: &[(&str, &str)] = &[
-    ("lofi-beats-mirostar", "Lofi Beats"),
-    ("raindrops-lofi-sleep-bluelike", "Raindrops"),
-    ("sunday-mood-lofi-cafe-upbeat-bluelike", "Sunday Mood"),
-    ("good-night-lofi-cozy-chill-fassounds", "Good Night"),
-    (
-        "ambient-trap-empty-streets-dreamstate-openmindaudio",
-        "Empty Streets",
-    ),
-    ("lofi-study-calm-peaceful-chill-hop-fassounds", "Study"),
-    ("lofi-cinematic-pulsebox", "Cinematic"),
-    ("lofi-hip-hop-leberch", "Hip Hop"),
-    ("cassette-retrositive", "Cassette"),
-    ("lofi-smooth-pulsebox", "Smooth"),
-];
-
-const AUDIO_LIBRARY_CATEGORY: &str = "Lo-Fi";
-
-#[derive(Serialize, Deserialize, Type, Clone, Debug)]
-#[serde(rename_all = "camelCase")]
-pub struct AudioLibraryTrack {
-    pub id: String,
-    pub name: String,
-    pub category: String,
-}
-
-#[derive(Serialize, Deserialize, Type, Clone, Debug)]
-#[serde(rename_all = "camelCase")]
-pub struct ImportedAudioTrack {
-    /// Path relative to the project directory, e.g. `assets/audio/`.
-    pub path: String,
-    pub name: String,
-    pub duration: f64,
-}
-
-#[tauri::command]
-#[specta::specta]
-pub fn list_audio_library() -> Vec {
-    AUDIO_LIBRARY
-        .iter()
-        .map(|(id, name)| AudioLibraryTrack {
-            id: (*id).to_string(),
-            name: (*name).to_string(),
-            category: AUDIO_LIBRARY_CATEGORY.to_string(),
-        })
-        .collect()
-}
-
-fn probe_duration(path: &std::path::Path) -> f64 {
-    get_media_duration(path)
-        .map(|duration| duration.as_secs_f64())
-        .unwrap_or(0.0)
-}
-
-#[tauri::command]
-#[specta::specta]
-#[tracing::instrument(skip(app, editor_instance))]
-pub async fn add_audio_library_track(
-    app: AppHandle,
-    editor_instance: WindowEditorInstance,
-    id: String,
-) -> Result {
-    let (_, name) = AUDIO_LIBRARY
-        .iter()
-        .find(|(track_id, _)| *track_id == id)
-        .ok_or_else(|| format!("Unknown library track: {id}"))?;
-    let name = (*name).to_string();
-
-    let source = app
-        .path()
-        .resolve(format!("assets/music/{id}.mp3"), BaseDirectory::Resource)
-        .map_err(|e| format!("Failed to resolve bundled track: {e}"))?;
-
-    let project_path = editor_instance.project_path.clone();
-
-    tokio::task::spawn_blocking(move || {
-        let audio_dir = project_path.join("assets").join("audio");
-        std::fs::create_dir_all(&audio_dir)
-            .map_err(|e| format!("Failed to create audio directory: {e}"))?;
-
-        // Stable name so re-adding a library track reuses the existing copy.
-        let dest_name = format!("library-{id}.mp3");
-        let dest = audio_dir.join(&dest_name);
-
-        if !dest.exists() {
-            std::fs::copy(&source, &dest).map_err(|e| {
-                format!(
-                    "Failed to copy bundled track from {}: {e}",
-                    source.display()
-                )
-            })?;
-        }
-
-        Ok(ImportedAudioTrack {
-            path: format!("assets/audio/{dest_name}"),
-            name,
-            duration: probe_duration(&dest),
-        })
-    })
-    .await
-    .map_err(|e| format!("Audio import task failed: {e}"))?
-}
-
-#[tauri::command]
-#[specta::specta]
-#[tracing::instrument(skip(editor_instance))]
-pub async fn import_audio_track_file(
-    editor_instance: WindowEditorInstance,
-    source_path: String,
-) -> Result {
-    let source = PathBuf::from(&source_path);
-
-    let extension = source
-        .extension()
-        .and_then(|ext| ext.to_str())
-        .map(|ext| ext.to_lowercase())
-        .ok_or_else(|| "Audio file has no extension".to_string())?;
-
-    if !AUDIO_IMPORT_EXTENSIONS.contains(&extension.as_str()) {
-        return Err(format!("Unsupported audio format: .{extension}"));
-    }
-
-    let display_name = source
-        .file_stem()
-        .and_then(|stem| stem.to_str())
-        .unwrap_or("Audio")
-        .to_string();
-
-    let project_path = editor_instance.project_path.clone();
-
-    tokio::task::spawn_blocking(move || {
-        if !source.exists() {
-            return Err(format!("Audio file not found: {}", source.display()));
-        }
-
-        let audio_dir = project_path.join("assets").join("audio");
-        std::fs::create_dir_all(&audio_dir)
-            .map_err(|e| format!("Failed to create audio directory: {e}"))?;
-
-        let dest_name = format!("{}.{extension}", uuid::Uuid::new_v4());
-        let dest = audio_dir.join(&dest_name);
-        std::fs::copy(&source, &dest).map_err(|e| format!("Failed to copy audio file: {e}"))?;
-
-        Ok(ImportedAudioTrack {
-            path: format!("assets/audio/{dest_name}"),
-            name: display_name,
-            duration: probe_duration(&dest),
-        })
-    })
-    .await
-    .map_err(|e| format!("Audio import task failed: {e}"))?
-}
diff --git a/apps/desktop/src-tauri/src/audio_meter.rs b/apps/desktop/src-tauri/src/audio_meter.rs
deleted file mode 100644
index db477c78d5a..00000000000
--- a/apps/desktop/src-tauri/src/audio_meter.rs
+++ /dev/null
@@ -1,242 +0,0 @@
-use cap_recording::feeds::microphone::MicrophoneSamples;
-use cpal::{SampleFormat, StreamInstant};
-use keyed_priority_queue::KeyedPriorityQueue;
-use serde::{Deserialize, Serialize};
-use std::cmp::Ordering;
-use std::collections::VecDeque;
-use std::time::Duration;
-use tauri::AppHandle;
-use tauri_specta::Event;
-
-const MAX_AMPLITUDE_F32: f64 = (u16::MAX / 2) as f64; // i16 max value
-const ZERO_AMPLITUDE: u16 = 0;
-const MIN_DB: f64 = -96.0;
-
-#[derive(Deserialize, specta::Type, Serialize, tauri_specta::Event, Debug, Clone)]
-pub struct AudioInputLevelChange(f64);
-
-pub fn spawn_event_emitter(
-    app_handle: AppHandle,
-    audio_input_rx: flume::Receiver,
-) {
-    let mut time_window = VolumeMeter::new(0.2);
-    tokio::spawn(async move {
-        while let Ok(samples) = audio_input_rx.recv_async().await {
-            let floats = samples_to_f64(&samples);
-
-            let db = db_fs(floats);
-
-            time_window.push(samples.info.timestamp().capture, db);
-
-            let max = time_window.max();
-
-            AudioInputLevelChange(max).emit(&app_handle).ok();
-        }
-    });
-}
-
-// https://github.com/cgbur/meter/blob/master/src/time_window.rs
-struct VolumeMeter {
-    keep_duration: Duration, // secs
-    maxes: KeyedPriorityQueue,
-    times: VecDeque,
-}
-
-impl VolumeMeter {
-    pub fn new(keep_secs: f32) -> Self {
-        Self {
-            keep_duration: Duration::from_secs_f32(keep_secs),
-            maxes: KeyedPriorityQueue::new(),
-            times: Default::default(),
-        }
-    }
-
-    pub fn push(&mut self, time: StreamInstant, value: f64) {
-        let value = MinNonNan(-value);
-        self.maxes.push(time, value);
-        self.times.push_back(time);
-
-        // The duration-window eviction below stalls permanently when a
-        // device's capture clock is frozen or non-monotonic (duration_since
-        // yields Zero forever or None), and this meter lives for the whole
-        // process; without a hard cap it grows one entry per audio callback
-        // until quit.
-        const MAX_WINDOW_ENTRIES: usize = 512;
-        while self.times.len() > MAX_WINDOW_ENTRIES {
-            // A frozen clock produces duplicate keys that share one `maxes`
-            // entry; only drop that entry once no duplicate remains queued.
-            if let Some(front) = self.times.pop_front()
-                && !self.times.contains(&front)
-            {
-                self.maxes.remove(&front);
-            }
-        }
-
-        while let Some(time) = self
-            .times
-            .back()
-            .unwrap()
-            .duration_since(self.times.front().unwrap())
-        {
-            if time > self.keep_duration {
-                self.maxes.remove(self.times.front().unwrap());
-                self.times.pop_front();
-            } else {
-                break;
-            }
-
-            if self.times.len() <= 1 {
-                break;
-            }
-        }
-    }
-
-    pub fn max(&self) -> f64 {
-        -self.maxes.peek().map(|(_, db)| db.0).unwrap_or(-MIN_DB)
-    }
-}
-
-#[derive(PartialEq)]
-struct MinNonNan(f64);
-
-impl Eq for MinNonNan {}
-
-#[allow(clippy::non_canonical_partial_ord_impl)]
-impl PartialOrd for MinNonNan {
-    fn partial_cmp(&self, other: &Self) -> Option {
-        other.0.partial_cmp(&self.0)
-    }
-}
-
-impl Ord for MinNonNan {
-    fn cmp(&self, other: &MinNonNan) -> Ordering {
-        self.partial_cmp(other).unwrap()
-    }
-}
-
-use cpal::Sample;
-
-fn db_fs(data: impl Iterator) -> f64 {
-    let max = data
-        .map(|f| f.to_sample::().unsigned_abs())
-        .max()
-        .unwrap_or(ZERO_AMPLITUDE);
-
-    (20.0 * (max as f64 / MAX_AMPLITUDE_F32).log10()).clamp(MIN_DB, 0.0)
-}
-
-fn samples_to_f64(samples: &MicrophoneSamples) -> impl Iterator + use<'_> {
-    samples
-        .data
-        .chunks(samples.format.sample_size())
-        .map(|data| sample_to_f64(data, samples.format))
-}
-
-fn sample_to_f64(data: &[u8], format: SampleFormat) -> f64 {
-    match format {
-        SampleFormat::I8 => i8::from_ne_bytes([data[0]]) as f64 / i8::MAX as f64,
-        SampleFormat::U8 => u8::from_ne_bytes([data[0]]).to_sample::(),
-        SampleFormat::I16 => i16::from_ne_bytes([data[0], data[1]]) as f64 / i16::MAX as f64,
-        SampleFormat::U16 => u16::from_ne_bytes([data[0], data[1]]).to_sample::(),
-        SampleFormat::I32 => {
-            i32::from_ne_bytes([data[0], data[1], data[2], data[3]]) as f64 / i32::MAX as f64
-        }
-        SampleFormat::U32 => {
-            u32::from_ne_bytes([data[0], data[1], data[2], data[3]]).to_sample::()
-        }
-        SampleFormat::U64 => u64::from_ne_bytes([
-            data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
-        ])
-        .to_sample::(),
-        SampleFormat::I64 => {
-            i64::from_ne_bytes([
-                data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
-            ]) as f64
-                / i64::MAX as f64
-        }
-        SampleFormat::F32 => f32::from_ne_bytes([data[0], data[1], data[2], data[3]]) as f64,
-        SampleFormat::F64 => f64::from_ne_bytes([
-            data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
-        ]),
-        _ => 0.0,
-    }
-}
-
-#[cfg(test)]
-mod sample_tests {
-    use super::*;
-
-    #[test]
-    fn unsigned_equilibrium_is_silent() {
-        let cases = [
-            (SampleFormat::U8, 128u8.to_ne_bytes().to_vec()),
-            (SampleFormat::U16, 32768u16.to_ne_bytes().to_vec()),
-            (SampleFormat::U32, (1u32 << 31).to_ne_bytes().to_vec()),
-            (SampleFormat::U64, (1u64 << 63).to_ne_bytes().to_vec()),
-        ];
-        for (format, bytes) in cases {
-            assert_eq!(sample_to_f64(&bytes, format), 0.0, "{format:?}");
-        }
-    }
-
-    #[test]
-    fn unsigned_negative_peaks_are_full_scale() {
-        for format in [
-            SampleFormat::U8,
-            SampleFormat::U16,
-            SampleFormat::U32,
-            SampleFormat::U64,
-        ] {
-            assert_eq!(sample_to_f64(&[0; 8], format), -1.0, "{format:?}");
-        }
-    }
-
-    #[test]
-    fn unsigned_samples_preserve_both_sides_of_equilibrium() {
-        assert_eq!(sample_to_f64(&[64], SampleFormat::U8), -0.5);
-        assert_eq!(sample_to_f64(&[192], SampleFormat::U8), 0.5);
-    }
-
-    #[test]
-    fn unsigned_microphone_silence_has_minimum_level() {
-        assert_eq!(
-            db_fs(std::iter::once(sample_to_f64(&[128], SampleFormat::U8))),
-            MIN_DB
-        );
-        assert_eq!(
-            db_fs(std::iter::once(sample_to_f64(&[0], SampleFormat::U8))),
-            0.0
-        );
-    }
-
-    #[test]
-    fn signed_and_float_samples_keep_existing_levels() {
-        let cases = [
-            (
-                SampleFormat::I8,
-                63i8.to_ne_bytes().to_vec(),
-                63.0 / i8::MAX as f64,
-            ),
-            (
-                SampleFormat::I16,
-                16383i16.to_ne_bytes().to_vec(),
-                16383.0 / i16::MAX as f64,
-            ),
-            (
-                SampleFormat::I32,
-                123456i32.to_ne_bytes().to_vec(),
-                123456.0 / i32::MAX as f64,
-            ),
-            (
-                SampleFormat::I64,
-                123456i64.to_ne_bytes().to_vec(),
-                123456.0 / i64::MAX as f64,
-            ),
-            (SampleFormat::F32, 0.5f32.to_ne_bytes().to_vec(), 0.5),
-            (SampleFormat::F64, 0.5f64.to_ne_bytes().to_vec(), 0.5),
-        ];
-        for (format, bytes, expected) in cases {
-            assert_eq!(sample_to_f64(&bytes, format), expected, "{format:?}");
-        }
-    }
-}
diff --git a/apps/desktop/src-tauri/src/auth.rs b/apps/desktop/src-tauri/src/auth.rs
deleted file mode 100644
index 5ae16506dba..00000000000
--- a/apps/desktop/src-tauri/src/auth.rs
+++ /dev/null
@@ -1,131 +0,0 @@
-use serde::{Deserialize, Serialize};
-use serde_json::json;
-use specta::Type;
-use tauri::{AppHandle, Runtime};
-use tauri_plugin_store::StoreExt;
-
-use web_api::ManagerExt;
-
-use crate::{
-    api::{self, Organization},
-    web_api,
-};
-
-#[derive(Serialize, Deserialize, Type, Debug)]
-pub struct AuthStore {
-    pub secret: AuthSecret,
-    pub user_id: Option,
-    pub plan: Option,
-    #[serde(default)]
-    pub organizations: Vec,
-    #[serde(default)]
-    pub organizations_updated_at: Option,
-}
-
-#[derive(Serialize, Deserialize, Type, Debug)]
-#[serde(untagged)]
-pub enum AuthSecret {
-    ApiKey { api_key: String },
-    Session { token: String, expires: i32 },
-}
-
-#[derive(Serialize, Deserialize, Type, Debug)]
-pub struct Plan {
-    pub upgraded: bool,
-    pub manual: bool,
-    pub last_checked: i32,
-}
-
-impl AuthStore {
-    pub fn load(app: &AppHandle) -> Result, String> {
-        let Some(store) = app
-            .store("store")
-            .map(|s| s.get("auth"))
-            .map_err(|e| e.to_string())?
-        else {
-            return Ok(None);
-        };
-
-        serde_json::from_value(store).map_err(|e| e.to_string())
-    }
-
-    pub fn get(app: &AppHandle) -> Result, String> {
-        let Ok(Some(store)) = app.store("store").map(|s| s.get("auth")) else {
-            return Ok(None);
-        };
-
-        serde_json::from_value(store).map_err(|e| e.to_string())
-    }
-
-    pub async fn update_auth_plan(app: &AppHandle) -> Result<(), String> {
-        let auth = Self::get(app)?;
-        let Some(auth) = auth else {
-            return Err("User not authenticated".to_string());
-        };
-
-        if let Some(plan) = &auth.plan
-            && plan.manual
-        {
-            return Ok(());
-        }
-
-        let mut auth = auth;
-
-        match app
-            .authed_api_request("/api/desktop/plan", |client, url| client.get(url))
-            .await
-        {
-            Ok(response) if response.status().is_success() => {
-                #[derive(Deserialize)]
-                struct PlanResponse {
-                    upgraded: bool,
-                }
-                match response.json::().await {
-                    Ok(plan_response) => {
-                        auth.plan = Some(Plan {
-                            upgraded: plan_response.upgraded,
-                            last_checked: chrono::Utc::now().timestamp() as i32,
-                            manual: auth.plan.as_ref().is_some_and(|p| p.manual),
-                        });
-                    }
-                    Err(e) => tracing::warn!("Failed to parse plan response: {e}"),
-                }
-            }
-            Ok(response) => tracing::warn!("Plan fetch returned {}", response.status()),
-            Err(e) => tracing::warn!("Failed to fetch plan: {e}"),
-        }
-
-        match api::fetch_organizations(app).await {
-            Ok(orgs) => {
-                auth.organizations = orgs;
-                auth.organizations_updated_at = Some(chrono::Utc::now().timestamp() as i32);
-            }
-            Err(e) => {
-                tracing::warn!("Failed to fetch organizations: {e}");
-                if auth.organizations.is_empty() {
-                    auth.organizations_updated_at = Some(chrono::Utc::now().timestamp() as i32);
-                }
-            }
-        }
-
-        Self::set(app, Some(auth))?;
-
-        Ok(())
-    }
-
-    pub fn is_upgraded(&self) -> bool {
-        match &self.plan {
-            Some(plan) => plan.upgraded || plan.manual,
-            None => false,
-        }
-    }
-
-    pub fn set(app: &AppHandle, value: Option) -> Result<(), String> {
-        let Ok(store) = app.store("store") else {
-            return Err("Store not found".to_string());
-        };
-
-        store.set("auth", json!(value));
-        store.save().map_err(|e| e.to_string())
-    }
-}
diff --git a/apps/desktop/src-tauri/src/automation.rs b/apps/desktop/src-tauri/src/automation.rs
deleted file mode 100644
index dc58a5d92e5..00000000000
--- a/apps/desktop/src-tauri/src/automation.rs
+++ /dev/null
@@ -1,1022 +0,0 @@
-use cap_automation::{
-    AutomationExportCompression, AutomationHost, AutomationRecordingMode, AutomationsStore,
-    Capability, CaptureTargetKind, ClipboardSource, ExportDestination, ExportFormat, ExportProfile,
-    Trigger, TriggerContext, sanitize_filename_component,
-};
-use cap_recording::sources::screen_capture::ScreenCaptureTarget;
-#[cfg(not(target_os = "linux"))]
-use clipboard_rs::Clipboard;
-use clipboard_rs::common::RustImage;
-use serde_json::json;
-use std::collections::HashMap;
-use std::path::{Path, PathBuf};
-use std::sync::Arc;
-use tauri::{AppHandle, Manager, Wry};
-use tauri_plugin_store::StoreExt;
-use tokio::sync::RwLock;
-use tracing::{error, info, warn};
-
-use crate::ClipboardContext;
-use crate::general_settings::PostStudioRecordingBehaviour;
-
-const WEBHOOK_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
-const COMMAND_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(300);
-
-#[derive(Debug, PartialEq, Eq)]
-enum ClipboardImageSource {
-    File(PathBuf),
-    ScreenshotProject(PathBuf),
-}
-
-fn resolve_clipboard_image_source(
-    ctx: &TriggerContext,
-    source: ClipboardSource,
-) -> Result {
-    match source {
-        ClipboardSource::Raw => ctx
-            .image_path
-            .as_ref()
-            .or(ctx.output_path.as_ref())
-            .cloned()
-            .map(ClipboardImageSource::File)
-            .ok_or_else(|| "No image or output path available for clipboard copy".to_string()),
-        ClipboardSource::Rendered => {
-            if let Some(path) = ctx.output_path.clone() {
-                return Ok(ClipboardImageSource::File(path));
-            }
-            if ctx.image_path.is_some()
-                && let Some(path) = ctx.project_path.clone()
-            {
-                return Ok(ClipboardImageSource::ScreenshotProject(path));
-            }
-            ctx.image_path
-                .clone()
-                .map(ClipboardImageSource::File)
-                .ok_or_else(|| "No rendered output available for clipboard copy".to_string())
-        }
-    }
-}
-
-pub struct DesktopAutomationHost {
-    app: AppHandle,
-    clipboard: Arc>,
-}
-
-impl DesktopAutomationHost {
-    pub fn new(app: AppHandle, clipboard: Arc>) -> Self {
-        Self { app, clipboard }
-    }
-}
-
-impl AutomationHost for DesktopAutomationHost {
-    fn capabilities(&self) -> &[Capability] {
-        &[
-            Capability::CopyToClipboard,
-            Capability::SaveToLocation,
-            Capability::Export,
-            Capability::Upload,
-            Capability::RevealInFileManager,
-            Capability::OpenFile,
-            Capability::RunCommand,
-            Capability::Webhook,
-            Capability::Notify,
-            Capability::OpenEditor,
-            Capability::ApplyPreset,
-            Capability::DeleteLocalFiles,
-            #[cfg(any(target_os = "macos", target_os = "windows"))]
-            Capability::RecognizeText,
-        ]
-    }
-
-    async fn copy_to_clipboard(
-        &self,
-        ctx: &TriggerContext,
-        source: &ClipboardSource,
-    ) -> Result<(), String> {
-        let source = resolve_clipboard_image_source(ctx, *source)?;
-        let img_data = match source {
-            ClipboardImageSource::File(path) => {
-                let path = path.to_string_lossy().to_string();
-                info!(%path, "Automation: copying file to clipboard");
-                clipboard_rs::RustImageData::from_path(&path)
-                    .map_err(|e| format!("Failed to load image for clipboard: {e}"))?
-            }
-            ClipboardImageSource::ScreenshotProject(path) => {
-                info!(project = %path.display(), "Automation: rendering screenshot for clipboard");
-                let rendered = crate::screenshot_editor::render_screenshot_project_for_export(
-                    self.app.clone(),
-                    path,
-                )
-                .await?;
-                clipboard_rs::RustImageData::from_bytes(&rendered.image_bytes)
-                    .map_err(|e| format!("Failed to load rendered screenshot for clipboard: {e}"))?
-            }
-        };
-
-        self.clipboard
-            .write()
-            .await
-            .set_image(img_data)
-            .map_err(|e| format!("Failed to set clipboard image: {e}"))?;
-
-        Ok(())
-    }
-
-    async fn save_to_location(
-        &self,
-        ctx: &TriggerContext,
-        dir: &str,
-        filename_template: Option<&str>,
-    ) -> Result<(), String> {
-        let src = ctx
-            .image_path
-            .as_ref()
-            .or(ctx.output_path.as_ref())
-            .ok_or("No file path available for save")?;
-
-        let filename = if let Some(tmpl) = filename_template {
-            apply_filename_template(tmpl, ctx)
-        } else {
-            src.file_name()
-                .map(|n| n.to_string_lossy().to_string())
-                .unwrap_or_else(|| "capture.png".to_string())
-        };
-
-        let dst = PathBuf::from(dir).join(&filename);
-        info!(src = %src.display(), dst = %dst.display(), "Automation: saving to location");
-
-        if let Some(parent) = dst.parent() {
-            tokio::fs::create_dir_all(parent)
-                .await
-                .map_err(|e| format!("Failed to create directory: {e}"))?;
-        }
-
-        tokio::fs::copy(src, &dst)
-            .await
-            .map_err(|e| format!("Failed to copy file: {e}"))?;
-
-        Ok(())
-    }
-
-    async fn export(
-        &self,
-        ctx: &TriggerContext,
-        profile: &ExportProfile,
-        destination: &ExportDestination,
-    ) -> Result<(), String> {
-        let project_path = ctx
-            .project_path
-            .as_ref()
-            .ok_or("No project path available for export")?;
-
-        info!(
-            project = %project_path.display(),
-            format = ?profile.format,
-            "Automation: exporting"
-        );
-
-        let settings = build_desktop_export_settings(profile);
-
-        let output_path = match destination {
-            ExportDestination::ProjectFolder => None,
-            ExportDestination::CustomPath { dir } => {
-                let ext = match profile.format {
-                    ExportFormat::Mp4 => "mp4",
-                    ExportFormat::Gif => "gif",
-                    ExportFormat::Mov => "mov",
-                };
-                let name = project_path
-                    .file_stem()
-                    .map(|s| s.to_string_lossy().to_string())
-                    .unwrap_or_else(|| "export".to_string());
-                Some(PathBuf::from(dir).join(format!("{name}.{ext}")))
-            }
-        };
-
-        let mut builder = cap_export::ExporterBase::builder(project_path.clone());
-
-        if let Some(ref out) = output_path {
-            builder = builder.with_output_path(out.clone());
-        }
-
-        let base = builder.build().await.map_err(|e| format!("{e}"))?;
-
-        let result_path = match settings {
-            crate::export::ExportSettings::Mp4(s) => s.export(base, |_| true).await,
-            crate::export::ExportSettings::Gif(s) => s.export(base, |_| true).await,
-            crate::export::ExportSettings::Mov(s) => s.export(base, |_| true).await,
-        }
-        .map_err(|e| format!("Export failed: {e}"))?;
-
-        info!(output = %result_path.display(), "Automation: export complete");
-        Ok(())
-    }
-
-    async fn upload(
-        &self,
-        ctx: &TriggerContext,
-        organization_id: Option<&str>,
-        copy_link: bool,
-        open_in_browser: bool,
-    ) -> Result<(), String> {
-        let link = if let Some(image_path) = ctx.image_path.as_ref() {
-            info!(path = %image_path.display(), "Automation: uploading screenshot");
-            let meta = ctx
-                .project_path
-                .as_ref()
-                .or(Some(image_path))
-                .and_then(|path| crate::load_screenshot_project_meta(path).ok());
-            let existing_video_id = meta
-                .as_ref()
-                .and_then(|(_, meta)| meta.sharing.as_ref().map(|sharing| sharing.id.clone()));
-            let uploaded = crate::upload::upload_screenshot_file(
-                &self.app,
-                image_path.clone(),
-                existing_video_id,
-                organization_id.map(str::to_string),
-            )
-            .await
-            .map_err(|e| format!("Upload failed: {e}"))?;
-
-            if let Some((project_path, meta)) = meta {
-                let _ = crate::save_screenshot_sharing(&project_path, meta, &uploaded, None);
-            }
-
-            uploaded.link
-        } else if let Some(existing) = ctx.share_link.as_ref() {
-            info!(link = %existing, "Automation: recording already uploaded, reusing existing link");
-            existing.clone()
-        } else if let Some(project_path) = ctx.project_path.as_ref() {
-            info!(path = %project_path.display(), "Automation: uploading recording");
-            let channel = tauri::ipc::Channel::new(|_| Ok(()));
-            let result = crate::upload_exported_video(
-                self.app.clone(),
-                project_path.clone(),
-                crate::UploadMode::Initial {
-                    pre_created_video: None,
-                },
-                channel,
-                organization_id.map(|s| s.to_string()),
-            )
-            .await?;
-
-            match result {
-                crate::UploadResult::Success(link) => link,
-                crate::UploadResult::NotAuthenticated => {
-                    return Err("Not authenticated for upload".to_string());
-                }
-                crate::UploadResult::UpgradeRequired => {
-                    return Err("Upgrade required for upload".to_string());
-                }
-                crate::UploadResult::PlanCheckFailed => {
-                    return Err("Plan check failed for upload".to_string());
-                }
-            }
-        } else {
-            return Err("No image or project path available for upload".to_string());
-        };
-
-        if copy_link {
-            self.clipboard
-                .write()
-                .await
-                .set_text(link.clone())
-                .map_err(|e| format!("Failed to copy link: {e}"))?;
-        }
-
-        if open_in_browser {
-            let _ = crate::open_external_link(self.app.clone(), link.clone());
-        }
-
-        Ok(())
-    }
-
-    async fn reveal_in_file_manager(&self, ctx: &TriggerContext) -> Result<(), String> {
-        let path = ctx
-            .image_path
-            .as_ref()
-            .or(ctx.output_path.as_ref())
-            .or(ctx.project_path.as_ref())
-            .ok_or("No path available to reveal")?;
-
-        reveal_path(path)
-    }
-
-    async fn open_file(&self, ctx: &TriggerContext) -> Result<(), String> {
-        use tauri_plugin_opener::OpenerExt;
-
-        let path = ctx
-            .image_path
-            .as_ref()
-            .or(ctx.output_path.as_ref())
-            .ok_or("No file path available to open")?;
-
-        let path_str = path.to_str().ok_or("Invalid path")?;
-        self.app
-            .opener()
-            .open_path(path_str, None::)
-            .map_err(|e| format!("Failed to open file: {e}"))?;
-
-        Ok(())
-    }
-
-    async fn run_command(
-        &self,
-        ctx: &TriggerContext,
-        program: &str,
-        args: &[String],
-        cwd: Option<&str>,
-        env: &HashMap,
-        use_shell: bool,
-    ) -> Result<(), String> {
-        info!(program, "Automation: running command");
-
-        let mut cmd = if use_shell {
-            let shell_line = cap_automation::shell_command_line(program, args);
-
-            #[cfg(target_os = "windows")]
-            let mut c = tokio::process::Command::new("cmd");
-            #[cfg(target_os = "windows")]
-            c.args(["/C", &shell_line]);
-
-            #[cfg(not(target_os = "windows"))]
-            let mut c = tokio::process::Command::new("sh");
-            #[cfg(not(target_os = "windows"))]
-            c.args(["-c", &shell_line]);
-
-            c
-        } else {
-            let mut c = tokio::process::Command::new(program);
-            c.args(args);
-            c
-        };
-
-        if let Some(dir) = cwd {
-            cmd.current_dir(dir);
-        }
-
-        for (k, v) in env {
-            cmd.env(k, v);
-        }
-
-        if let Some(ref p) = ctx.project_path {
-            cmd.env("CAP_PROJECT_PATH", p);
-        }
-        if let Some(ref p) = ctx.image_path {
-            cmd.env("CAP_IMAGE_PATH", p);
-        }
-        if let Some(ref p) = ctx.output_path {
-            cmd.env("CAP_OUTPUT_PATH", p);
-        }
-        if let Some(ref l) = ctx.share_link {
-            cmd.env("CAP_SHARE_LINK", l);
-        }
-
-        // Kill the child if the timeout drops the future, so a hung command can't outlive the run.
-        cmd.kill_on_drop(true);
-        let output = tokio::time::timeout(COMMAND_TIMEOUT, cmd.output())
-            .await
-            .map_err(|_| format!("Command timed out after {}s", COMMAND_TIMEOUT.as_secs()))?
-            .map_err(|e| format!("Failed to run command: {e}"))?;
-
-        if !output.status.success() {
-            let stderr = String::from_utf8_lossy(&output.stderr);
-            return Err(format!("Command exited with {}: {}", output.status, stderr));
-        }
-
-        Ok(())
-    }
-
-    async fn webhook(
-        &self,
-        ctx: &TriggerContext,
-        url: &str,
-        method: &str,
-        headers: &HashMap,
-        body_template: Option<&str>,
-    ) -> Result<(), String> {
-        info!(url, method, "Automation: sending webhook");
-
-        let client = reqwest::Client::builder()
-            .timeout(WEBHOOK_TIMEOUT)
-            .build()
-            .map_err(|e| format!("Failed to build HTTP client: {e}"))?;
-        let method = method
-            .parse::()
-            .map_err(|e| format!("Invalid HTTP method: {e}"))?;
-
-        let body = if let Some(tmpl) = body_template {
-            apply_body_template(tmpl, ctx)
-        } else {
-            serde_json::to_string(&serde_json::json!({
-                "project_path": ctx.project_path,
-                "image_path": ctx.image_path,
-                "output_path": ctx.output_path,
-                "share_link": ctx.share_link,
-            }))
-            .map_err(|e| format!("Failed to serialize webhook body: {e}"))?
-        };
-
-        let mut req = client.request(method, url).body(body);
-        for (k, v) in headers {
-            req = req.header(k, v);
-        }
-
-        let resp = req
-            .send()
-            .await
-            .map_err(|e| format!("Webhook request failed: {e}"))?;
-
-        if !resp.status().is_success() {
-            return Err(format!("Webhook returned status {}", resp.status()));
-        }
-
-        Ok(())
-    }
-
-    async fn recognize_text_to_clipboard(&self, ctx: &TriggerContext) -> Result<(), String> {
-        let path = ctx
-            .image_path
-            .as_ref()
-            .or(ctx.output_path.as_ref())
-            .ok_or("No image path available for OCR")?;
-
-        info!(path = %path.display(), "Automation: recognizing text");
-
-        let text = crate::screenshot_editor::recognize_text_from_image_path(path).await?;
-
-        if text.trim().is_empty() {
-            return Err("No text recognized in image".to_string());
-        }
-
-        self.clipboard
-            .write()
-            .await
-            .set_text(text)
-            .map_err(|e| format!("Failed to set clipboard text: {e}"))?;
-
-        Ok(())
-    }
-
-    async fn notify(
-        &self,
-        ctx: &TriggerContext,
-        title_template: &str,
-        body_template: &str,
-    ) -> Result<(), String> {
-        #[cfg(not(target_os = "linux"))]
-        use tauri_plugin_notification::NotificationExt;
-
-        let enabled = crate::general_settings::GeneralSettingsStore::get(&self.app)
-            .map(|s| s.is_some_and(|s| s.enable_notifications))
-            .unwrap_or(false);
-
-        if !enabled {
-            return Ok(());
-        }
-
-        let title = apply_body_template(&apply_filename_template(title_template, ctx), ctx);
-        let body = apply_body_template(&apply_filename_template(body_template, ctx), ctx);
-
-        #[cfg(target_os = "linux")]
-        crate::notifications::show_linux_notification(&title, &body).await?;
-
-        #[cfg(not(target_os = "linux"))]
-        self.app
-            .notification()
-            .builder()
-            .title(title)
-            .body(body)
-            .show()
-            .map_err(|e| format!("Failed to send notification: {e}"))?;
-
-        Ok(())
-    }
-
-    async fn open_editor(&self, ctx: &TriggerContext) -> Result<(), String> {
-        if let Some(image_path) = ctx.image_path.as_ref() {
-            let _ = crate::windows::ShowCapWindow::ScreenshotEditor {
-                path: image_path.clone(),
-            }
-            .show(&self.app)
-            .await;
-            return Ok(());
-        }
-
-        let path = ctx
-            .project_path
-            .as_ref()
-            .ok_or("No project path for editor")?;
-
-        let _ = crate::windows::ShowCapWindow::Editor {
-            project_path: path.clone(),
-        }
-        .show(&self.app)
-        .await;
-
-        Ok(())
-    }
-
-    async fn apply_preset(&self, ctx: &TriggerContext, name: &str) -> Result<(), String> {
-        let project_path = ctx
-            .project_path
-            .as_ref()
-            .ok_or("No project path for preset")?;
-
-        let preset = crate::presets::PresetsStore::get_by_name(&self.app, name)?
-            .ok_or_else(|| format!("Preset '{name}' not found"))?;
-
-        info!(preset = name, project = %project_path.display(), "Automation: applying preset");
-
-        let existing_timeline = cap_project::ProjectConfiguration::load(project_path)
-            .ok()
-            .and_then(|c| c.timeline);
-
-        let mut config = preset.config;
-        if config.timeline.is_none() {
-            config.timeline = existing_timeline;
-        }
-
-        config
-            .write(project_path)
-            .map_err(|e| format!("Failed to write project config: {e}"))?;
-
-        Ok(())
-    }
-
-    async fn delete_local_files(&self, ctx: &TriggerContext) -> Result<(), String> {
-        let path = ctx
-            .project_path
-            .as_ref()
-            .ok_or("No project path for deletion")?;
-
-        info!(path = %path.display(), "Automation: deleting local files");
-        tokio::fs::remove_dir_all(path)
-            .await
-            .map_err(|e| format!("Failed to delete: {e}"))?;
-
-        Ok(())
-    }
-}
-
-fn reveal_path(path: &Path) -> Result<(), String> {
-    let path_str = path.to_str().ok_or("Invalid path")?;
-
-    #[cfg(target_os = "macos")]
-    {
-        std::process::Command::new("open")
-            .arg("-R")
-            .arg(path_str)
-            .spawn()
-            .map_err(|e| format!("Failed to reveal: {e}"))?;
-    }
-
-    #[cfg(target_os = "windows")]
-    {
-        std::process::Command::new("explorer")
-            .args(["/select,", path_str])
-            .spawn()
-            .map_err(|e| format!("Failed to reveal: {e}"))?;
-    }
-
-    #[cfg(target_os = "linux")]
-    {
-        let parent = path.parent().and_then(|p| p.to_str()).unwrap_or(path_str);
-        std::process::Command::new("xdg-open")
-            .arg(parent)
-            .spawn()
-            .map_err(|e| format!("Failed to reveal: {e}"))?;
-    }
-
-    Ok(())
-}
-
-fn build_desktop_export_settings(profile: &ExportProfile) -> crate::export::ExportSettings {
-    let compression = profile
-        .compression
-        .map(|c| match c {
-            AutomationExportCompression::Maximum => cap_export::mp4::ExportCompression::Maximum,
-            AutomationExportCompression::Social => cap_export::mp4::ExportCompression::Social,
-            AutomationExportCompression::Web => cap_export::mp4::ExportCompression::Web,
-            AutomationExportCompression::Potato => cap_export::mp4::ExportCompression::Potato,
-        })
-        .unwrap_or(cap_export::mp4::ExportCompression::Web);
-
-    match profile.format {
-        ExportFormat::Mp4 => {
-            crate::export::ExportSettings::Mp4(cap_export::mp4::Mp4ExportSettings {
-                fps: profile.fps,
-                resolution_base: profile.resolution_base,
-                compression,
-                custom_bpp: None,
-                force_ffmpeg_decoder: false,
-                optimize_filesize: false,
-            })
-        }
-        ExportFormat::Gif => {
-            crate::export::ExportSettings::Gif(cap_export::gif::GifExportSettings {
-                fps: profile.fps,
-                resolution_base: profile.resolution_base,
-                quality: None,
-            })
-        }
-        ExportFormat::Mov => {
-            crate::export::ExportSettings::Mov(cap_export::mov::MovExportSettings {
-                fps: profile.fps,
-                resolution_base: profile.resolution_base,
-                cursor_only: false,
-            })
-        }
-    }
-}
-
-fn apply_filename_template(template: &str, ctx: &TriggerContext) -> String {
-    let now = chrono::Local::now();
-    let mut result = template.to_string();
-    result = result.replace("{date}", &now.format("%Y-%m-%d").to_string());
-    result = result.replace("{time}", &now.format("%H-%M-%S").to_string());
-    result = result.replace("{datetime}", &now.format("%Y-%m-%d_%H-%M-%S").to_string());
-    if let Some(ref title) = ctx.window_title {
-        result = result.replace("{window}", &sanitize_filename_component(title));
-    }
-    result
-}
-
-fn apply_body_template(template: &str, ctx: &TriggerContext) -> String {
-    let mut result = template.to_string();
-    if let Some(ref p) = ctx.project_path {
-        result = result.replace("{project_path}", &p.to_string_lossy());
-    }
-    if let Some(ref p) = ctx.image_path {
-        result = result.replace("{image_path}", &p.to_string_lossy());
-    }
-    if let Some(ref p) = ctx.output_path {
-        result = result.replace("{output_path}", &p.to_string_lossy());
-    }
-    if let Some(ref l) = ctx.share_link {
-        result = result.replace("{share_link}", l);
-    }
-    result
-}
-
-pub fn capture_target_kind(target: &ScreenCaptureTarget) -> Option {
-    match target {
-        ScreenCaptureTarget::Window { .. } => Some(CaptureTargetKind::Window),
-        ScreenCaptureTarget::Display { .. } => Some(CaptureTargetKind::Display),
-        ScreenCaptureTarget::Area { .. } => Some(CaptureTargetKind::Area),
-        ScreenCaptureTarget::CameraOnly => None,
-    }
-}
-
-fn build_host(app: &AppHandle) -> Option {
-    let clipboard = app
-        .try_state::>>()
-        .map(|s| s.inner().clone())?;
-    Some(DesktopAutomationHost::new(app.clone(), clipboard))
-}
-
-pub async fn run_trigger(app: &AppHandle, trigger: Trigger, ctx: TriggerContext) {
-    let store = match get_store(app) {
-        Ok(Some(store)) => store,
-        Ok(None) => return,
-        Err(e) => {
-            error!("Failed to load automations store: {e}");
-            return;
-        }
-    };
-
-    if store.rules.is_empty() {
-        return;
-    }
-
-    let Some(host) = build_host(app) else {
-        warn!("Automation host unavailable (clipboard state missing)");
-        return;
-    };
-
-    let results = cap_automation::run(&host, &store, &trigger, &ctx).await;
-    for result in &results {
-        for action in &result.action_results {
-            if let Some(error) = &action.error {
-                warn!(
-                    rule_id = %result.rule_id,
-                    error = %error,
-                    "Automation action did not complete"
-                );
-            }
-        }
-    }
-}
-
-pub fn should_open_screenshot_editor(app: &AppHandle, target: &ScreenCaptureTarget) -> bool {
-    let store = match get_store(app) {
-        Ok(Some(store)) => store,
-        _ => return true,
-    };
-
-    if store.rules.is_empty() {
-        return true;
-    }
-
-    let mut ctx = TriggerContext::new();
-    if let Some(kind) = capture_target_kind(target) {
-        ctx = ctx.with_capture_target(kind);
-    }
-    if let Some(title) = target.title() {
-        ctx = ctx.with_window_title(title);
-    }
-
-    !cap_automation::has_skip_editor(&store, &Trigger::ScreenshotTaken, &ctx)
-}
-
-// `None` means a matching `SkipEditor` rule asked for a headless flow, so the caller must suppress
-// both the editor and the recordings overlay. Automation rules win over the user's default behaviour.
-pub fn studio_recording_editor_behaviour(
-    app: &AppHandle,
-    project_path: &Path,
-    duration_secs: f64,
-    default: PostStudioRecordingBehaviour,
-) -> Option {
-    let store = match get_store(app) {
-        Ok(Some(store)) if !store.rules.is_empty() => store,
-        _ => return Some(default),
-    };
-
-    let mut ctx = TriggerContext::new()
-        .with_project_path(project_path.to_path_buf())
-        .with_recording_mode(AutomationRecordingMode::Studio);
-    if duration_secs > 0.0 {
-        ctx = ctx.with_duration(duration_secs);
-    }
-
-    if cap_automation::has_skip_editor(&store, &Trigger::StudioRecordingFinished, &ctx) {
-        None
-    } else if cap_automation::has_open_editor(&store, &Trigger::StudioRecordingFinished, &ctx) {
-        Some(PostStudioRecordingBehaviour::OpenEditor)
-    } else {
-        Some(default)
-    }
-}
-
-pub fn run_screenshot_automations(
-    app: AppHandle,
-    image_path: PathBuf,
-    target: &ScreenCaptureTarget,
-) {
-    let project_path = image_path.parent().map(Path::to_path_buf);
-    let capture_target = capture_target_kind(target);
-    let window_title = target.title();
-
-    tokio::spawn(async move {
-        let mut ctx = TriggerContext::new().with_image_path(image_path);
-        if let Some(project_path) = project_path {
-            ctx = ctx.with_project_path(project_path);
-        }
-        if let Some(kind) = capture_target {
-            ctx = ctx.with_capture_target(kind);
-        }
-        if let Some(title) = window_title {
-            ctx = ctx.with_window_title(title);
-        }
-
-        run_trigger(&app, Trigger::ScreenshotTaken, ctx).await;
-    });
-}
-
-pub fn run_studio_recording_automations(app: AppHandle, project_path: PathBuf, duration_secs: f64) {
-    tokio::spawn(async move {
-        let mut ctx = TriggerContext::new()
-            .with_project_path(project_path)
-            .with_recording_mode(AutomationRecordingMode::Studio);
-        if duration_secs > 0.0 {
-            ctx = ctx.with_duration(duration_secs);
-        }
-        run_trigger(&app, Trigger::StudioRecordingFinished, ctx).await;
-    });
-}
-
-pub fn run_instant_recording_automations(
-    app: AppHandle,
-    project_path: PathBuf,
-    share_link: Option,
-    share_id: Option,
-) {
-    tokio::spawn(async move {
-        let mut ctx = TriggerContext::new()
-            .with_project_path(project_path)
-            .with_recording_mode(AutomationRecordingMode::Instant);
-        if let Some(link) = share_link {
-            ctx = ctx.with_share_link(link);
-        }
-        if let Some(id) = share_id {
-            ctx = ctx.with_share_id(id);
-        }
-        run_trigger(&app, Trigger::InstantRecordingFinished, ctx).await;
-    });
-}
-
-pub fn run_upload_completed_automations(
-    app: AppHandle,
-    project_path: PathBuf,
-    share_link: Option,
-    share_id: Option,
-) {
-    tokio::spawn(async move {
-        let mut ctx = TriggerContext::new().with_project_path(project_path);
-        if let Some(link) = share_link {
-            ctx = ctx.with_share_link(link);
-        }
-        if let Some(id) = share_id {
-            ctx = ctx.with_share_id(id);
-        }
-        run_trigger(&app, Trigger::UploadCompleted, ctx).await;
-    });
-}
-
-pub fn run_video_imported_automations(app: AppHandle, project_path: PathBuf) {
-    tokio::spawn(async move {
-        let ctx = TriggerContext::new().with_project_path(project_path);
-        run_trigger(&app, Trigger::VideoImported, ctx).await;
-    });
-}
-
-pub fn run_recording_started_automations(app: AppHandle) {
-    tokio::spawn(async move {
-        run_trigger(&app, Trigger::RecordingStarted, TriggerContext::new()).await;
-    });
-}
-
-pub fn run_recording_deleted_automations(app: AppHandle, project_path: PathBuf) {
-    tokio::spawn(async move {
-        let ctx = TriggerContext::new().with_project_path(project_path);
-        run_trigger(&app, Trigger::RecordingDeleted, ctx).await;
-    });
-}
-
-pub fn get_store(app: &AppHandle) -> Result, String> {
-    match app.store("store").map(|s| s.get("automations")) {
-        Ok(Some(store)) => match serde_json::from_value(store) {
-            Ok(settings) => Ok(Some(settings)),
-            Err(e) => {
-                error!("Failed to deserialize automations store: {e}");
-                Ok(None)
-            }
-        },
-        _ => Ok(None),
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn get_automations(app: AppHandle) -> Result {
-    Ok(get_store(&app)?.unwrap_or_default())
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn set_automations(app: AppHandle, store: AutomationsStore) -> Result<(), String> {
-    let tauri_store = app.store("store").map_err(|e| e.to_string())?;
-    tauri_store.set("automations", json!(store));
-    tauri_store.save().map_err(|e| e.to_string())
-}
-
-#[derive(serde::Serialize, specta::Type)]
-#[serde(rename_all = "camelCase")]
-pub struct AutomationActionCheck {
-    pub action_type: String,
-    pub capability: String,
-    pub supported: bool,
-}
-
-#[derive(serde::Serialize, specta::Type)]
-#[serde(rename_all = "camelCase")]
-pub struct AutomationTestReport {
-    pub rule_id: String,
-    pub rule_name: String,
-    pub action_checks: Vec,
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn test_automation(
-    app: AppHandle,
-    rule_id: String,
-) -> Result {
-    let store = get_store(&app)?.unwrap_or_default();
-    let rule = store
-        .rules
-        .iter()
-        .find(|r| r.id == rule_id)
-        .ok_or_else(|| format!("Rule '{rule_id}' not found"))?;
-
-    let clipboard = app
-        .try_state::>>()
-        .map(|s| s.inner().clone());
-
-    let supported: Vec = if let Some(clipboard) = clipboard {
-        let host = DesktopAutomationHost::new(app.clone(), clipboard);
-        host.capabilities().to_vec()
-    } else {
-        Vec::new()
-    };
-
-    let action_checks = rule
-        .actions
-        .iter()
-        .map(|action| {
-            let cap = action.required_capability();
-            AutomationActionCheck {
-                action_type: format!("{action:?}")
-                    .split_whitespace()
-                    .next()
-                    .unwrap_or("Unknown")
-                    .to_string(),
-                capability: cap.map_or_else(|| "None".to_string(), |c| format!("{c:?}")),
-                supported: cap.is_none_or(|c| supported.contains(&c)),
-            }
-        })
-        .collect();
-
-    Ok(AutomationTestReport {
-        rule_id: rule.id.clone(),
-        rule_name: rule.name.clone(),
-        action_checks,
-    })
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn automation_should_open_screenshot_editor(
-    app: AppHandle,
-    target: ScreenCaptureTarget,
-) -> bool {
-    should_open_screenshot_editor(&app, &target)
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn list_automation_capabilities() -> Vec {
-    vec![
-        "CopyToClipboard".to_string(),
-        "SaveToLocation".to_string(),
-        "Export".to_string(),
-        "Upload".to_string(),
-        "RevealInFileManager".to_string(),
-        "OpenFile".to_string(),
-        "RunCommand".to_string(),
-        "Webhook".to_string(),
-        "RecognizeText".to_string(),
-        "Notify".to_string(),
-        "OpenEditor".to_string(),
-        "ApplyPreset".to_string(),
-        "DeleteLocalFiles".to_string(),
-    ]
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn rendered_screenshot_uses_project_instead_of_raw_capture() {
-        let ctx = TriggerContext::new()
-            .with_project_path(PathBuf::from("capture.cap"))
-            .with_image_path(PathBuf::from("capture.cap/original.png"));
-
-        assert_eq!(
-            resolve_clipboard_image_source(&ctx, ClipboardSource::Rendered),
-            Ok(ClipboardImageSource::ScreenshotProject(PathBuf::from(
-                "capture.cap"
-            )))
-        );
-    }
-
-    #[test]
-    fn rendered_output_takes_priority_over_screenshot_project() {
-        let ctx = TriggerContext::new()
-            .with_project_path(PathBuf::from("capture.cap"))
-            .with_image_path(PathBuf::from("capture.cap/original.png"))
-            .with_output_path(PathBuf::from("capture-rendered.png"));
-
-        assert_eq!(
-            resolve_clipboard_image_source(&ctx, ClipboardSource::Rendered),
-            Ok(ClipboardImageSource::File(PathBuf::from(
-                "capture-rendered.png"
-            )))
-        );
-    }
-
-    #[test]
-    fn raw_screenshot_keeps_original_capture() {
-        let ctx = TriggerContext::new()
-            .with_project_path(PathBuf::from("capture.cap"))
-            .with_image_path(PathBuf::from("capture.cap/original.png"));
-
-        assert_eq!(
-            resolve_clipboard_image_source(&ctx, ClipboardSource::Raw),
-            Ok(ClipboardImageSource::File(PathBuf::from(
-                "capture.cap/original.png"
-            )))
-        );
-    }
-}
diff --git a/apps/desktop/src-tauri/src/camera.rs b/apps/desktop/src-tauri/src/camera.rs
deleted file mode 100644
index 350bce064a6..00000000000
--- a/apps/desktop/src-tauri/src/camera.rs
+++ /dev/null
@@ -1,2126 +0,0 @@
-use anyhow::{Context, anyhow};
-#[cfg(not(target_os = "macos"))]
-use cap_recording::FFmpegVideoFrame;
-#[cfg(target_os = "macos")]
-use cap_recording::NativeCameraFrame;
-use cap_recording::feeds::{self, camera::CameraFeed};
-#[cfg(target_os = "macos")]
-use cap_utils::macos_qos::{MacOsQosClass, set_current_thread_qos};
-
-#[cfg(target_os = "macos")]
-use crate::camera_native::{NativeFrameConverter, classify_frame};
-use ffmpeg::{
-    format::{self, Pixel},
-    frame,
-    software::scaling,
-};
-use kameo::actor::ActorRef;
-use serde::{Deserialize, Serialize};
-use specta::Type;
-use std::{
-    sync::{
-        Arc,
-        atomic::{AtomicU64, Ordering},
-    },
-    thread,
-};
-use tauri::{LogicalPosition, LogicalSize, Manager, PhysicalSize, WebviewWindow};
-use tokio::{
-    runtime::Runtime,
-    sync::{broadcast, oneshot},
-    task::LocalSet,
-    time::{Duration, Instant},
-};
-use tracing::{error, info, trace, warn};
-use wgpu::{CompositeAlphaMode, SurfaceTexture};
-
-static TOOLBAR_HEIGHT: f32 = 56.0;
-
-const DEFAULT_SURFACE_SCALE: f64 = 2.0;
-// Quantizing the target texture width stops drag-resizing from rebuilding the
-// scaler, preview texture, and bind group on every 1px size change.
-const CAMERA_PREVIEW_TEXTURE_WIDTH_BUCKET: u32 = 64;
-const CAMERA_PREVIEW_MIN_TEXTURE_WIDTH: u32 = 320;
-const CAMERA_PREVIEW_MAX_TEXTURE_WIDTH: u32 = 960;
-const CAMERA_PREVIEW_MAX_TEXTURE_HEIGHT: u32 = 540;
-const CAMERA_PREVIEW_BLUR_MAX_TEXTURE_WIDTH: u32 = 640;
-const CAMERA_PREVIEW_BLUR_MAX_TEXTURE_HEIGHT: u32 = 360;
-const CAMERA_PREVIEW_TARGET_FRAME_INTERVAL: Duration = Duration::from_micros(16_666);
-const CAMERA_PREVIEW_FRAME_INTERVAL_SLACK: Duration = Duration::from_millis(1);
-const CAMERA_PREVIEW_BLUR_INFERENCE_INTERVAL: Duration = Duration::from_millis(33);
-
-// ── Low-spec preview profile ────────────────────────────────────────────────
-// On low-RAM machines (e.g. an 8GB iMac) the full-quality preview is laggy, so
-// we opt those machines into a cheaper preview: smaller textures, 30fps pacing,
-// and (most importantly) NO background-blur init at all. This is gated by a
-// single startup RAM check (see `init_preview_profile`); on every machine with
-// more than the threshold, `is_low_spec_preview()` returns `false` and the
-// preview path uses the high-spec constants above bit-for-bit, so there is zero
-// behavioural change for >8GB machines. This affects ONLY the preview — the
-// recording pipeline is entirely separate and untouched.
-const CAMERA_PREVIEW_LOW_SPEC_MAX_TEXTURE_WIDTH: u32 = 640;
-const CAMERA_PREVIEW_LOW_SPEC_MAX_TEXTURE_HEIGHT: u32 = 360;
-const CAMERA_PREVIEW_LOW_SPEC_TARGET_FRAME_INTERVAL: Duration = Duration::from_micros(33_333);
-
-/// Machines with total RAM at or below this are treated as low-spec for preview.
-pub const LOW_SPEC_PREVIEW_RAM_THRESHOLD_BYTES: u64 = 8 * 1024 * 1024 * 1024;
-
-static LOW_SPEC_PREVIEW: std::sync::OnceLock = std::sync::OnceLock::new();
-
-/// Detect the preview profile once at startup from the machine's total RAM and
-/// log the result. Subsequent calls are no-ops (the first value wins), so this
-/// is safe to call from a single startup site. Reading via
-/// `is_low_spec_preview()` never touches sysinfo, so there are no per-frame
-/// system queries.
-pub fn init_preview_profile(total_ram_bytes: u64) -> bool {
-    let low_spec = total_ram_bytes <= LOW_SPEC_PREVIEW_RAM_THRESHOLD_BYTES;
-    // Only the first set takes effect; ignore the (impossible in practice)
-    // racing second caller.
-    let _ = LOW_SPEC_PREVIEW.set(low_spec);
-    let active = *LOW_SPEC_PREVIEW.get().unwrap_or(&low_spec);
-    info!(
-        total_ram_mb = total_ram_bytes / 1_048_576,
-        low_spec_preview = active,
-        "Camera preview profile detected"
-    );
-    active
-}
-
-/// Whether the low-spec preview profile is active. Defaults to `false` (the
-/// high-spec / current behaviour) if detection never ran, so any unexpected
-/// ordering can only ever fall back to the existing >8GB behaviour.
-#[inline]
-pub fn is_low_spec_preview() -> bool {
-    *LOW_SPEC_PREVIEW.get().unwrap_or(&false)
-}
-
-pub const MIN_CAMERA_SIZE: f32 = 150.0;
-pub const MAX_CAMERA_SIZE: f32 = 600.0;
-pub const DEFAULT_CAMERA_SIZE: f32 = 230.0;
-pub const WIDE_CAMERA_ASPECT_RATIO: f32 = 16.0 / 9.0;
-
-// On macOS the preview consumes retained CMSampleBuffers and renders them via
-// a zero-copy IOSurface->Metal->wgpu import; everywhere else it consumes the
-// CPU-converted ffmpeg frames.
-#[cfg(target_os = "macos")]
-type PreviewCameraFrame = NativeCameraFrame;
-#[cfg(not(target_os = "macos"))]
-type PreviewCameraFrame = FFmpegVideoFrame;
-
-#[derive(Clone)]
-pub enum CameraPreviewSender {
-    #[cfg(not(target_os = "macos"))]
-    Ffmpeg(flume::Sender),
-    #[cfg(target_os = "macos")]
-    Native(flume::Sender),
-}
-
-impl CameraPreviewSender {
-    fn from_tx(tx: flume::Sender) -> Self {
-        #[cfg(target_os = "macos")]
-        {
-            Self::Native(tx)
-        }
-        #[cfg(not(target_os = "macos"))]
-        {
-            Self::Ffmpeg(tx)
-        }
-    }
-
-    pub async fn attach(&self, feed: &ActorRef) -> Result<(), String> {
-        match self {
-            #[cfg(not(target_os = "macos"))]
-            Self::Ffmpeg(tx) => feed
-                .ask(feeds::camera::AddSender(tx.clone()))
-                .await
-                .map_err(|err| err.to_string()),
-            #[cfg(target_os = "macos")]
-            Self::Native(tx) => feed
-                .ask(feeds::camera::AddNativeSender(tx.clone()))
-                .await
-                .map_err(|err| err.to_string()),
-        }
-    }
-
-    pub async fn detach(&self, feed: &ActorRef) -> Result<(), String> {
-        match self {
-            #[cfg(not(target_os = "macos"))]
-            Self::Ffmpeg(tx) => feed
-                .ask(feeds::camera::RemoveSender(tx.clone()))
-                .await
-                .map_err(|err| err.to_string()),
-            #[cfg(target_os = "macos")]
-            Self::Native(tx) => feed
-                .ask(feeds::camera::RemoveNativeSender(tx.clone()))
-                .await
-                .map_err(|err| err.to_string()),
-        }
-    }
-}
-
-#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize, Type)]
-#[serde(rename_all = "lowercase")]
-pub enum CameraPreviewShape {
-    #[default]
-    Round,
-    Square,
-    Full,
-}
-
-#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
-pub struct CameraPreviewState {
-    pub size: f32,
-    pub shape: CameraPreviewShape,
-    pub mirrored: bool,
-    #[serde(default)]
-    pub background_blur: cap_project::BackgroundBlurMode,
-}
-
-impl Default for CameraPreviewState {
-    fn default() -> Self {
-        Self {
-            size: DEFAULT_CAMERA_SIZE,
-            shape: CameraPreviewShape::default(),
-            mirrored: false,
-            background_blur: cap_project::BackgroundBlurMode::Off,
-        }
-    }
-}
-
-fn clamp_size(size: f32) -> f32 {
-    size.clamp(MIN_CAMERA_SIZE, MAX_CAMERA_SIZE)
-}
-
-fn preferred_alpha_mode(alpha_modes: &[CompositeAlphaMode]) -> CompositeAlphaMode {
-    [
-        CompositeAlphaMode::PreMultiplied,
-        CompositeAlphaMode::PostMultiplied,
-        CompositeAlphaMode::Opaque,
-        CompositeAlphaMode::Auto,
-        CompositeAlphaMode::Inherit,
-    ]
-    .into_iter()
-    .find(|mode| alpha_modes.contains(mode))
-    .or_else(|| alpha_modes.first().copied())
-    .unwrap_or(CompositeAlphaMode::Opaque)
-}
-
-fn camera_preview_frame_due(last_render_at: Option, now: Instant) -> bool {
-    // High-spec keeps the original 60fps target; low-spec paces at 30fps.
-    let target_interval = if is_low_spec_preview() {
-        CAMERA_PREVIEW_LOW_SPEC_TARGET_FRAME_INTERVAL
-    } else {
-        CAMERA_PREVIEW_TARGET_FRAME_INTERVAL
-    };
-    last_render_at.is_none_or(|last| {
-        now.saturating_duration_since(last) + CAMERA_PREVIEW_FRAME_INTERVAL_SLACK >= target_interval
-    })
-}
-
-fn camera_preview_texture_dimensions(
-    source_width: u32,
-    source_height: u32,
-    region_width: u32,
-    region_height: u32,
-    blur_enabled: bool,
-) -> (u32, u32) {
-    let source_width = source_width.max(1);
-    let source_height = source_height.max(1);
-    let region_width = region_width.max(1);
-    let region_height = region_height.max(1);
-    let (max_width, max_height) = if is_low_spec_preview() {
-        // Low-spec caps preview to 640x360 regardless of blur (blur is skipped
-        // entirely on low-spec, so `blur_enabled` is effectively always false
-        // here, but we clamp unconditionally to stay safe if that ever changes).
-        (
-            CAMERA_PREVIEW_LOW_SPEC_MAX_TEXTURE_WIDTH,
-            CAMERA_PREVIEW_LOW_SPEC_MAX_TEXTURE_HEIGHT,
-        )
-    } else if blur_enabled {
-        (
-            CAMERA_PREVIEW_BLUR_MAX_TEXTURE_WIDTH,
-            CAMERA_PREVIEW_BLUR_MAX_TEXTURE_HEIGHT,
-        )
-    } else {
-        (
-            CAMERA_PREVIEW_MAX_TEXTURE_WIDTH,
-            CAMERA_PREVIEW_MAX_TEXTURE_HEIGHT,
-        )
-    };
-    let source_aspect = source_width as f64 / source_height as f64;
-    let cover_width = (region_width as f64).max(region_height as f64 * source_aspect);
-    let requested_width = (cover_width.ceil() as u32)
-        .max(CAMERA_PREVIEW_MIN_TEXTURE_WIDTH)
-        .div_ceil(CAMERA_PREVIEW_TEXTURE_WIDTH_BUCKET)
-        .saturating_mul(CAMERA_PREVIEW_TEXTURE_WIDTH_BUCKET)
-        .min(max_width);
-    let scale = (requested_width as f64 / source_width as f64)
-        .min(max_height as f64 / source_height as f64)
-        .min(1.0);
-    let target_width = ((source_width as f64 * scale).round() as u32).max(1);
-    let target_height = ((source_height as f64 * scale).round() as u32).max(1);
-    (target_width, target_height)
-}
-
-pub struct CameraPreviewManager {
-    store: Result>, String>,
-    store_save_generation: Arc,
-    preview: Option,
-    preview_session_id: Arc,
-    wgpu_instance: wgpu::Instance,
-}
-
-impl CameraPreviewManager {
-    pub fn new(app: &tauri::AppHandle) -> Self {
-        Self {
-            store: tauri_plugin_store::StoreBuilder::new(app, "cameraPreview")
-                .build()
-                .map_err(|err| format!("Error initializing camera preview store: {err}")),
-            store_save_generation: Arc::new(AtomicU64::new(0)),
-            preview: None,
-            preview_session_id: Arc::new(AtomicU64::new(0)),
-            wgpu_instance: cap_rendering::create_wgpu_instance_sync(),
-        }
-    }
-
-    pub fn session_id_handle(&self) -> Arc {
-        self.preview_session_id.clone()
-    }
-
-    pub fn get_state(&self) -> anyhow::Result {
-        let mut state: CameraPreviewState = self
-            .store
-            .as_ref()
-            .map_err(|err| anyhow!("{err}"))?
-            .get("state")
-            .and_then(|v| serde_json::from_value(v).ok())
-            .unwrap_or_default();
-
-        state.size = clamp_size(state.size);
-        Ok(state)
-    }
-
-    pub fn set_state(&self, mut state: CameraPreviewState) -> anyhow::Result<()> {
-        state.size = clamp_size(state.size);
-
-        let store = self.store.as_ref().map_err(|err| anyhow!("{err}"))?;
-        store.set("state", serde_json::to_value(&state)?);
-
-        // set_state fires per mousemove during a size drag; debounce the disk
-        // write so only the post-drag state is persisted.
-        let generation = self.store_save_generation.fetch_add(1, Ordering::AcqRel) + 1;
-        let save_generation = self.store_save_generation.clone();
-        let store = store.clone();
-        tauri::async_runtime::spawn(async move {
-            tokio::time::sleep(Duration::from_millis(150)).await;
-            if save_generation.load(Ordering::Acquire) == generation
-                && let Err(err) = store.save()
-            {
-                error!("Error saving camera preview store: {err}");
-            }
-        });
-
-        if let Some(preview) = &self.preview {
-            preview
-                .reconfigure
-                .send(ReconfigureEvent::State(state))
-                .map_err(|err| error!("Error asking camera preview to reconfigure: {err}"))
-                .ok();
-        }
-
-        Ok(())
-    }
-
-    pub fn is_initialized(&self) -> bool {
-        self.preview.is_some()
-    }
-
-    pub fn is_paused(&self) -> bool {
-        self.preview
-            .as_ref()
-            .is_some_and(|preview| preview.is_paused)
-    }
-
-    pub fn sender(&self) -> Option {
-        self.preview
-            .as_ref()
-            .map(|p| CameraPreviewSender::from_tx(p.camera_tx.clone()))
-    }
-
-    pub fn notify_window_resized(&self, width: u32, height: u32) {
-        if let Some(preview) = &self.preview {
-            preview
-                .reconfigure
-                .send(ReconfigureEvent::WindowResized { width, height })
-                .map_err(|err| error!("Error notifying camera preview of resize: {err}"))
-                .ok();
-        }
-    }
-
-    // Pauses the camera preview, hiding the window but keeping GPU resources alive.
-    // Called when the user deselects the camera. This is part of the persistent
-    // renderer architecture that prevents crashes from repeated resource creation.
-    pub fn pause(&mut self) {
-        if let Some(preview) = &mut self.preview
-            && !preview.is_paused
-        {
-            preview.is_paused = true;
-            preview
-                .reconfigure
-                .send(ReconfigureEvent::Pause)
-                .map_err(|err| error!("Error sending camera preview pause event: {err}"))
-                .ok();
-        }
-    }
-
-    pub fn begin_shutdown(&mut self) -> Option> {
-        let preview = self.preview.take()?;
-        info!(
-            "Camera preview shutdown requested (session {}).",
-            preview.session_id
-        );
-        preview
-            .reconfigure
-            .send(ReconfigureEvent::Shutdown)
-            .map_err(|err| error!("Error sending camera preview shutdown event: {err}"))
-            .ok();
-        Some(preview.shutdown_complete)
-    }
-
-    pub async fn init_window(
-        &mut self,
-        window: WebviewWindow,
-        actor: ActorRef,
-    ) -> anyhow::Result<()> {
-        let reveal_generation = crate::clean_capture::generation(window.app_handle());
-        if let Some(preview) = &mut self.preview {
-            CameraPreviewSender::from_tx(preview.camera_tx.clone())
-                .attach(&actor)
-                .await
-                .map_err(|err| anyhow!("Error re-attaching camera feed consumer: {err}"))?;
-
-            if preview.is_paused {
-                preview.is_paused = false;
-                preview
-                    .reconfigure
-                    .send(ReconfigureEvent::Resume)
-                    .map_err(|err| error!("Error sending camera preview resume event: {err}"))
-                    .ok();
-            }
-
-            window
-                .run_on_main_thread({
-                    let window = window.clone();
-                    move || {
-                        let _ = crate::clean_capture::reveal_now(&window, reveal_generation);
-                    }
-                })
-                .ok();
-
-            return Ok(());
-        }
-
-        let session_id = self.preview_session_id.fetch_add(1, Ordering::AcqRel) + 1;
-
-        let (camera_tx, camera_rx) = flume::bounded::(1);
-
-        CameraPreviewSender::from_tx(camera_tx.clone())
-            .attach(&actor)
-            .await
-            .map_err(|err| anyhow!("Error attaching camera feed consumer: {err}"))?;
-
-        let default_state = self
-            .get_state()
-            .map_err(|err| error!("Error getting camera preview state: {err}"))
-            .unwrap_or_default();
-
-        // Capacity must absorb bursts of control events (State spam during a
-        // size drag interleaved with Pause/Resume); a lagged capacity-1 channel
-        // could drop a Resume and leave the preview stuck hidden.
-        let (reconfigure, reconfigure_rx) = broadcast::channel(8);
-        let mut renderer = InitializedCameraPreview::init_wgpu(
-            window.clone(),
-            &default_state,
-            self.wgpu_instance.clone(),
-        )
-        .await?;
-        window
-            .run_on_main_thread({
-                let window = window.clone();
-                move || {
-                    let _ = crate::clean_capture::reveal_now(&window, reveal_generation);
-                }
-            })
-            .ok();
-
-        let rt = Runtime::new().context("Failed to create camera preview runtime")?;
-        let (shutdown_complete_tx, shutdown_complete_rx) = oneshot::channel();
-
-        self.preview = Some(InitializedCameraPreview {
-            reconfigure,
-            session_id,
-            shutdown_complete: shutdown_complete_rx,
-            camera_tx,
-            is_paused: false,
-        });
-
-        thread::spawn(move || {
-            #[cfg(target_os = "macos")]
-            {
-                let result = set_current_thread_qos(MacOsQosClass::UserInteractive);
-                if result != 0 {
-                    warn!(result, "pthread_set_qos_class_self_np failed");
-                }
-            }
-            LocalSet::new().block_on(
-                &rt,
-                renderer.run(window.clone(), default_state, reconfigure_rx, camera_rx),
-            );
-
-            let (drop_tx, drop_rx) = oneshot::channel();
-            let renderer = Box::new(renderer);
-            let _ = window.run_on_main_thread(move || {
-                drop(renderer);
-                let _ = drop_tx.send(());
-            });
-
-            wait_for_shutdown_signal(&rt, drop_rx, Duration::from_millis(250));
-
-            shutdown_complete_tx.send(()).ok();
-            info!("DONE");
-        });
-
-        Ok(())
-    }
-}
-
-fn wait_for_shutdown_signal(runtime: &Runtime, receiver: oneshot::Receiver<()>, timeout: Duration) {
-    runtime.block_on(async move {
-        let _ = tokio::time::timeout(timeout, receiver).await;
-    });
-}
-
-// Internal events for the persistent camera renderer architecture.
-//
-// The camera preview uses a persistent WGPU renderer that stays alive across
-// camera deselect/reselect cycles. This avoids repeated GPU resource creation
-// which, combined with macOS panel.order_front_regardless() calls, was causing
-// crashes after ~4-5 toggle cycles.
-//
-// Pause/Resume hide/show the window while keeping GPU resources alive.
-// See the comment in windows.rs ShowCapWindow::Camera for the critical detail
-// about avoiding order_front_regardless().
-#[derive(Clone)]
-enum ReconfigureEvent {
-    State(CameraPreviewState),
-    WindowResized { width: u32, height: u32 },
-    Pause,
-    Resume,
-    Shutdown,
-}
-
-struct InitializedCameraPreview {
-    reconfigure: broadcast::Sender,
-    session_id: u64,
-    shutdown_complete: oneshot::Receiver<()>,
-    camera_tx: flume::Sender,
-    is_paused: bool,
-}
-
-impl InitializedCameraPreview {
-    async fn init_wgpu(
-        window: WebviewWindow,
-        default_state: &CameraPreviewState,
-        instance: wgpu::Instance,
-    ) -> anyhow::Result {
-        let aspect = if default_state.shape == CameraPreviewShape::Full {
-            WIDE_CAMERA_ASPECT_RATIO
-        } else {
-            1.0
-        };
-
-        let (window_width, window_height, surface_scale) =
-            resize_window(&window, default_state, aspect, false)
-                .await
-                .context("Error resizing Tauri window")?;
-
-        let (tx, rx) = oneshot::channel();
-        window
-            .run_on_main_thread({
-                let window = window.clone();
-                let instance = instance.clone();
-                move || {
-                    let surface = instance.create_surface(window.clone());
-                    tx.send(surface).ok();
-                }
-            })
-            .with_context(|| "Failed to initialize wgpu instance")?;
-
-        let surface = rx
-            .await
-            .with_context(|| "Failed to receive initialized wgpu surface")?;
-        let surface = surface.with_context(|| "Failed to initialize wgpu surface")?;
-
-        let force_software_adapter = cap_rendering::force_software_wgpu_adapter();
-        let adapter = instance
-            .request_adapter(&wgpu::RequestAdapterOptions {
-                power_preference: wgpu::PowerPreference::LowPower,
-                force_fallback_adapter: force_software_adapter,
-                compatible_surface: Some(&surface),
-            })
-            .await
-            .with_context(|| "Failed to find an appropriate wgpu adapter")?;
-
-        let (device, queue) = adapter
-            .request_device(&wgpu::DeviceDescriptor {
-                label: None,
-                required_features: wgpu::Features::empty(),
-                required_limits: wgpu::Limits::downlevel_webgl2_defaults()
-                    .using_resolution(adapter.limits()),
-                memory_hints: Default::default(),
-                trace: wgpu::Trace::Off,
-            })
-            .await
-            .with_context(|| "Failed to create wgpu device")?;
-
-        let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
-            label: None,
-            source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(include_str!(
-                "./camera.wgsl"
-            ))),
-        });
-
-        let uniform_bind_group_layout =
-            device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
-                label: Some("Uniform Bind Group Layout"),
-                entries: &[
-                    wgpu::BindGroupLayoutEntry {
-                        binding: 0,
-                        visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
-                        ty: wgpu::BindingType::Buffer {
-                            ty: wgpu::BufferBindingType::Uniform,
-                            has_dynamic_offset: false,
-                            min_binding_size: None,
-                        },
-                        count: None,
-                    },
-                    wgpu::BindGroupLayoutEntry {
-                        binding: 1,
-                        visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
-                        ty: wgpu::BindingType::Buffer {
-                            ty: wgpu::BufferBindingType::Uniform,
-                            has_dynamic_offset: false,
-                            min_binding_size: None,
-                        },
-                        count: None,
-                    },
-                    wgpu::BindGroupLayoutEntry {
-                        binding: 2,
-                        visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
-                        ty: wgpu::BindingType::Buffer {
-                            ty: wgpu::BufferBindingType::Uniform,
-                            has_dynamic_offset: false,
-                            min_binding_size: None,
-                        },
-                        count: None,
-                    },
-                ],
-            });
-
-        let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
-            label: Some("Texture Bind Group Layout"),
-            entries: &[
-                wgpu::BindGroupLayoutEntry {
-                    binding: 0,
-                    visibility: wgpu::ShaderStages::FRAGMENT,
-                    ty: wgpu::BindingType::Texture {
-                        sample_type: wgpu::TextureSampleType::Float { filterable: true },
-                        view_dimension: wgpu::TextureViewDimension::D2,
-                        multisampled: false,
-                    },
-                    count: None,
-                },
-                wgpu::BindGroupLayoutEntry {
-                    binding: 1,
-                    visibility: wgpu::ShaderStages::FRAGMENT,
-                    ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
-                    count: None,
-                },
-            ],
-        });
-
-        let state_uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor {
-            label: Some("State Uniform Buffer"),
-            size: std::mem::size_of::() as u64,
-            usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
-            mapped_at_creation: false,
-        });
-
-        let window_uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor {
-            label: Some("Window Uniform Buffer"),
-            size: std::mem::size_of::() as u64,
-            usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
-            mapped_at_creation: false,
-        });
-
-        let camera_uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor {
-            label: Some("Camera Uniform Buffer"),
-            size: std::mem::size_of::() as u64,
-            usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
-            mapped_at_creation: false,
-        });
-
-        let uniform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
-            label: Some("Uniform Bind Group"),
-            layout: &uniform_bind_group_layout,
-            entries: &[
-                wgpu::BindGroupEntry {
-                    binding: 0,
-                    resource: state_uniform_buffer.as_entire_binding(),
-                },
-                wgpu::BindGroupEntry {
-                    binding: 1,
-                    resource: window_uniform_buffer.as_entire_binding(),
-                },
-                wgpu::BindGroupEntry {
-                    binding: 2,
-                    resource: camera_uniform_buffer.as_entire_binding(),
-                },
-            ],
-        });
-
-        let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
-            label: None,
-            bind_group_layouts: &[&bind_group_layout, &uniform_bind_group_layout],
-            push_constant_ranges: &[],
-        });
-
-        let swapchain_format = wgpu::TextureFormat::Bgra8Unorm;
-        let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
-            label: None,
-            layout: Some(&pipeline_layout),
-            vertex: wgpu::VertexState {
-                module: &shader,
-                entry_point: Some("vs_main"),
-                buffers: &[],
-                compilation_options: Default::default(),
-            },
-            fragment: Some(wgpu::FragmentState {
-                module: &shader,
-                entry_point: Some("fs_main"),
-                targets: &[Some(wgpu::ColorTargetState {
-                    format: swapchain_format,
-                    blend: Some(wgpu::BlendState::ALPHA_BLENDING),
-                    write_mask: wgpu::ColorWrites::ALL,
-                })],
-                compilation_options: Default::default(),
-            }),
-            primitive: wgpu::PrimitiveState::default(),
-            depth_stencil: None,
-            multisample: Default::default(),
-            multiview: None,
-            cache: None,
-        });
-
-        let surface_capabilities = surface.get_capabilities(&adapter);
-        let alpha_mode = preferred_alpha_mode(&surface_capabilities.alpha_modes);
-
-        let present_mode = if surface_capabilities
-            .present_modes
-            .contains(&wgpu::PresentMode::Mailbox)
-        {
-            wgpu::PresentMode::Mailbox
-        } else {
-            wgpu::PresentMode::Fifo
-        };
-
-        let surface_config = wgpu::SurfaceConfiguration {
-            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
-            format: swapchain_format,
-            width: window_width,
-            height: window_height,
-            present_mode,
-            alpha_mode,
-            view_formats: vec![],
-            desired_maximum_frame_latency: 1,
-        };
-
-        surface.configure(&device, &surface_config);
-
-        let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
-            address_mode_u: wgpu::AddressMode::ClampToEdge,
-            address_mode_v: wgpu::AddressMode::ClampToEdge,
-            address_mode_w: wgpu::AddressMode::ClampToEdge,
-            mag_filter: wgpu::FilterMode::Linear,
-            min_filter: wgpu::FilterMode::Linear,
-            mipmap_filter: wgpu::FilterMode::Linear,
-            ..Default::default()
-        });
-
-        let mut renderer = Renderer {
-            surface: Some(surface),
-            surface_config,
-            surface_scale,
-            render_pipeline,
-            device,
-            queue,
-            sampler,
-            bind_group_layout,
-            state_uniform_buffer,
-            window_uniform_buffer,
-            camera_uniform_buffer,
-            uniform_bind_group,
-            texture: Cached::default(),
-            aspect_ratio: Cached::default(),
-            blur_processor: None,
-            blur_processor_init_attempted: false,
-            blur_source_texture: None,
-            #[cfg(target_os = "macos")]
-            native_converter: None,
-            #[cfg(target_os = "macos")]
-            native_converter_init_attempted: false,
-        };
-
-        renderer.update_state_uniforms(default_state);
-        renderer
-            .sync_ratio_uniform_and_resize_window_to_it(&window, default_state, aspect)
-            .await;
-        renderer.reconfigure_gpu_surface(window_width, window_height);
-
-        let initial_surface = renderer.acquire_surface_texture();
-        if let Some(surface) = initial_surface {
-            let output_width = 5;
-            let output_height = 5;
-
-            let (buffer, stride) =
-                render_solid_frame([0x11, 0x11, 0x11, 0xFF], output_width, output_height);
-
-            PreparedTexture::init(
-                renderer.device.clone(),
-                renderer.queue.clone(),
-                &renderer.sampler,
-                &renderer.bind_group_layout,
-                renderer.uniform_bind_group.clone(),
-                renderer.render_pipeline.clone(),
-                output_width,
-                output_height,
-            )
-            .render(&surface, &buffer, stride);
-            surface.present();
-        }
-
-        Ok(renderer)
-    }
-}
-
-struct Renderer {
-    surface: Option>,
-    surface_config: wgpu::SurfaceConfiguration,
-    surface_scale: f64,
-    render_pipeline: wgpu::RenderPipeline,
-    device: wgpu::Device,
-    queue: wgpu::Queue,
-    sampler: wgpu::Sampler,
-    bind_group_layout: wgpu::BindGroupLayout,
-    state_uniform_buffer: wgpu::Buffer,
-    window_uniform_buffer: wgpu::Buffer,
-    camera_uniform_buffer: wgpu::Buffer,
-    uniform_bind_group: wgpu::BindGroup,
-    texture: Cached<(u32, u32), PreparedTexture>,
-    aspect_ratio: Cached,
-    blur_processor: Option,
-    blur_processor_init_attempted: bool,
-    blur_source_texture: Option,
-    #[cfg(target_os = "macos")]
-    native_converter: Option,
-    #[cfg(target_os = "macos")]
-    native_converter_init_attempted: bool,
-}
-
-impl Renderer {
-    async fn run(
-        &mut self,
-        window: WebviewWindow,
-        default_state: CameraPreviewState,
-        mut reconfigure: broadcast::Receiver,
-        camera_rx: flume::Receiver,
-    ) {
-        let mut resampler_frame = Cached::default();
-        let Ok(mut scaler) = scaling::Context::get(
-            Pixel::RGBA,
-            1,
-            1,
-            Pixel::RGBA,
-            1,
-            1,
-            scaling::Flags::empty(),
-        )
-        .map_err(|err| error!("Error initializing ffmpeg scaler: {err:?}")) else {
-            return;
-        };
-        let mut source_dimensions = Cached::default();
-        let mut last_render_at = None;
-
-        // The camera's pixel buffer pool only recycles an IOSurface once its
-        // CVPixelBuffer is released; holding the last couple of sample buffers
-        // keeps the camera from writing into a surface the GPU is still
-        // sampling.
-        #[cfg(target_os = "macos")]
-        let mut inflight_frames: std::collections::VecDeque =
-            std::collections::VecDeque::new();
-        #[cfg(target_os = "macos")]
-        let mut native_fallback_logged = false;
-
-        let start_time = Instant::now();
-        let startup_timeout = Duration::from_secs(5);
-        let mut received_first_frame = false;
-        let mut is_paused = false;
-
-        let mut state = default_state;
-        let mut needs_full_reconfigure = false;
-
-        let pause_and_hide = || {
-            window
-                .run_on_main_thread({
-                    let window = window.clone();
-                    move || {
-                        let _ = window.hide();
-                    }
-                })
-                .ok();
-        };
-
-        'main_loop: loop {
-            if is_paused {
-                loop {
-                    match reconfigure.recv().await {
-                        Ok(ReconfigureEvent::Resume) => {
-                            is_paused = false;
-                            while camera_rx.try_recv().is_ok() {}
-                            #[cfg(target_os = "macos")]
-                            inflight_frames.clear();
-                            if let Some(texture) = self.acquire_surface_texture() {
-                                let (buffer, stride) =
-                                    render_solid_frame([0x11, 0x11, 0x11, 0xFF], 5, 5);
-                                PreparedTexture::init(
-                                    self.device.clone(),
-                                    self.queue.clone(),
-                                    &self.sampler,
-                                    &self.bind_group_layout,
-                                    self.uniform_bind_group.clone(),
-                                    self.render_pipeline.clone(),
-                                    5,
-                                    5,
-                                )
-                                .render(&texture, &buffer, stride);
-                                texture.present();
-                            }
-                            break;
-                        }
-                        Ok(ReconfigureEvent::Shutdown) => {
-                            self.cleanup_for_shutdown(&window).await;
-                            return;
-                        }
-                        Ok(ReconfigureEvent::State(new_state)) => {
-                            state = new_state;
-                            needs_full_reconfigure = true;
-                        }
-                        Ok(ReconfigureEvent::WindowResized { width, height }) => {
-                            self.reconfigure_gpu_surface(width, height);
-                        }
-                        Ok(ReconfigureEvent::Pause) => {}
-                        Err(broadcast::error::RecvError::Lagged(_)) => {
-                            continue;
-                        }
-                        Err(broadcast::error::RecvError::Closed) => {
-                            self.cleanup_for_shutdown(&window).await;
-                            return;
-                        }
-                    }
-                }
-            }
-
-            if needs_full_reconfigure {
-                needs_full_reconfigure = false;
-                self.update_state_uniforms(&state);
-                if state.background_blur == cap_project::BackgroundBlurMode::Off {
-                    self.release_blur_resources();
-                }
-                source_dimensions = Cached::default();
-                last_render_at = None;
-                let aspect_ratio = self.aspect_ratio.get_latest_key().copied().unwrap_or(
-                    if state.shape == CameraPreviewShape::Full {
-                        WIDE_CAMERA_ASPECT_RATIO
-                    } else {
-                        1.0
-                    },
-                );
-                self.aspect_ratio = Cached::default();
-                if let Ok((width, height, scale)) =
-                    resize_window(&window, &state, aspect_ratio, false)
-                        .await
-                        .map_err(|err| {
-                            error!("Error resizing camera preview window after resume: {err}")
-                        })
-                {
-                    self.surface_scale = scale;
-                    self.reconfigure_gpu_surface(width, height);
-                }
-            }
-
-            let frame_timeout = if received_first_frame {
-                Duration::from_secs(5)
-            } else if start_time.elapsed() < startup_timeout {
-                startup_timeout.saturating_sub(start_time.elapsed())
-            } else {
-                Duration::from_secs(1)
-            };
-
-            let event = loop {
-                if frame_timeout.is_zero() {
-                    warn!("Camera preview timed out waiting for first frame, waiting for recovery");
-                    tokio::time::sleep(Duration::from_secs(1)).await;
-                    continue 'main_loop;
-                }
-
-                tokio::select! {
-                    frame = camera_rx.recv_async() => {
-                        match frame {
-                            Ok(f) => break Ok(f),
-                            Err(_) => {
-                                is_paused = true;
-                                pause_and_hide();
-                                continue 'main_loop;
-                            }
-                        }
-                    },
-                    result = reconfigure.recv() => {
-                        match result {
-                            Ok(result) => break Err(result),
-                            Err(broadcast::error::RecvError::Lagged(_)) => continue,
-                            Err(broadcast::error::RecvError::Closed) => {
-                                break Err(ReconfigureEvent::Shutdown);
-                            }
-                        }
-                    },
-                    _ = tokio::time::sleep(frame_timeout) => {
-                        if received_first_frame {
-                            warn!("Camera preview: frames stalled, waiting for feed refresh");
-                            continue;
-                        }
-                        warn!("Camera preview: no frames received within startup timeout, waiting for recovery");
-                        continue 'main_loop;
-                    }
-                }
-            };
-
-            match event {
-                Ok(mut frame) => {
-                    while let Ok(newer) = camera_rx.try_recv() {
-                        frame = newer;
-                    }
-
-                    received_first_frame = true;
-                    let now = Instant::now();
-                    if !camera_preview_frame_due(last_render_at, now) {
-                        continue 'main_loop;
-                    }
-                    last_render_at = Some(now);
-
-                    #[cfg(target_os = "macos")]
-                    let (source_width, source_height) = {
-                        let Some(image_buf) = frame.sample_buf.image_buf() else {
-                            continue 'main_loop;
-                        };
-                        (image_buf.width() as u32, image_buf.height() as u32)
-                    };
-                    #[cfg(not(target_os = "macos"))]
-                    let (source_width, source_height) = (frame.inner.width(), frame.inner.height());
-
-                    let aspect_ratio = source_width as f32 / source_height as f32;
-                    if source_dimensions.update_key_and_should_init((source_width, source_height)) {
-                        self.sync_ratio_uniform_and_resize_window_to_it(
-                            &window,
-                            &state,
-                            aspect_ratio,
-                        )
-                        .await;
-                    }
-
-                    let surface_result = self.acquire_surface_texture();
-                    if let Some(surface) = surface_result {
-                        let surface_scale = self.surface_scale.max(1.0);
-                        let toolbar_px = (TOOLBAR_HEIGHT as f64 * surface_scale).round() as u32;
-                        let region_width = self.surface_config.width.max(1);
-                        let region_height =
-                            self.surface_config.height.saturating_sub(toolbar_px).max(1);
-                        let blur_mode = blur_mode_from_project(state.background_blur);
-                        let (output_width, output_height) = camera_preview_texture_dimensions(
-                            source_width,
-                            source_height,
-                            region_width,
-                            region_height,
-                            blur_mode.is_some(),
-                        );
-
-                        #[cfg(target_os = "macos")]
-                        {
-                            match self.render_native_frame(
-                                &frame,
-                                output_width,
-                                output_height,
-                                blur_mode,
-                                &surface,
-                            ) {
-                                Ok(()) => {
-                                    surface.present();
-                                    inflight_frames.push_back(frame);
-                                    while inflight_frames.len() > 2 {
-                                        inflight_frames.pop_front();
-                                    }
-                                }
-                                Err(err) => {
-                                    if !native_fallback_logged {
-                                        native_fallback_logged = true;
-                                        warn!(
-                                            "Camera GPU-native preview unavailable ({err}); using CPU conversion"
-                                        );
-                                    }
-                                    match cap_camera_ffmpeg::sample_buf_as_ffmpeg(&frame.sample_buf)
-                                    {
-                                        Ok(inner) => {
-                                            if self.render_cpu_frame(
-                                                &inner,
-                                                output_width,
-                                                output_height,
-                                                blur_mode,
-                                                &surface,
-                                                &mut scaler,
-                                                &mut resampler_frame,
-                                            ) {
-                                                surface.present();
-                                            }
-                                        }
-                                        Err(err) => {
-                                            error!(
-                                                "Camera preview CPU fallback conversion failed: {err}"
-                                            );
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                        #[cfg(not(target_os = "macos"))]
-                        {
-                            if self.render_cpu_frame(
-                                &frame.inner,
-                                output_width,
-                                output_height,
-                                blur_mode,
-                                &surface,
-                                &mut scaler,
-                                &mut resampler_frame,
-                            ) {
-                                surface.present();
-                            }
-                        }
-                    }
-                }
-                Err(ReconfigureEvent::State(new_state)) => {
-                    trace!("CameraPreview/ReconfigureEvent.State({new_state:?})");
-
-                    state = new_state;
-
-                    let aspect_ratio = self.aspect_ratio.get_latest_key().copied().unwrap_or(
-                        if state.shape == CameraPreviewShape::Full {
-                            WIDE_CAMERA_ASPECT_RATIO
-                        } else {
-                            1.0
-                        },
-                    );
-
-                    self.sync_ratio_uniform_and_resize_window_to_it(&window, &state, aspect_ratio)
-                        .await;
-                    self.update_state_uniforms(&state);
-                    if state.background_blur == cap_project::BackgroundBlurMode::Off {
-                        self.release_blur_resources();
-                    }
-                    if let Ok((width, height, scale)) =
-                        resize_window(&window, &state, aspect_ratio, false)
-                            .await
-                            .map_err(|err| error!("Error resizing camera preview window: {err}"))
-                    {
-                        self.surface_scale = scale;
-                        self.reconfigure_gpu_surface(width, height);
-                    }
-                }
-                Err(ReconfigureEvent::WindowResized { width, height }) => {
-                    trace!("CameraPreview/ReconfigureEvent.WindowResized({width}x{height})");
-                    self.reconfigure_gpu_surface(width, height);
-                }
-                Err(ReconfigureEvent::Pause) => {
-                    // When pausing, we hide the window to provide proper UX feedback.
-                    // The WGPU Surface and Device are kept alive to avoid repeated GPU
-                    // resource creation, which previously contributed to crashes.
-                    //
-                    // The corresponding show operation in windows.rs uses window.show()
-                    // instead of panel.order_front_regardless() - see the comment there
-                    // for why this is critical to avoid macOS crashes.
-                    is_paused = true;
-                    #[cfg(target_os = "macos")]
-                    inflight_frames.clear();
-                    window
-                        .run_on_main_thread({
-                            let window = window.clone();
-                            move || {
-                                let _ = window.hide();
-                            }
-                        })
-                        .ok();
-                }
-                Err(ReconfigureEvent::Resume) => {
-                    while camera_rx.try_recv().is_ok() {}
-                    #[cfg(target_os = "macos")]
-                    inflight_frames.clear();
-                    if let Some(texture) = self.acquire_surface_texture() {
-                        let (buffer, stride) = render_solid_frame([0x11, 0x11, 0x11, 0xFF], 5, 5);
-                        PreparedTexture::init(
-                            self.device.clone(),
-                            self.queue.clone(),
-                            &self.sampler,
-                            &self.bind_group_layout,
-                            self.uniform_bind_group.clone(),
-                            self.render_pipeline.clone(),
-                            5,
-                            5,
-                        )
-                        .render(&texture, &buffer, stride);
-                        texture.present();
-                    }
-                }
-                Err(ReconfigureEvent::Shutdown) => {
-                    self.cleanup_for_shutdown(&window).await;
-                    return;
-                }
-            }
-        }
-    }
-
-    #[allow(clippy::too_many_arguments)]
-    fn render_cpu_frame(
-        &mut self,
-        inner: &frame::Video,
-        output_width: u32,
-        output_height: u32,
-        blur_mode: Option,
-        surface: &SurfaceTexture,
-        scaler: &mut scaling::Context,
-        resampler_frame: &mut Cached<(u32, u32), frame::Video>,
-    ) -> bool {
-        let source_width = inner.width();
-        let source_height = inner.height();
-
-        let already_preview_rgba = inner.format() == Pixel::RGBA
-            && output_width == source_width
-            && output_height == source_height;
-        let (frame_data, frame_stride) = if already_preview_rgba {
-            (inner.data(0), inner.stride(0) as u32)
-        } else {
-            let resampler_frame =
-                resampler_frame.get_or_init((output_width, output_height), frame::Video::empty);
-
-            scaler.cached(
-                inner.format(),
-                source_width,
-                source_height,
-                format::Pixel::RGBA,
-                output_width,
-                output_height,
-                ffmpeg::software::scaling::flag::Flags::FAST_BILINEAR,
-            );
-
-            if let Err(err) = scaler.run(inner, resampler_frame) {
-                error!("Error rescaling frame with ffmpeg: {err:?}");
-                return false;
-            }
-
-            (resampler_frame.data(0), resampler_frame.stride(0) as u32)
-        };
-
-        let blurred = if let Some(mode) = blur_mode {
-            self.run_background_blur(frame_data, frame_stride, output_width, output_height, mode)
-        } else {
-            false
-        };
-
-        let prepared = self.texture.get_or_init((output_width, output_height), || {
-            PreparedTexture::init(
-                self.device.clone(),
-                self.queue.clone(),
-                &self.sampler,
-                &self.bind_group_layout,
-                self.uniform_bind_group.clone(),
-                self.render_pipeline.clone(),
-                output_width,
-                output_height,
-            )
-        });
-
-        if blurred {
-            let Some(blur_output) = self
-                .blur_processor
-                .as_mut()
-                .and_then(|p| p.process_returning_output())
-            else {
-                prepared.render(surface, frame_data, frame_stride);
-                return true;
-            };
-            let mut encoder = self
-                .device
-                .create_command_encoder(&wgpu::CommandEncoderDescriptor {
-                    label: Some("Blur Copy"),
-                });
-            encoder.copy_texture_to_texture(
-                wgpu::TexelCopyTextureInfo {
-                    texture: blur_output,
-                    mip_level: 0,
-                    origin: wgpu::Origin3d::ZERO,
-                    aspect: wgpu::TextureAspect::All,
-                },
-                wgpu::TexelCopyTextureInfo {
-                    texture: &prepared.texture,
-                    mip_level: 0,
-                    origin: wgpu::Origin3d::ZERO,
-                    aspect: wgpu::TextureAspect::All,
-                },
-                wgpu::Extent3d {
-                    width: output_width,
-                    height: output_height,
-                    depth_or_array_layers: 1,
-                },
-            );
-            self.queue.submit(std::iter::once(encoder.finish()));
-            prepared.render_no_upload(surface);
-        } else {
-            prepared.render(surface, frame_data, frame_stride);
-        }
-        true
-    }
-
-    #[cfg(target_os = "macos")]
-    fn ensure_native_converter(&mut self) -> bool {
-        if self.native_converter.is_some() {
-            return true;
-        }
-        if self.native_converter_init_attempted {
-            return false;
-        }
-        self.native_converter_init_attempted = true;
-        self.native_converter = NativeFrameConverter::new(&self.device);
-        if self.native_converter.is_some() {
-            info!("Camera GPU-native frame converter initialized");
-            true
-        } else {
-            warn!("Failed to initialize camera GPU-native frame converter");
-            false
-        }
-    }
-
-    #[cfg(target_os = "macos")]
-    fn render_native_frame(
-        &mut self,
-        frame: &NativeCameraFrame,
-        output_width: u32,
-        output_height: u32,
-        blur_mode: Option,
-        surface: &SurfaceTexture,
-    ) -> Result<(), String> {
-        let kind = classify_frame(frame).map_err(|err| err.to_string())?;
-        if !self.ensure_native_converter() {
-            return Err("GPU-native converter unavailable".to_string());
-        }
-
-        let use_blur = blur_mode.is_some() && self.ensure_blur_processor();
-
-        if use_blur {
-            self.ensure_blur_source_texture(output_width, output_height);
-            let src_tex = self.blur_source_texture.as_ref().expect("just ensured");
-            let dst_view = src_tex.create_view(&wgpu::TextureViewDescriptor::default());
-            self.native_converter
-                .as_ref()
-                .expect("ensured above")
-                .render_frame(&self.device, &self.queue, frame, &kind, &dst_view)
-                .map_err(|err| err.to_string())?;
-
-            if let (Some(mode), Some(processor)) = (blur_mode, self.blur_processor.as_mut()) {
-                processor.process(&self.device, &self.queue, src_tex, mode);
-            }
-
-            let prepared = self.texture.get_or_init((output_width, output_height), || {
-                PreparedTexture::init(
-                    self.device.clone(),
-                    self.queue.clone(),
-                    &self.sampler,
-                    &self.bind_group_layout,
-                    self.uniform_bind_group.clone(),
-                    self.render_pipeline.clone(),
-                    output_width,
-                    output_height,
-                )
-            });
-
-            let blur_output = self
-                .blur_processor
-                .as_mut()
-                .and_then(|p| p.process_returning_output())
-                .ok_or_else(|| "blur output missing".to_string())?;
-            let mut encoder = self
-                .device
-                .create_command_encoder(&wgpu::CommandEncoderDescriptor {
-                    label: Some("Blur Copy"),
-                });
-            encoder.copy_texture_to_texture(
-                wgpu::TexelCopyTextureInfo {
-                    texture: blur_output,
-                    mip_level: 0,
-                    origin: wgpu::Origin3d::ZERO,
-                    aspect: wgpu::TextureAspect::All,
-                },
-                wgpu::TexelCopyTextureInfo {
-                    texture: &prepared.texture,
-                    mip_level: 0,
-                    origin: wgpu::Origin3d::ZERO,
-                    aspect: wgpu::TextureAspect::All,
-                },
-                wgpu::Extent3d {
-                    width: output_width,
-                    height: output_height,
-                    depth_or_array_layers: 1,
-                },
-            );
-            self.queue.submit(std::iter::once(encoder.finish()));
-            prepared.render_no_upload(surface);
-        } else {
-            let prepared = self.texture.get_or_init((output_width, output_height), || {
-                PreparedTexture::init(
-                    self.device.clone(),
-                    self.queue.clone(),
-                    &self.sampler,
-                    &self.bind_group_layout,
-                    self.uniform_bind_group.clone(),
-                    self.render_pipeline.clone(),
-                    output_width,
-                    output_height,
-                )
-            });
-            let dst_view = prepared
-                .texture
-                .create_view(&wgpu::TextureViewDescriptor::default());
-            self.native_converter
-                .as_ref()
-                .expect("ensured above")
-                .render_frame(&self.device, &self.queue, frame, &kind, &dst_view)
-                .map_err(|err| err.to_string())?;
-            prepared.render_no_upload(surface);
-        }
-
-        Ok(())
-    }
-
-    fn run_background_blur(
-        &mut self,
-        frame_data: &[u8],
-        frame_stride: u32,
-        width: u32,
-        height: u32,
-        mode: cap_camera_effects::BlurMode,
-    ) -> bool {
-        if !self.ensure_blur_processor() {
-            return false;
-        }
-
-        self.ensure_blur_source_texture(width, height);
-
-        let (Some(src_tex), Some(processor)) = (
-            self.blur_source_texture.as_ref(),
-            self.blur_processor.as_mut(),
-        ) else {
-            return false;
-        };
-
-        self.queue.write_texture(
-            wgpu::TexelCopyTextureInfo {
-                texture: src_tex,
-                mip_level: 0,
-                origin: wgpu::Origin3d::ZERO,
-                aspect: wgpu::TextureAspect::All,
-            },
-            frame_data,
-            wgpu::TexelCopyBufferLayout {
-                offset: 0,
-                bytes_per_row: Some(frame_stride),
-                rows_per_image: Some(height),
-            },
-            wgpu::Extent3d {
-                width,
-                height,
-                depth_or_array_layers: 1,
-            },
-        );
-
-        processor.process(&self.device, &self.queue, src_tex, mode);
-        true
-    }
-
-    // The blur processor owns an ONNX session plus several GPU textures, so it
-    // is dropped as soon as blur is switched off instead of living for the
-    // window's lifetime; turning blur back on re-runs the lazy init.
-    fn release_blur_resources(&mut self) {
-        if self.blur_processor.is_some() || self.blur_source_texture.is_some() {
-            self.blur_processor = None;
-            self.blur_source_texture = None;
-            info!("Released camera background blur resources");
-        }
-        self.blur_processor_init_attempted = false;
-    }
-
-    fn ensure_blur_processor(&mut self) -> bool {
-        if self.blur_processor.is_some() {
-            return true;
-        }
-
-        // Low-spec: never spin up the ONNX/wgpu blur processor (the heaviest
-        // cost in the preview). Both callers treat `false` as "blur unavailable"
-        // and fall back to rendering the raw camera frame, so the preview stays
-        // functional, just unblurred. The UI blur toggle is unaffected; it just
-        // does not take visual effect on these machines.
-        if is_low_spec_preview() {
-            return false;
-        }
-
-        if self.blur_processor_init_attempted {
-            return false;
-        }
-
-        self.blur_processor_init_attempted = true;
-        match cap_camera_effects::BlurProcessor::new(&self.device, wgpu::TextureFormat::Rgba8Unorm)
-        {
-            Ok(processor) => {
-                let mut processor = processor;
-                processor.set_inference_interval(CAMERA_PREVIEW_BLUR_INFERENCE_INTERVAL);
-                info!("Camera background blur processor initialized");
-                self.blur_processor = Some(processor);
-                true
-            }
-            Err(err) => {
-                warn!("Failed to initialize camera background blur: {err}");
-                false
-            }
-        }
-    }
-
-    fn ensure_blur_source_texture(&mut self, width: u32, height: u32) -> &wgpu::Texture {
-        if self
-            .blur_source_texture
-            .as_ref()
-            .is_none_or(|t| t.width() != width || t.height() != height)
-        {
-            self.blur_source_texture = Some(self.device.create_texture(&wgpu::TextureDescriptor {
-                label: Some("Blur Source"),
-                size: wgpu::Extent3d {
-                    width,
-                    height,
-                    depth_or_array_layers: 1,
-                },
-                mip_level_count: 1,
-                sample_count: 1,
-                dimension: wgpu::TextureDimension::D2,
-                format: wgpu::TextureFormat::Rgba8Unorm,
-                usage: wgpu::TextureUsages::TEXTURE_BINDING
-                    | wgpu::TextureUsages::COPY_DST
-                    | wgpu::TextureUsages::COPY_SRC
-                    | wgpu::TextureUsages::RENDER_ATTACHMENT,
-                view_formats: &[],
-            }));
-        }
-        self.blur_source_texture.as_ref().unwrap()
-    }
-
-    async fn cleanup_for_shutdown(&mut self, window: &WebviewWindow) {
-        info!("Camera preview shutdown requested. Cleaning up...");
-
-        let _ = self.device.poll(wgpu::PollType::Poll);
-
-        drop(std::mem::take(&mut self.texture));
-        self.aspect_ratio = Cached::default();
-
-        let surface = self.surface.take();
-        let (drop_tx, drop_rx) = oneshot::channel();
-        let _ = window.run_on_main_thread(move || {
-            drop(surface);
-            let _ = drop_tx.send(());
-        });
-        let _ = tokio::time::timeout(Duration::from_millis(250), drop_rx).await;
-
-        self.device.destroy();
-
-        tokio::time::sleep(Duration::from_millis(50)).await;
-    }
-
-    fn acquire_surface_texture(&mut self) -> Option {
-        let surface = self.surface.as_ref()?;
-        match surface.get_current_texture() {
-            Ok(texture) => Some(texture),
-            Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
-                tracing::warn!("Camera preview surface lost/outdated; reconfiguring");
-                surface.configure(&self.device, &self.surface_config);
-                match surface.get_current_texture() {
-                    Ok(texture) => Some(texture),
-                    Err(err) => {
-                        tracing::error!(
-                            "Camera preview surface still failing after reconfigure: {err:?}"
-                        );
-                        None
-                    }
-                }
-            }
-            Err(wgpu::SurfaceError::Timeout) => {
-                tracing::debug!("Camera preview surface acquire timed out; skipping frame");
-                None
-            }
-            Err(err) => {
-                tracing::error!("Error getting camera renderer surface texture: {err:?}");
-                None
-            }
-        }
-    }
-
-    fn reconfigure_gpu_surface(&mut self, window_width: u32, window_height: u32) {
-        let scale = self.surface_scale.max(1.0);
-        let surface_width = if window_width > 0 {
-            ((window_width as f64 * scale).round() as u32).max(1)
-        } else {
-            1
-        };
-        let surface_height = if window_height > 0 {
-            ((window_height as f64 * scale).round() as u32).max(1)
-        } else {
-            1
-        };
-
-        if self.surface_config.width != surface_width
-            || self.surface_config.height != surface_height
-        {
-            self.surface_config.width = surface_width;
-            self.surface_config.height = surface_height;
-            if let Some(surface) = &self.surface {
-                surface.configure(&self.device, &self.surface_config);
-            }
-        }
-
-        let window_uniforms = WindowUniforms {
-            window_height: window_height as f32,
-            window_width: window_width as f32,
-            toolbar_percentage: (TOOLBAR_HEIGHT * scale as f32) / self.surface_config.height as f32,
-            _padding: 0.0,
-        };
-        self.queue.write_buffer(
-            &self.window_uniform_buffer,
-            0,
-            bytemuck::cast_slice(&[window_uniforms]),
-        );
-    }
-
-    fn update_state_uniforms(&self, state: &CameraPreviewState) {
-        let clamped_size = clamp_size(state.size);
-        let normalized_size =
-            (clamped_size - MIN_CAMERA_SIZE) / (MAX_CAMERA_SIZE - MIN_CAMERA_SIZE);
-
-        let state_uniforms = StateUniforms {
-            shape: if state.background_blur == cap_project::BackgroundBlurMode::Remove {
-                3.0
-            } else {
-                match state.shape {
-                    CameraPreviewShape::Round => 0.0,
-                    CameraPreviewShape::Square => 1.0,
-                    CameraPreviewShape::Full => 2.0,
-                }
-            },
-            size: normalized_size,
-            mirrored: if state.mirrored { 1.0 } else { 0.0 },
-            _padding: 0.0,
-        };
-        self.queue.write_buffer(
-            &self.state_uniform_buffer,
-            0,
-            bytemuck::cast_slice(&[state_uniforms]),
-        );
-    }
-
-    async fn sync_ratio_uniform_and_resize_window_to_it(
-        &mut self,
-        window: &WebviewWindow,
-        state: &CameraPreviewState,
-        aspect_ratio: f32,
-    ) {
-        if self.aspect_ratio.update_key_and_should_init(aspect_ratio) {
-            let camera_uniforms = CameraUniforms {
-                camera_aspect_ratio: aspect_ratio,
-                _padding: 0.0,
-            };
-            self.queue.write_buffer(
-                &self.camera_uniform_buffer,
-                0,
-                bytemuck::cast_slice(&[camera_uniforms]),
-            );
-
-            if let Ok((width, height, scale)) = resize_window(window, state, aspect_ratio, false)
-                .await
-                .map_err(|err| error!("Error resizing camera preview window: {err}"))
-            {
-                self.surface_scale = scale;
-                self.reconfigure_gpu_surface(width, height);
-            }
-        }
-    }
-}
-
-async fn resize_window(
-    window: &WebviewWindow,
-    state: &CameraPreviewState,
-    aspect: f32,
-    should_move: bool,
-) -> anyhow::Result<(u32, u32, f64)> {
-    trace!("CameraPreview/resize_window");
-
-    let base = clamp_size(state.size);
-    let aspect = if state.shape == CameraPreviewShape::Full {
-        aspect.max(WIDE_CAMERA_ASPECT_RATIO)
-    } else {
-        1.0
-    };
-    let window_width = base * aspect;
-    let window_height = base + TOOLBAR_HEIGHT;
-
-    let window_width = window_width as u32;
-    let window_height = window_height as u32;
-
-    let (tx, rx) = oneshot::channel();
-    window
-        .run_on_main_thread({
-            let window = window.clone();
-            move || {
-                let result: tauri::Result<(u32, u32, f64)> = (|| {
-                    if should_move {
-                        let (monitor_size, monitor_offset, monitor_scale_factor): (
-                            PhysicalSize,
-                            LogicalPosition,
-                            _,
-                        ) = if let Some(monitor) = window.current_monitor()? {
-                            let size = monitor.position().to_logical(monitor.scale_factor());
-                            (*monitor.size(), size, monitor.scale_factor())
-                        } else {
-                            (PhysicalSize::new(640, 360), LogicalPosition::new(0, 0), 1.0)
-                        };
-
-                        let x = (monitor_size.width as f64 / monitor_scale_factor
-                            - window_width as f64
-                            - 100.0) as u32
-                            + monitor_offset.x;
-                        let y = (monitor_size.height as f64 / monitor_scale_factor
-                            - window_height as f64
-                            - 100.0) as u32
-                            + monitor_offset.y;
-
-                        window.set_position(LogicalPosition::new(x, y))?;
-                    } else if let Some(monitor) = window.current_monitor()? {
-                        let scale_factor = monitor.scale_factor();
-                        let monitor_pos = monitor.position().to_logical::(scale_factor);
-                        let monitor_size = monitor.size().to_logical::(scale_factor);
-
-                        let current_pos = window
-                            .outer_position()
-                            .map(|p| p.to_logical::(scale_factor))
-                            .unwrap_or(monitor_pos);
-
-                        let mut new_x = current_pos.x;
-                        let mut new_y = current_pos.y;
-                        let new_width = window_width as f64;
-                        let new_height = window_height as f64;
-
-                        if new_x + new_width > monitor_pos.x + monitor_size.width {
-                            new_x = monitor_pos.x + monitor_size.width - new_width;
-                        }
-
-                        if new_y + new_height > monitor_pos.y + monitor_size.height {
-                            new_y = monitor_pos.y + monitor_size.height - new_height;
-                        }
-
-                        if new_x < monitor_pos.x {
-                            new_x = monitor_pos.x;
-                        }
-
-                        if new_y < monitor_pos.y {
-                            new_y = monitor_pos.y;
-                        }
-
-                        if (new_x - current_pos.x).abs() > 1.0
-                            || (new_y - current_pos.y).abs() > 1.0
-                        {
-                            window.set_position(LogicalPosition::new(new_x, new_y))?;
-                        }
-                    }
-
-                    window.set_size(LogicalSize::new(window_width, window_height))?;
-
-                    let scale_factor = window
-                        .scale_factor()
-                        .ok()
-                        .filter(|scale| *scale > 0.0)
-                        .unwrap_or(DEFAULT_SURFACE_SCALE);
-
-                    Ok((window_width, window_height, scale_factor))
-                })();
-
-                tx.send(result).ok();
-            }
-        })
-        .context("Failed to run window resize on main thread")?;
-
-    rx.await
-        .context("Failed to receive window resize result")?
-        .map_err(anyhow::Error::new)
-}
-
-#[cfg(test)]
-mod tests {
-    use super::{
-        CAMERA_PREVIEW_MAX_TEXTURE_HEIGHT, CAMERA_PREVIEW_MAX_TEXTURE_WIDTH,
-        camera_preview_texture_dimensions, preferred_alpha_mode, wait_for_shutdown_signal,
-    };
-    use std::thread;
-    use tokio::{runtime::Runtime, sync::oneshot, time::Duration};
-    use wgpu::CompositeAlphaMode;
-
-    #[test]
-    fn texture_covers_square_region_without_upscaling() {
-        let (width, height) = camera_preview_texture_dimensions(1280, 720, 460, 460, false);
-        let cover_scale = (460.0 / width as f64).max(460.0 / height as f64);
-        assert!(
-            cover_scale <= 1.0,
-            "texture {width}x{height} would upscale to cover a 460x460 region (scale {cover_scale})"
-        );
-    }
-
-    #[test]
-    fn texture_dimensions_stay_within_caps() {
-        let (width, height) = camera_preview_texture_dimensions(1920, 1080, 4000, 2200, false);
-        assert!(width <= CAMERA_PREVIEW_MAX_TEXTURE_WIDTH);
-        assert!(height <= CAMERA_PREVIEW_MAX_TEXTURE_HEIGHT);
-    }
-
-    #[test]
-    fn preferred_alpha_mode_avoids_unsupported_inherit_fallback() {
-        assert_eq!(
-            preferred_alpha_mode(&[CompositeAlphaMode::Opaque]),
-            CompositeAlphaMode::Opaque
-        );
-    }
-
-    #[test]
-    fn preferred_alpha_mode_keeps_transparent_modes_when_supported() {
-        assert_eq!(
-            preferred_alpha_mode(&[
-                CompositeAlphaMode::Opaque,
-                CompositeAlphaMode::PreMultiplied,
-            ]),
-            CompositeAlphaMode::PreMultiplied
-        );
-        assert_eq!(
-            preferred_alpha_mode(&[
-                CompositeAlphaMode::Opaque,
-                CompositeAlphaMode::PostMultiplied,
-            ]),
-            CompositeAlphaMode::PostMultiplied
-        );
-    }
-
-    #[test]
-    fn preferred_alpha_mode_uses_other_supported_fallbacks() {
-        assert_eq!(
-            preferred_alpha_mode(&[CompositeAlphaMode::Auto]),
-            CompositeAlphaMode::Auto
-        );
-        assert_eq!(
-            preferred_alpha_mode(&[CompositeAlphaMode::Inherit]),
-            CompositeAlphaMode::Inherit
-        );
-        assert_eq!(preferred_alpha_mode(&[]), CompositeAlphaMode::Opaque);
-    }
-
-    #[test]
-    fn wait_for_shutdown_signal_can_run_from_plain_thread() {
-        let runtime = Runtime::new().unwrap();
-        let (tx, rx) = oneshot::channel();
-
-        let handle = thread::spawn(move || {
-            wait_for_shutdown_signal(&runtime, rx, Duration::from_millis(100));
-        });
-
-        tx.send(()).ok();
-        handle.join().unwrap();
-    }
-}
-
-fn blur_mode_from_project(
-    mode: cap_project::BackgroundBlurMode,
-) -> Option {
-    match mode {
-        cap_project::BackgroundBlurMode::Off => None,
-        cap_project::BackgroundBlurMode::Light => Some(cap_camera_effects::BlurMode::Light),
-        cap_project::BackgroundBlurMode::Heavy => Some(cap_camera_effects::BlurMode::Heavy),
-        cap_project::BackgroundBlurMode::Remove => {
-            cfg!(target_os = "macos").then_some(cap_camera_effects::BlurMode::Remove)
-        }
-    }
-}
-
-fn render_solid_frame(color: [u8; 4], width: u32, height: u32) -> (Vec, u32) {
-    let pixel_count = (height * width) as usize;
-    let buffer: Vec = color
-        .iter()
-        .cycle()
-        .take(pixel_count * 4)
-        .copied()
-        .collect();
-
-    (buffer, 4 * width)
-}
-
-pub struct PreparedTexture {
-    texture: wgpu::Texture,
-    bind_group: wgpu::BindGroup,
-    uniform_bind_group: wgpu::BindGroup,
-    render_pipeline: wgpu::RenderPipeline,
-    device: wgpu::Device,
-    queue: wgpu::Queue,
-    width: u32,
-    height: u32,
-}
-
-impl PreparedTexture {
-    #[allow(clippy::too_many_arguments)]
-    pub fn init(
-        device: wgpu::Device,
-        queue: wgpu::Queue,
-        sampler: &wgpu::Sampler,
-        bind_group_layout: &wgpu::BindGroupLayout,
-        uniform_bind_group: wgpu::BindGroup,
-        render_pipeline: wgpu::RenderPipeline,
-        width: u32,
-        height: u32,
-    ) -> Self {
-        let texture = device.create_texture(&wgpu::TextureDescriptor {
-            label: Some("Texture"),
-            size: wgpu::Extent3d {
-                width,
-                height,
-                depth_or_array_layers: 1,
-            },
-            mip_level_count: 1,
-            sample_count: 1,
-            dimension: wgpu::TextureDimension::D2,
-            format: wgpu::TextureFormat::Rgba8Unorm,
-            usage: wgpu::TextureUsages::TEXTURE_BINDING
-                | wgpu::TextureUsages::COPY_DST
-                | wgpu::TextureUsages::RENDER_ATTACHMENT,
-            view_formats: &[],
-        });
-
-        let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default());
-
-        let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
-            label: Some("Texture Bind Group"),
-            layout: bind_group_layout,
-            entries: &[
-                wgpu::BindGroupEntry {
-                    binding: 0,
-                    resource: wgpu::BindingResource::TextureView(&texture_view),
-                },
-                wgpu::BindGroupEntry {
-                    binding: 1,
-                    resource: wgpu::BindingResource::Sampler(sampler),
-                },
-            ],
-        });
-
-        Self {
-            texture,
-            bind_group,
-            uniform_bind_group,
-            render_pipeline,
-            device,
-            queue,
-            width,
-            height,
-        }
-    }
-
-    pub fn render_no_upload(&self, surface: &SurfaceTexture) {
-        let surface_view = surface
-            .texture
-            .create_view(&wgpu::TextureViewDescriptor::default());
-
-        let mut encoder = self
-            .device
-            .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
-
-        {
-            let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
-                label: None,
-                color_attachments: &[Some(wgpu::RenderPassColorAttachment {
-                    view: &surface_view,
-                    resolve_target: None,
-                    ops: wgpu::Operations {
-                        load: wgpu::LoadOp::Clear(wgpu::Color {
-                            r: 0.0,
-                            g: 0.0,
-                            b: 0.0,
-                            a: 0.0,
-                        }),
-                        store: wgpu::StoreOp::Store,
-                    },
-                })],
-                depth_stencil_attachment: None,
-                timestamp_writes: None,
-                occlusion_query_set: None,
-            });
-
-            render_pass.set_pipeline(&self.render_pipeline);
-            render_pass.set_bind_group(0, &self.bind_group, &[]);
-            render_pass.set_bind_group(1, &self.uniform_bind_group, &[]);
-            render_pass.draw(0..6, 0..1);
-        }
-
-        self.queue.submit(Some(encoder.finish()));
-    }
-
-    pub fn render(&self, surface: &SurfaceTexture, buffer: &[u8], stride: u32) {
-        let surface_view = surface
-            .texture
-            .create_view(&wgpu::TextureViewDescriptor::default());
-
-        self.queue.write_texture(
-            wgpu::TexelCopyTextureInfo {
-                texture: &self.texture,
-                mip_level: 0,
-                origin: wgpu::Origin3d::ZERO,
-                aspect: wgpu::TextureAspect::All,
-            },
-            buffer,
-            wgpu::TexelCopyBufferLayout {
-                offset: 0,
-                bytes_per_row: Some(stride),
-                rows_per_image: Some(self.height),
-            },
-            wgpu::Extent3d {
-                width: self.width,
-                height: self.height,
-                depth_or_array_layers: 1,
-            },
-        );
-
-        let mut encoder = self
-            .device
-            .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
-
-        {
-            let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
-                label: None,
-                color_attachments: &[Some(wgpu::RenderPassColorAttachment {
-                    view: &surface_view,
-                    resolve_target: None,
-                    ops: wgpu::Operations {
-                        load: wgpu::LoadOp::Clear(wgpu::Color {
-                            r: 0.0,
-                            g: 0.0,
-                            b: 0.0,
-                            a: 0.0,
-                        }),
-                        store: wgpu::StoreOp::Store,
-                    },
-                })],
-                depth_stencil_attachment: None,
-                timestamp_writes: None,
-                occlusion_query_set: None,
-            });
-
-            render_pass.set_pipeline(&self.render_pipeline);
-            render_pass.set_bind_group(0, &self.bind_group, &[]);
-            render_pass.set_bind_group(1, &self.uniform_bind_group, &[]);
-            render_pass.draw(0..6, 0..1);
-        }
-
-        self.queue.submit(Some(encoder.finish()));
-    }
-}
-
-struct Cached {
-    value: Option<(K, V)>,
-}
-
-impl Default for Cached {
-    fn default() -> Self {
-        Self { value: None }
-    }
-}
-
-impl Cached {
-    pub fn get_or_init(&mut self, key: K, init: impl FnOnce() -> V) -> &mut V {
-        if self.value.as_ref().is_none_or(|(k, _)| *k != key) {
-            self.value = Some((key, init()));
-        }
-
-        &mut self.value.as_mut().expect("checked above").1
-    }
-
-    pub fn get_latest_key(&self) -> Option<&K> {
-        self.value.as_ref().map(|(k, _)| k)
-    }
-}
-
-impl Cached {
-    pub fn update_key_and_should_init(&mut self, key: K) -> bool {
-        if self.value.as_ref().is_none_or(|(k, _)| *k != key) {
-            self.value = Some((key, ()));
-            true
-        } else {
-            false
-        }
-    }
-}
-
-#[repr(C)]
-#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
-struct StateUniforms {
-    shape: f32,
-    size: f32,
-    mirrored: f32,
-    _padding: f32,
-}
-
-#[repr(C)]
-#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
-struct WindowUniforms {
-    window_height: f32,
-    window_width: f32,
-    toolbar_percentage: f32,
-    _padding: f32,
-}
-
-#[repr(C)]
-#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
-struct CameraUniforms {
-    camera_aspect_ratio: f32,
-    _padding: f32,
-}
diff --git a/apps/desktop/src-tauri/src/camera.wgsl b/apps/desktop/src-tauri/src/camera.wgsl
deleted file mode 100644
index 7d5354bc9cf..00000000000
--- a/apps/desktop/src-tauri/src/camera.wgsl
+++ /dev/null
@@ -1,179 +0,0 @@
-struct StateUniforms {
-    shape: f32,
-    size: f32,
-    mirrored: f32,
-    _padding: f32,
-}
-
-struct WindowUniforms {
-    window_height: f32,
-    window_width: f32,
-    toolbar_percentage: f32,
-    _padding: f32,
-}
-
-struct CameraUniforms {
-    camera_aspect_ratio: f32,
-    _padding: f32,
-}
-
-@group(1) @binding(0)
-var uniforms: StateUniforms;
-
-@group(1) @binding(1)
-var window_uniforms: WindowUniforms;
-
-@group(1) @binding(2)
-var camera_uniforms: CameraUniforms;
-
-@group(0) @binding(0)
-var t_camera: texture_2d;
-
-@group(0) @binding(1)
-var s_camera: sampler;
-
-struct VertexOutput {
-    @builtin(position) position: vec4,
-    @location(0) uv: vec2,
-};
-
-@vertex
-fn vs_main(@builtin(vertex_index) idx: u32) -> VertexOutput {
-    var out: VertexOutput;
-
-    // We use the vertex_index to determine the position of each vertex.
-    // This maps the 6 vertex indices to NDC coordinates for a fullscreen quad.
-    var indexes = array, 6>(
-        vec2(-1.0, -1.0),// First triangle (bottom-left)
-        vec2(1.0, -1.0),
-        vec2(-1.0, 1.0),
-        vec2(-1.0, 1.0), // Second triangle (top-right)
-        vec2(1.0, -1.0),
-        vec2(1.0, 1.0),
-    );
-    var uv = array, 6>(
-        vec2(0.0, 1.0),
-        vec2(1.0, 1.0),
-        vec2(0.0, 0.0),
-        vec2(0.0, 0.0),
-        vec2(1.0, 1.0),
-        vec2(1.0, 0.0),
-    );
-
-    var pos: vec2 = indexes[idx];
-    pos.y *= (1.0 - window_uniforms.toolbar_percentage);
-    pos.y -= window_uniforms.toolbar_percentage;
-
-    out.position = vec4(pos, 0.0, 1.0);
-    out.uv = uv[idx];
-    return out;
-}
-
-@fragment
-fn fs_main(in: VertexOutput) -> @location(0) vec4 {
-    // Calculate the effective rendering dimensions (accounting for toolbar)
-    let effective_height = window_uniforms.window_height * (1.0 - window_uniforms.toolbar_percentage);
-    let crop_width = window_uniforms.window_width;
-    let crop_height = effective_height;
-    let crop_aspect = crop_width / crop_height;
-    let camera_aspect = camera_uniforms.camera_aspect_ratio;
-
-    // Calculate UV coordinates for proper "cover" behavior
-    var final_uv = in.uv;
-
-    // Determine which dimension needs to be scaled to cover the crop region
-    if (camera_aspect > crop_aspect) {
-        // Camera is wider than crop region - scale horizontally
-        let scale = crop_aspect / camera_aspect;
-        let offset = (1.0 - scale) * 0.5;
-        final_uv.x = final_uv.x * scale + offset;
-    } else {
-        // Camera is taller than crop region - scale vertically
-        let scale = camera_aspect / crop_aspect;
-        let offset = (1.0 - scale) * 0.5;
-        final_uv.y = final_uv.y * scale + offset;
-    }
-
-    // Apply mirroring if enabled
-    if (uniforms.mirrored == 1.0) {
-        final_uv.x = 1.0 - final_uv.x;
-    }
-
-    // Shape constants: 0 = Round, 1 = Square, 2 = Full
-    // Size constants: 0 = Sm, 1 = Lg
-    let shape = uniforms.shape;
-    let size = uniforms.size;
-
-    // Convert UV coordinates to center-based coordinates [-1, 1]
-    let center_uv = (in.uv - 0.5) * 2.0;
-
-    var mask = 1.0;
-
-    if (shape == 0.0) {
-        // Round shape with enhanced anti-aliasing
-        let distance = length(center_uv);
-        let radius = 1.0;
-
-        // Multi-level anti-aliasing approach
-        let pixel_size = length(fwidth(center_uv));
-        let aa_width = max(pixel_size, 0.003); // Reduced minimum AA width
-
-        // Primary edge calculation
-        let edge_distance = distance - radius;
-        mask = 1.0 - smoothstep(-aa_width, aa_width, edge_distance);
-
-    } else if (shape == 1.0) {
-        // Square shape with enhanced corner anti-aliasing
-        // Interpolate corner radius based on normalized size (0-1)
-        let corner_radius = mix(0.10, 0.14, size);
-        let abs_uv = abs(center_uv);
-        let corner_pos = abs_uv - (1.0 - corner_radius);
-        let corner_dist = length(max(corner_pos, vec2(0.0, 0.0)));
-
-        // Enhanced anti-aliasing for corners
-        let pixel_size = length(fwidth(center_uv));
-        let aa_width = max(pixel_size, 0.002);
-
-        let edge_distance = corner_dist - corner_radius;
-        mask = 1.0 - smoothstep(-aa_width, aa_width, edge_distance);
-    } else if (shape == 2.0) {
-        // Full shape with aspect ratio-corrected rounded corners
-        let window_aspect = crop_aspect;
-        // Interpolate corner radius based on normalized size (0-1)
-        let corner_radius = mix(0.08, 0.12, size);
-
-        let abs_uv = abs(center_uv);
-        let corner_pos = abs_uv - (1.0 - corner_radius);
-
-        // Use aspect-ratio aware distance calculation for circular corners
-        var adjusted_corner_pos = max(corner_pos, vec2(0.0, 0.0));
-        if (window_aspect > 1.0) {
-            // For wide windows, scale X component to make distance calculation circular
-            adjusted_corner_pos.x *= window_aspect;
-        } else {
-            // For tall windows, scale Y component to make distance calculation circular
-            adjusted_corner_pos.y /= window_aspect;
-        }
-
-        let corner_dist = length(adjusted_corner_pos);
-
-        // Enhanced anti-aliasing for corners
-        let pixel_size = length(fwidth(center_uv));
-        let aa_width = max(pixel_size, 0.002);
-
-        let edge_distance = corner_dist - corner_radius;
-        mask = 1.0 - smoothstep(-aa_width, aa_width, edge_distance);
-    } else {
-        // For any other shape, default to no masking (rectangular)
-        mask = 1.0;
-    }
-
-    if (mask < 0.05) {
-        return vec4(0.0, 0.0, 0.0, 0.0);
-    }
-
-    let camera_color = textureSample(t_camera, s_camera, final_uv);
-
-    let final_alpha = camera_color.a * select(1.0, mask, mask < 0.95);
-    return vec4(camera_color.rgb, final_alpha);
-}
diff --git a/apps/desktop/src-tauri/src/camera_legacy.rs b/apps/desktop/src-tauri/src/camera_legacy.rs
deleted file mode 100644
index 4c4655f9538..00000000000
--- a/apps/desktop/src-tauri/src/camera_legacy.rs
+++ /dev/null
@@ -1,1084 +0,0 @@
-use std::sync::Arc;
-use std::sync::atomic::{AtomicU8, AtomicUsize, Ordering};
-use std::time::{Duration, Instant};
-
-use cap_recording::FFmpegVideoFrame;
-#[cfg(target_os = "macos")]
-use cap_utils::macos_qos::{MacOsQosClass, set_current_thread_qos};
-use flume::Sender;
-use tokio::sync::watch;
-use tokio_util::sync::CancellationToken;
-
-use crate::camera::{CameraPreviewState, MAX_CAMERA_SIZE, MIN_CAMERA_SIZE, is_low_spec_preview};
-use crate::frame_ws::{WSFrame, WSFrameFormat, create_watch_frame_ws_with_instant_tracking};
-
-const WS_READBACK_PENDING: u8 = 0;
-const WS_READBACK_READY_OK: u8 = 1;
-const WS_READBACK_READY_ERR: u8 = 2;
-
-const WS_READBACK_CONSUMED: u8 = 3;
-
-#[cfg(target_os = "linux")]
-type OutputReceipt = Option;
-#[cfg(not(target_os = "linux"))]
-#[derive(Default)]
-struct PreviewReceipt;
-#[cfg(not(target_os = "linux"))]
-type OutputReceipt = PreviewReceipt;
-
-struct ReadbackTicket {
-    status: Arc,
-    receipt: OutputReceipt,
-}
-
-impl ReadbackTicket {
-    fn new(receipt: OutputReceipt) -> Self {
-        Self {
-            status: Arc::new(AtomicU8::new(WS_READBACK_PENDING)),
-            receipt,
-        }
-    }
-
-    fn take_ready(&mut self) -> Result, String> {
-        match self.status.load(Ordering::Acquire) {
-            WS_READBACK_READY_OK => {
-                self.status.store(WS_READBACK_CONSUMED, Ordering::Release);
-                Ok(Some(std::mem::take(&mut self.receipt)))
-            }
-            WS_READBACK_READY_ERR => {
-                self.status.store(WS_READBACK_CONSUMED, Ordering::Release);
-                Err("Requested camera blur GPU readback failed".into())
-            }
-            _ => Ok(None),
-        }
-    }
-}
-
-enum WsReadbackState {
-    Idle,
-    InFlight(ReadbackTicket),
-}
-
-struct WsReadback {
-    buffer: wgpu::Buffer,
-    state: WsReadbackState,
-}
-
-struct BlurInput<'a> {
-    rgba: &'a [u8],
-    width: u32,
-    height: u32,
-    stride: u32,
-    mode: cap_camera_effects::BlurMode,
-    receipt: OutputReceipt,
-}
-
-struct BlurredFrame {
-    data: Arc>,
-    #[cfg(target_os = "linux")]
-    receipt: Option,
-}
-
-pub struct CameraPreviewWs {
-    pub sender: Sender,
-    pub port: u16,
-    pub shutdown: CancellationToken,
-    #[cfg(target_os = "linux")]
-    pub processing: crate::linux_instant_camera::ProcessingFactory,
-}
-
-#[cfg(target_os = "linux")]
-enum WorkerEvent {
-    Frame(F),
-    Command(C),
-    Closed,
-    Tick,
-}
-
-#[cfg(target_os = "linux")]
-fn next_worker_event(
-    frames: &flume::Receiver,
-    commands: &flume::Receiver,
-    timeout: Option,
-) -> WorkerEvent {
-    let selector = flume::Selector::new()
-        .recv(frames, |result| {
-            result.map_or(WorkerEvent::Closed, WorkerEvent::Frame)
-        })
-        .recv(commands, |result| {
-            result.map_or(WorkerEvent::Closed, WorkerEvent::Command)
-        });
-    match timeout {
-        Some(timeout) => selector.wait_timeout(timeout).unwrap_or(WorkerEvent::Tick),
-        None => selector.wait(),
-    }
-}
-
-fn processing_needed(preview: bool, recording: bool) -> bool {
-    preview || recording
-}
-
-const WS_PREVIEW_SURFACE_SCALE: u32 = 2;
-// Same drag-resize hysteresis as the native preview: only rebuild the scaler
-// and reallocate buffers when the target width crosses a 64px bucket.
-const WS_PREVIEW_WIDTH_BUCKET: u32 = 64;
-const WS_PREVIEW_MIN_WIDTH: u32 = 320;
-const WS_PREVIEW_MAX_WIDTH: u32 = 960;
-const WS_PREVIEW_MAX_HEIGHT: u32 = 540;
-const WS_PREVIEW_BLUR_MAX_WIDTH: u32 = 640;
-const WS_PREVIEW_BLUR_MAX_HEIGHT: u32 = 360;
-const WS_PREVIEW_TARGET_FRAME_INTERVAL: Duration = Duration::from_micros(16_666);
-const WS_PREVIEW_FRAME_INTERVAL_SLACK: Duration = Duration::from_millis(1);
-const WS_BLUR_INFERENCE_INTERVAL: Duration =
-    Duration::from_millis(if cfg!(target_os = "macos") { 33 } else { 150 });
-
-// Low-spec preview profile (mirrors the native path in camera.rs). Only used
-// when `is_low_spec_preview()` is true (machines <= 8GB RAM detected at
-// startup); high-spec machines use the constants above bit-for-bit.
-const WS_PREVIEW_LOW_SPEC_MAX_WIDTH: u32 = 640;
-const WS_PREVIEW_LOW_SPEC_MAX_HEIGHT: u32 = 360;
-const WS_PREVIEW_LOW_SPEC_TARGET_FRAME_INTERVAL: Duration = Duration::from_micros(33_333);
-const FRAME_POOL_LOW_SPEC_MAX: usize = 2;
-
-fn preview_frame_due(last_preview_at: Option, now: Instant) -> bool {
-    // High-spec keeps the original 60fps target; low-spec paces at 30fps.
-    let target_interval = if is_low_spec_preview() {
-        WS_PREVIEW_LOW_SPEC_TARGET_FRAME_INTERVAL
-    } else {
-        WS_PREVIEW_TARGET_FRAME_INTERVAL
-    };
-    last_preview_at.is_none_or(|last| {
-        now.saturating_duration_since(last) + WS_PREVIEW_FRAME_INTERVAL_SLACK >= target_interval
-    })
-}
-
-const FRAME_POOL_MAX: usize = 4;
-
-/// Frame-pool cap, lowered on low-spec to hold fewer ~2MB buffers in memory.
-#[inline]
-fn frame_pool_max() -> usize {
-    if is_low_spec_preview() {
-        FRAME_POOL_LOW_SPEC_MAX
-    } else {
-        FRAME_POOL_MAX
-    }
-}
-
-// Reuses a previously-sent frame buffer once every WSFrame referencing it has
-// been dropped (watch cell replaced + socket sends finished), eliminating the
-// ~2MB allocation + page-fault churn per frame at steady state.
-fn with_pooled_buffer(
-    pool: &mut Vec>>,
-    fill: impl FnOnce(&mut Vec),
-) -> Arc> {
-    for buf in pool.iter_mut() {
-        if Arc::strong_count(buf) == 1
-            && let Some(vec) = Arc::get_mut(buf)
-        {
-            vec.clear();
-            fill(vec);
-            return buf.clone();
-        }
-    }
-
-    let mut vec = Vec::new();
-    fill(&mut vec);
-    let buf = Arc::new(vec);
-    if pool.len() < frame_pool_max() {
-        pool.push(buf.clone());
-    }
-    buf
-}
-
-fn pack_plane_rows(dst: &mut Vec, src: &[u8], row_bytes: usize, height: u32, stride: u32) {
-    let stride = stride as usize;
-    let height = height as usize;
-    dst.reserve(row_bytes * height);
-    if stride == row_bytes {
-        dst.extend_from_slice(&src[..row_bytes * height]);
-    } else {
-        for row in 0..height {
-            let start = row * stride;
-            dst.extend_from_slice(&src[start..start + row_bytes]);
-        }
-    }
-}
-
-fn pack_rgba_rows(dst: &mut Vec, frame: &ffmpeg::util::frame::Video) {
-    pack_plane_rows(
-        dst,
-        frame.data(0),
-        frame.width() as usize * 4,
-        frame.height(),
-        frame.stride(0) as u32,
-    );
-}
-
-fn pack_nv12_planes(dst: &mut Vec, frame: &ffmpeg::util::frame::Video) {
-    let width = frame.width() as usize;
-    pack_plane_rows(
-        dst,
-        frame.data(0),
-        width,
-        frame.height(),
-        frame.stride(0) as u32,
-    );
-    pack_plane_rows(
-        dst,
-        frame.data(1),
-        width,
-        frame.height() / 2,
-        frame.stride(1) as u32,
-    );
-}
-
-fn prepare_ws_data(
-    frame: &ffmpeg::util::frame::Video,
-    format: WSFrameFormat,
-    frame_pool: &mut Vec>>,
-) -> (Arc>, u32) {
-    match format {
-        WSFrameFormat::Rgba => (
-            with_pooled_buffer(frame_pool, |vec| pack_rgba_rows(vec, frame)),
-            frame.width() * 4,
-        ),
-        WSFrameFormat::Nv12 { .. } => (
-            with_pooled_buffer(frame_pool, |vec| pack_nv12_planes(vec, frame)),
-            frame.width(),
-        ),
-    }
-}
-
-fn scaled_preview_dimensions(width: u32, height: u32, state: &CameraPreviewState) -> (u32, u32) {
-    let blur_enabled = state.background_blur != cap_project::BackgroundBlurMode::Off;
-    let (max_width, max_height) = if is_low_spec_preview() {
-        // Low-spec caps preview to 640x360 (blur is skipped on low-spec, so the
-        // blur-vs-no-blur branch below does not apply).
-        (
-            WS_PREVIEW_LOW_SPEC_MAX_WIDTH,
-            WS_PREVIEW_LOW_SPEC_MAX_HEIGHT,
-        )
-    } else if blur_enabled {
-        (WS_PREVIEW_BLUR_MAX_WIDTH, WS_PREVIEW_BLUR_MAX_HEIGHT)
-    } else {
-        (WS_PREVIEW_MAX_WIDTH, WS_PREVIEW_MAX_HEIGHT)
-    };
-    let visible_width = (state.size.clamp(MIN_CAMERA_SIZE, MAX_CAMERA_SIZE) as u32)
-        .saturating_mul(WS_PREVIEW_SURFACE_SCALE);
-    let requested_width = visible_width
-        .max(WS_PREVIEW_MIN_WIDTH)
-        .div_ceil(WS_PREVIEW_WIDTH_BUCKET)
-        .saturating_mul(WS_PREVIEW_WIDTH_BUCKET)
-        .min(max_width);
-    let width_scale = requested_width as f64 / width.max(1) as f64;
-    let height_scale = max_height as f64 / height.max(1) as f64;
-    let scale = width_scale.min(height_scale).min(1.0);
-    let target_width = ((width as f64 * scale).round() as u32).max(1);
-    let target_height = ((height as f64 * scale).round() as u32).max(1);
-    (target_width, target_height)
-}
-
-pub async fn create_camera_preview_ws(
-    state_rx: watch::Receiver,
-) -> CameraPreviewWs {
-    let (camera_tx, camera_rx) = flume::bounded::(1);
-    #[cfg(target_os = "linux")]
-    let (processing, commands) = crate::linux_instant_camera::processing_channel();
-    let (frame_tx, frame_rx) = watch::channel::>>(None);
-    let subscriber_count = Arc::new(AtomicUsize::new(0));
-    let instant_subscriber_count = Arc::new(AtomicUsize::new(0));
-    let frame_tx_clone = frame_tx.clone();
-    let thread_subscriber_count = subscriber_count.clone();
-    let thread_instant_subscriber_count = instant_subscriber_count.clone();
-    std::thread::spawn(move || {
-        use ffmpeg::format::Pixel;
-
-        #[cfg(target_os = "macos")]
-        {
-            let result = set_current_thread_qos(MacOsQosClass::UserInteractive);
-            if result != 0 {
-                tracing::warn!(result, "pthread_set_qos_class_self_np failed");
-            }
-        }
-        #[cfg(windows)]
-        {
-            use windows::Win32::System::Threading::{
-                GetCurrentThread, SetThreadPriority, THREAD_PRIORITY_ABOVE_NORMAL,
-            };
-            if let Err(err) =
-                unsafe { SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL) }
-            {
-                tracing::warn!("SetThreadPriority failed: {err}");
-            }
-        }
-
-        let mut converter: Option<(Pixel, Pixel, ffmpeg::software::scaling::Context)> = None;
-        let mut reusable_frame: Option = None;
-        let mut state_rx = state_rx;
-
-        let mut blur_state = WsBlurState::new();
-        let mut last_preview_at = None;
-        let mut frame_pool: Vec>> = Vec::new();
-        let mut frame_counter: u32 = 0;
-        let mut idle = true;
-        #[cfg(target_os = "linux")]
-        let mut recording: Option = None;
-        #[cfg(target_os = "linux")]
-        let mut warm_until: Option = None;
-        loop {
-            #[cfg(target_os = "linux")]
-            if recording.as_ref().is_some_and(|work| work.cancelled()) {
-                recording = None;
-                warm_until = Some(Instant::now() + Duration::from_millis(500));
-            }
-            #[cfg(target_os = "linux")]
-            if let Some(deadline) = warm_until {
-                if thread_subscriber_count.load(Ordering::Acquire) > 0 {
-                    warm_until = None;
-                } else if Instant::now() >= deadline {
-                    converter = None;
-                    reusable_frame = None;
-                    frame_pool.clear();
-                    blur_state.release();
-                    last_preview_at = None;
-                    idle = true;
-                    warm_until = None;
-                    let _previous_frame = frame_tx_clone.send_replace(None);
-                }
-            }
-            let input = &camera_rx;
-            #[cfg(target_os = "linux")]
-            let input = recording.as_ref().map_or(input, |work| &work.frames);
-            #[cfg(target_os = "linux")]
-            let raw_frame = {
-                let timeout = if recording.is_some() {
-                    Some(Duration::from_millis(50))
-                } else {
-                    warm_until.map(|deadline| deadline.saturating_duration_since(Instant::now()))
-                };
-                let event = next_worker_event(input, &commands, timeout);
-                match event {
-                    WorkerEvent::Frame(frame) => frame,
-                    WorkerEvent::Command(work) => {
-                        if work.cancelled() {
-                            continue;
-                        }
-                        if recording.is_some() {
-                            work.fail("Another camera processing lease is active");
-                            continue;
-                        }
-                        warm_until = None;
-                        blur_state.begin_recording_epoch();
-                        last_preview_at = None;
-                        recording = Some(*work);
-                        continue;
-                    }
-                    WorkerEvent::Closed => break,
-                    WorkerEvent::Tick => continue,
-                }
-            };
-            #[cfg(not(target_os = "linux"))]
-            let raw_frame = match input.recv() {
-                Ok(frame) => frame,
-                Err(_) => break,
-            };
-            let mut raw_frame = raw_frame;
-            while let Ok(newer) = input.try_recv() {
-                raw_frame = newer;
-            }
-            #[cfg(target_os = "linux")]
-            if let Some(work) = &recording {
-                match work.accepts(raw_frame.timestamp) {
-                    Ok(true) => {}
-                    Ok(false) => continue,
-                    Err(error) => {
-                        work.fail(error);
-                        continue;
-                    }
-                }
-            }
-            #[cfg(target_os = "linux")]
-            let capture_timestamp = raw_frame.timestamp;
-            let frame = raw_frame.inner;
-            let instant_preview_active =
-                thread_instant_subscriber_count.load(Ordering::Acquire) > 0;
-            let ws_active = thread_subscriber_count.load(Ordering::Acquire) > 0;
-            #[cfg(target_os = "linux")]
-            let recording_active = recording.is_some();
-            #[cfg(not(target_os = "linux"))]
-            let recording_active = false;
-            let processing_active = processing_needed(ws_active, recording_active);
-            if !processing_active {
-                #[cfg(target_os = "linux")]
-                if warm_until.is_some() {
-                    continue;
-                }
-                if !idle {
-                    idle = true;
-                    converter = None;
-                    reusable_frame = None;
-                    frame_pool.clear();
-                    blur_state.release();
-                    last_preview_at = None;
-                    let _previous_frame = frame_tx_clone.send_replace(None);
-                }
-                continue;
-            }
-            idle = false;
-            let now = Instant::now();
-            if !preview_frame_due(last_preview_at, now) {
-                continue;
-            }
-            last_preview_at = Some(now);
-            let state = state_rx.borrow_and_update().clone();
-            #[cfg(target_os = "linux")]
-            let state = recording.as_ref().map_or(state, |work| work.state.clone());
-            let blur_mode = state.background_blur;
-            let blur_enabled = blur_mode != cap_project::BackgroundBlurMode::Off;
-            let effects_mode = match blur_mode {
-                cap_project::BackgroundBlurMode::Off | cap_project::BackgroundBlurMode::Light => {
-                    cap_camera_effects::BlurMode::Light
-                }
-                cap_project::BackgroundBlurMode::Heavy => cap_camera_effects::BlurMode::Heavy,
-                cap_project::BackgroundBlurMode::Remove => cap_camera_effects::BlurMode::Remove,
-            };
-            let (mut target_width, mut target_height) =
-                scaled_preview_dimensions(frame.width(), frame.height(), &state);
-            let use_nv12 = cfg!(target_os = "macos")
-                && instant_preview_active
-                && !blur_enabled
-                && frame.format() == Pixel::NV12;
-            let (output_pixel, output_format) = if use_nv12 {
-                target_width = target_width.max(2) & !1;
-                target_height = target_height.max(2) & !1;
-                (
-                    Pixel::NV12,
-                    WSFrameFormat::Nv12 {
-                        full_range: frame.color_range() == ffmpeg::color::Range::JPEG,
-                    },
-                )
-            } else {
-                (Pixel::RGBA, WSFrameFormat::Rgba)
-            };
-            let needs_convert = frame.format() != output_pixel
-                || frame.width() != target_width
-                || frame.height() != target_height;
-            if !blur_enabled {
-                blur_state.release();
-            }
-            let output_frame = if needs_convert {
-                let ctx = match &mut converter {
-                    Some((input_format, cached_output_format, ctx))
-                        if *input_format == frame.format()
-                            && *cached_output_format == output_pixel
-                            && ctx.input().width == frame.width()
-                            && ctx.input().height == frame.height()
-                            && ctx.output().width == target_width
-                            && ctx.output().height == target_height =>
-                    {
-                        ctx
-                    }
-                    _ => {
-                        let new_converter = ffmpeg::software::scaling::Context::get(
-                            frame.format(),
-                            frame.width(),
-                            frame.height(),
-                            output_pixel,
-                            target_width,
-                            target_height,
-                            ffmpeg::software::scaling::flag::Flags::FAST_BILINEAR,
-                        );
-                        let Ok(new_converter) = new_converter else {
-                            #[cfg(target_os = "linux")]
-                            if let Some(work) = &recording {
-                                work.fail("Camera pixel conversion is unavailable");
-                            }
-                            continue;
-                        };
-                        reusable_frame = None;
-                        &mut converter
-                            .insert((frame.format(), output_pixel, new_converter))
-                            .2
-                    }
-                };
-                let out_frame = reusable_frame.get_or_insert_with(|| {
-                    ffmpeg::util::frame::Video::new(
-                        output_pixel,
-                        ctx.output().width,
-                        ctx.output().height,
-                    )
-                });
-                if ctx.run(&frame, out_frame).is_err() {
-                    #[cfg(target_os = "linux")]
-                    if let Some(work) = &recording {
-                        work.fail("Camera pixel conversion failed");
-                    }
-                    continue;
-                }
-                &*out_frame
-            } else {
-                &frame
-            };
-            let width = output_frame.width();
-            let height = output_frame.height();
-            #[cfg(target_os = "linux")]
-            let receipt = recording
-                .as_ref()
-                .map(|work| work.receipt(capture_timestamp, (width, height)));
-            let blurred = if blur_enabled {
-                blur_state.process(
-                    BlurInput {
-                        rgba: output_frame.data(0),
-                        width,
-                        height,
-                        stride: output_frame.stride(0) as u32,
-                        mode: effects_mode,
-                        #[cfg(target_os = "linux")]
-                        receipt: receipt.clone(),
-                        #[cfg(not(target_os = "linux"))]
-                        receipt: PreviewReceipt,
-                    },
-                    &mut frame_pool,
-                )
-            } else {
-                Ok(None)
-            };
-            #[cfg(target_os = "linux")]
-            if let Some(work) = &recording {
-                if !blur_enabled {
-                    let (data, _) = prepare_ws_data(output_frame, output_format, &mut frame_pool);
-                    work.publish(&data, receipt.unwrap());
-                } else {
-                    match &blurred {
-                        Ok(Some(output)) => {
-                            if let Some(receipt) = output.receipt.clone() {
-                                work.publish(&output.data, receipt);
-                            }
-                        }
-                        Ok(None) => {}
-                        Err(error) => work.fail(error.clone()),
-                    }
-                }
-            }
-            if ws_active {
-                if blur_mode == cap_project::BackgroundBlurMode::Remove
-                    && matches!(blurred, Ok(None))
-                {
-                    continue;
-                }
-                let (data, stride) = blurred
-                    .ok()
-                    .flatten()
-                    .map(|frame| (frame.data, width * 4))
-                    .unwrap_or_else(|| {
-                        prepare_ws_data(output_frame, output_format, &mut frame_pool)
-                    });
-                frame_counter = frame_counter.wrapping_add(1);
-                let _previous_frame = frame_tx_clone.send_replace(Some(Arc::new(WSFrame {
-                    data: data.into(),
-                    width,
-                    height,
-                    stride,
-                    frame_number: frame_counter,
-                    target_time_ns: 0,
-                    format: output_format,
-                    created_at: Instant::now(),
-                })));
-            } else {
-                frame_tx_clone.send_if_modified(|frame| frame.take().is_some());
-            }
-        }
-    });
-    let (camera_ws_port, _shutdown) = create_watch_frame_ws_with_instant_tracking(
-        frame_rx,
-        subscriber_count,
-        instant_subscriber_count,
-    )
-    .await;
-
-    CameraPreviewWs {
-        sender: camera_tx,
-        port: camera_ws_port,
-        shutdown: _shutdown,
-        #[cfg(target_os = "linux")]
-        processing,
-    }
-}
-
-struct WsBlurState {
-    processor: Option,
-    init_attempted: bool,
-}
-
-struct WsBlurResources {
-    device: wgpu::Device,
-    queue: wgpu::Queue,
-    processor: cap_camera_effects::BlurProcessor,
-    source_texture: Option<(u32, u32, wgpu::Texture)>,
-    readbacks: Option<(u32, u32, [WsReadback; 2])>,
-    current_idx: usize,
-    mode: Option,
-}
-
-impl WsBlurState {
-    fn new() -> Self {
-        Self {
-            processor: None,
-            init_attempted: false,
-        }
-    }
-
-    #[cfg(target_os = "linux")]
-    fn begin_recording_epoch(&mut self) {
-        if let Some(resources) = &mut self.processor {
-            resources.readbacks = None;
-            resources.current_idx = 0;
-            resources.processor.reset_mask_history();
-        } else {
-            self.init_attempted = false;
-        }
-    }
-
-    // Drops the dedicated wgpu device, ONNX session, and readback buffers as
-    // soon as blur is off; re-enabling re-runs the lazy init.
-    fn release(&mut self) {
-        if self.processor.is_some() {
-            self.processor = None;
-            tracing::info!("Released WebSocket camera blur resources");
-        }
-        self.init_attempted = false;
-    }
-
-    fn process(
-        &mut self,
-        input: BlurInput<'_>,
-        pool: &mut Vec>>,
-    ) -> Result, String> {
-        let BlurInput {
-            rgba: rgba_data,
-            width,
-            height,
-            stride,
-            mode,
-            receipt,
-        } = input;
-        // Idle preview keeps its compatibility fallback; recording requires this error to stay terminal.
-        if is_low_spec_preview() || cap_camera_effects::blur_disabled() {
-            return Err("Requested camera blur is disabled or unavailable on this device".into());
-        }
-
-        if !self.init_attempted {
-            self.init_attempted = true;
-            self.processor = Some(init_headless_blur()?);
-        }
-
-        let res = self
-            .processor
-            .as_mut()
-            .ok_or("Requested camera blur initialization failed")?;
-
-        if res.mode != Some(mode) {
-            res.readbacks = None;
-            res.current_idx = 0;
-            res.mode = Some(mode);
-        }
-
-        #[cfg(target_os = "linux")]
-        if receipt.as_ref().is_some_and(|receipt| matches!(receipt.timestamp,
-            cap_timestamp::Timestamp::Instant(captured) if captured.elapsed() > Duration::from_secs(1))) {
-            return Ok(None);
-        }
-
-        let src = match &res.source_texture {
-            Some((w, h, t)) if *w == width && *h == height => t,
-            _ => {
-                let tex = res.device.create_texture(&wgpu::TextureDescriptor {
-                    label: Some("WS Blur Source"),
-                    size: wgpu::Extent3d {
-                        width,
-                        height,
-                        depth_or_array_layers: 1,
-                    },
-                    mip_level_count: 1,
-                    sample_count: 1,
-                    dimension: wgpu::TextureDimension::D2,
-                    format: wgpu::TextureFormat::Rgba8Unorm,
-                    usage: wgpu::TextureUsages::TEXTURE_BINDING
-                        | wgpu::TextureUsages::COPY_DST
-                        | wgpu::TextureUsages::COPY_SRC,
-                    view_formats: &[],
-                });
-                res.source_texture = Some((width, height, tex));
-                &res.source_texture.as_ref().unwrap().2
-            }
-        };
-
-        let bytes_per_row_aligned = (width * 4 + 255) & !255;
-        let buf_size = (bytes_per_row_aligned * height) as u64;
-
-        let readbacks_match = matches!(
-            &res.readbacks,
-            Some((w, h, _)) if *w == width && *h == height
-        );
-        if !readbacks_match {
-            let make_buf = |label: &str| {
-                res.device.create_buffer(&wgpu::BufferDescriptor {
-                    label: Some(label),
-                    size: buf_size,
-                    usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
-                    mapped_at_creation: false,
-                })
-            };
-            let readbacks = [
-                WsReadback {
-                    buffer: make_buf("WS Blur Readback 0"),
-                    state: WsReadbackState::Idle,
-                },
-                WsReadback {
-                    buffer: make_buf("WS Blur Readback 1"),
-                    state: WsReadbackState::Idle,
-                },
-            ];
-            res.readbacks = Some((width, height, readbacks));
-            res.current_idx = 0;
-        }
-
-        let _ = res.device.poll(wgpu::PollType::Poll);
-
-        let current_idx = res.current_idx;
-        let prev_idx = 1 - current_idx;
-
-        let prev_data = try_drain_readback(
-            &mut res.readbacks.as_mut().unwrap().2[prev_idx],
-            width,
-            height,
-            bytes_per_row_aligned,
-            pool,
-        );
-        let curr_data = try_drain_readback(
-            &mut res.readbacks.as_mut().unwrap().2[current_idx],
-            width,
-            height,
-            bytes_per_row_aligned,
-            pool,
-        );
-        #[cfg(target_os = "linux")]
-        let require_verified_output = receipt.is_some();
-        #[cfg(not(target_os = "linux"))]
-        let require_verified_output = false;
-        let blurred_out = if require_verified_output {
-            prev_data?.or(curr_data?)
-        } else {
-            prev_data.ok().flatten().or(curr_data.ok().flatten())
-        };
-
-        let issue_idx = if matches!(
-            res.readbacks.as_ref().unwrap().2[current_idx].state,
-            WsReadbackState::Idle
-        ) {
-            Some(current_idx)
-        } else if matches!(
-            res.readbacks.as_ref().unwrap().2[prev_idx].state,
-            WsReadbackState::Idle
-        ) {
-            Some(prev_idx)
-        } else {
-            None
-        };
-
-        if let Some(idx) = issue_idx {
-            res.queue.write_texture(
-                wgpu::TexelCopyTextureInfo {
-                    texture: src,
-                    mip_level: 0,
-                    origin: wgpu::Origin3d::ZERO,
-                    aspect: wgpu::TextureAspect::All,
-                },
-                rgba_data,
-                wgpu::TexelCopyBufferLayout {
-                    offset: 0,
-                    bytes_per_row: Some(stride),
-                    rows_per_image: Some(height),
-                },
-                wgpu::Extent3d {
-                    width,
-                    height,
-                    depth_or_array_layers: 1,
-                },
-            );
-
-            let output = res.processor.process(&res.device, &res.queue, src, mode);
-
-            let mut encoder = res
-                .device
-                .create_command_encoder(&wgpu::CommandEncoderDescriptor {
-                    label: Some("WS Blur Copy"),
-                });
-
-            encoder.copy_texture_to_buffer(
-                wgpu::TexelCopyTextureInfo {
-                    texture: output,
-                    mip_level: 0,
-                    origin: wgpu::Origin3d::ZERO,
-                    aspect: wgpu::TextureAspect::All,
-                },
-                wgpu::TexelCopyBufferInfo {
-                    buffer: &res.readbacks.as_ref().unwrap().2[idx].buffer,
-                    layout: wgpu::TexelCopyBufferLayout {
-                        offset: 0,
-                        bytes_per_row: Some(bytes_per_row_aligned),
-                        rows_per_image: Some(height),
-                    },
-                },
-                wgpu::Extent3d {
-                    width,
-                    height,
-                    depth_or_array_layers: 1,
-                },
-            );
-
-            #[cfg(target_os = "linux")]
-            let receipt = receipt.map(|mut receipt| {
-                receipt.blur = res.processor.output_status();
-                receipt
-            });
-            res.queue.submit(std::iter::once(encoder.finish()));
-            let ticket = ReadbackTicket::new(receipt);
-            let status_cb = ticket.status.clone();
-            res.readbacks.as_ref().unwrap().2[idx]
-                .buffer
-                .slice(..)
-                .map_async(wgpu::MapMode::Read, move |result| {
-                    status_cb.store(
-                        if result.is_ok() {
-                            WS_READBACK_READY_OK
-                        } else {
-                            WS_READBACK_READY_ERR
-                        },
-                        Ordering::Release,
-                    );
-                });
-            res.readbacks.as_mut().unwrap().2[idx].state = WsReadbackState::InFlight(ticket);
-            res.current_idx = 1 - idx;
-        }
-
-        Ok(blurred_out)
-    }
-}
-
-fn try_drain_readback(
-    readback: &mut WsReadback,
-    width: u32,
-    height: u32,
-    bytes_per_row_aligned: u32,
-    pool: &mut Vec>>,
-) -> Result, String> {
-    let WsReadbackState::InFlight(ticket) = &mut readback.state else {
-        return Ok(None);
-    };
-    let receipt = match ticket.take_ready() {
-        Ok(Some(receipt)) => receipt,
-        Ok(None) => return Ok(None),
-        Err(error) => {
-            readback.buffer.unmap();
-            readback.state = WsReadbackState::Idle;
-            return Err(error);
-        }
-    };
-    let slice = readback.buffer.slice(..);
-    let data = slice.get_mapped_range();
-    let row_bytes = (width * 4) as usize;
-    let out = with_pooled_buffer(pool, |vec| {
-        vec.reserve(row_bytes * height as usize);
-        for row in 0..height as usize {
-            let start = row * bytes_per_row_aligned as usize;
-            vec.extend_from_slice(&data[start..start + row_bytes]);
-        }
-    });
-    drop(data);
-    readback.buffer.unmap();
-    readback.state = WsReadbackState::Idle;
-    #[cfg(not(target_os = "linux"))]
-    let _ = receipt;
-    Ok(Some(BlurredFrame {
-        data: out,
-        #[cfg(target_os = "linux")]
-        receipt,
-    }))
-}
-
-fn init_headless_blur() -> Result {
-    // Arm the sentinel's blur marker around the blur-dedicated wgpu
-    // adapter/device setup too, so a native death here is attributed to blur.
-    // Deliberately not `enter_gpu_init_phase`: that would cross-trigger WARP
-    // software-graphics recovery and cripple the editor for a blur-only crash.
-    crate::crash_sentinel::enter_blur_session();
-    struct BlurSessionGuard;
-    impl Drop for BlurSessionGuard {
-        fn drop(&mut self) {
-            crate::crash_sentinel::exit_blur_session();
-        }
-    }
-    let _guard = BlurSessionGuard;
-
-    let instance = cap_rendering::create_wgpu_instance_sync();
-    let force_software_adapter = cap_rendering::force_software_wgpu_adapter();
-    let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
-        power_preference: wgpu::PowerPreference::LowPower,
-        force_fallback_adapter: force_software_adapter,
-        compatible_surface: None,
-    }))
-    .map_err(|error| format!("Camera blur adapter unavailable: {error}"))?;
-
-    let (device, queue) = pollster::block_on(adapter.request_device(&wgpu::DeviceDescriptor {
-        label: Some("WS Blur Device"),
-        required_features: wgpu::Features::empty(),
-        required_limits:
-            wgpu::Limits::downlevel_webgl2_defaults().using_resolution(adapter.limits()),
-        memory_hints: Default::default(),
-        trace: wgpu::Trace::Off,
-    }))
-    .map_err(|error| format!("Camera blur device unavailable: {error}"))?;
-
-    let mut processor =
-        cap_camera_effects::BlurProcessor::new(&device, wgpu::TextureFormat::Rgba8Unorm)
-            .map_err(|error| format!("Camera blur processor unavailable: {error}"))?;
-    processor.set_inference_interval(WS_BLUR_INFERENCE_INTERVAL);
-
-    tracing::info!("WebSocket camera blur processor initialized (headless)");
-
-    Ok(WsBlurResources {
-        device,
-        queue,
-        processor,
-        source_texture: None,
-        readbacks: None,
-        current_idx: 0,
-        mode: None,
-    })
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn packs_plane_rows_without_stride_padding() {
-        let src = [0, 1, 2, 3, 90, 91, 4, 5, 6, 7, 92, 93, 8, 9, 10, 11, 94, 95];
-        let mut dst = vec![99];
-
-        pack_plane_rows(&mut dst, &src, 4, 3, 6);
-
-        assert_eq!(dst, [99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
-    }
-
-    #[test]
-    fn packs_contiguous_plane_as_one_slice() {
-        let src = [0, 1, 2, 3, 4, 5, 6, 7];
-        let mut dst = Vec::new();
-
-        pack_plane_rows(&mut dst, &src, 4, 2, 4);
-
-        assert_eq!(dst, src);
-    }
-
-    #[cfg(target_os = "linux")]
-    fn receipt(generation: u64, captured: Instant) -> crate::linux_instant_camera::FrameReceipt {
-        crate::linux_instant_camera::FrameReceipt {
-            timestamp: cap_timestamp::Timestamp::Instant(captured),
-            generation,
-            processing: cap_recording::instant_recording::LinuxCameraProcessing {
-                mirrored: false,
-                blur: cap_recording::instant_recording::LinuxCameraBlur::Off,
-            },
-            dimensions: (2, 1),
-            blur: None,
-        }
-    }
-
-    #[cfg(target_os = "linux")]
-    #[tokio::test]
-    async fn asynchronous_readback_keeps_its_original_capture_and_generation() {
-        let first = Instant::now();
-        let second = first + Duration::from_millis(10);
-        let mut a = ReadbackTicket::new(Some(receipt(7, first)));
-        let mut b = ReadbackTicket::new(Some(receipt(8, second)));
-        let a_ready = a.status.clone();
-        let b_ready = b.status.clone();
-        let (release, delayed) = tokio::sync::oneshot::channel();
-        let (ready, notified) = tokio::sync::oneshot::channel();
-        let worker = tokio::spawn(async move {
-            b_ready.store(WS_READBACK_READY_OK, Ordering::Release);
-            ready.send(()).unwrap();
-            delayed.await.unwrap();
-            a_ready.store(WS_READBACK_READY_OK, Ordering::Release);
-        });
-        notified.await.unwrap();
-        assert!(a.take_ready().unwrap().is_none());
-        let newer = b.take_ready().unwrap().unwrap().unwrap();
-        assert_eq!(newer.generation, 8);
-        assert!(matches!(newer.timestamp,cap_timestamp::Timestamp::Instant(at) if at==second));
-        assert!(b.take_ready().unwrap().is_none());
-        release.send(()).unwrap();
-        worker.await.unwrap();
-        let older = a.take_ready().unwrap().unwrap().unwrap();
-        assert_eq!(older.generation, 7);
-        assert!(matches!(older.timestamp,cap_timestamp::Timestamp::Instant(at) if at==first));
-    }
-
-    #[cfg(target_os = "linux")]
-    #[tokio::test]
-    async fn cancelled_readback_callback_cannot_certify_a_new_lease() {
-        let old = ReadbackTicket::new(Some(receipt(1, Instant::now())));
-        let callback = old.status.clone();
-        drop(old);
-        let mut fresh = ReadbackTicket::new(Some(receipt(2, Instant::now())));
-        tokio::spawn(async move {
-            callback.store(WS_READBACK_READY_OK, Ordering::Release);
-        })
-        .await
-        .unwrap();
-        assert!(fresh.take_ready().unwrap().is_none());
-        fresh.status.store(WS_READBACK_READY_ERR, Ordering::Release);
-        assert!(fresh.take_ready().is_err());
-        assert!(fresh.take_ready().unwrap().is_none());
-    }
-
-    #[cfg(target_os = "linux")]
-    #[tokio::test]
-    async fn hidden_websocket_does_not_disable_recording_demand_or_command_delivery() {
-        let (frame_tx, frames) = flume::bounded::(2);
-        let (command_tx, commands) = flume::bounded::(1);
-        let frame_input = frames.clone();
-        let command_input = commands.clone();
-        let waiting = tokio::task::spawn_blocking(move || {
-            next_worker_event(&frame_input, &command_input, None)
-        });
-        command_tx.send_async(7).await.unwrap();
-        assert!(matches!(waiting.await.unwrap(), WorkerEvent::Command(7)));
-        assert!(processing_needed(false, true));
-        frame_tx.send_async(42).await.unwrap();
-        assert!(matches!(
-            next_worker_event(&frames, &commands, Some(Duration::from_secs(1))),
-            WorkerEvent::Frame(42)
-        ));
-        assert!(!processing_needed(false, false));
-    }
-
-    #[cfg(target_os = "linux")]
-    #[tokio::test]
-    async fn active_worker_polls_cancellation_without_needing_a_camera_frame() {
-        let (_frame_tx, frames) = flume::bounded::(2);
-        let (_command_tx, commands) = flume::bounded::(1);
-        let waiting = tokio::task::spawn_blocking(move || {
-            next_worker_event(&frames, &commands, Some(Duration::from_millis(1)))
-        });
-        assert!(matches!(
-            tokio::time::timeout(Duration::from_secs(1), waiting)
-                .await
-                .unwrap()
-                .unwrap(),
-            WorkerEvent::Tick
-        ));
-    }
-}
diff --git a/apps/desktop/src-tauri/src/camera_native.rs b/apps/desktop/src-tauri/src/camera_native.rs
deleted file mode 100644
index 9d398845128..00000000000
--- a/apps/desktop/src-tauri/src/camera_native.rs
+++ /dev/null
@@ -1,356 +0,0 @@
-use cap_recording::NativeCameraFrame;
-use cap_rendering::iosurface_texture::{
-    IOSurfaceTextureCache, IOSurfaceTextureError, import_metal_texture_to_wgpu,
-};
-
-// Converts IOSurface-backed camera frames into an RGBA destination texture
-// entirely on the GPU: the CVPixelBuffer planes are imported as Metal textures
-// (zero CPU copies) and a fullscreen pass does YUV->RGB plus downscaling in
-// one step. BT.601 matches what the swscale CPU path produced for untagged
-// webcam streams.
-const CONVERT_SHADER: &str = r#"
-struct VertexOutput {
-    @builtin(position) position: vec4,
-    @location(0) uv: vec2,
-}
-
-@vertex
-fn vs_main(@builtin(vertex_index) vi: u32) -> VertexOutput {
-    var positions = array, 3>(
-        vec2(-1.0, -1.0),
-        vec2(3.0, -1.0),
-        vec2(-1.0, 3.0),
-    );
-    var uvs = array, 3>(
-        vec2(0.0, 1.0),
-        vec2(2.0, 1.0),
-        vec2(0.0, -1.0),
-    );
-    var out: VertexOutput;
-    out.position = vec4(positions[vi], 0.0, 1.0);
-    out.uv = uvs[vi];
-    return out;
-}
-
-@group(0) @binding(0) var frame_sampler: sampler;
-@group(0) @binding(1) var plane0_texture: texture_2d;
-@group(0) @binding(2) var uv_texture: texture_2d;
-
-fn yuv_video_range(y: f32, u: f32, v: f32) -> vec3 {
-    let yy = y - 0.0625;
-    let uu = u - 0.5;
-    let vv = v - 0.5;
-    return clamp(
-        vec3(
-            1.164 * yy + 1.596 * vv,
-            1.164 * yy - 0.392 * uu - 0.813 * vv,
-            1.164 * yy + 2.017 * uu,
-        ),
-        vec3(0.0),
-        vec3(1.0),
-    );
-}
-
-fn yuv_full_range(y: f32, u: f32, v: f32) -> vec3 {
-    let uu = u - 0.5;
-    let vv = v - 0.5;
-    return clamp(
-        vec3(
-            y + 1.402 * vv,
-            y - 0.344 * uu - 0.714 * vv,
-            y + 1.772 * uu,
-        ),
-        vec3(0.0),
-        vec3(1.0),
-    );
-}
-
-@fragment
-fn fs_nv12_video(in: VertexOutput) -> @location(0) vec4 {
-    let y = textureSample(plane0_texture, frame_sampler, in.uv).r;
-    let uv = textureSample(uv_texture, frame_sampler, in.uv).rg;
-    return vec4(yuv_video_range(y, uv.r, uv.g), 1.0);
-}
-
-@fragment
-fn fs_nv12_full(in: VertexOutput) -> @location(0) vec4 {
-    let y = textureSample(plane0_texture, frame_sampler, in.uv).r;
-    let uv = textureSample(uv_texture, frame_sampler, in.uv).rg;
-    return vec4(yuv_full_range(y, uv.r, uv.g), 1.0);
-}
-
-@fragment
-fn fs_bgra(in: VertexOutput) -> @location(0) vec4 {
-    let color = textureSample(plane0_texture, frame_sampler, in.uv);
-    return vec4(color.rgb, 1.0);
-}
-"#;
-
-#[derive(Debug)]
-pub enum NativeFrameError {
-    NoImageBuffer,
-    NoFormatDesc,
-    UnsupportedFormat(String),
-    Surface(IOSurfaceTextureError),
-}
-
-impl std::fmt::Display for NativeFrameError {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            Self::NoImageBuffer => write!(f, "sample buffer has no image buffer"),
-            Self::NoFormatDesc => write!(f, "sample buffer has no format description"),
-            Self::UnsupportedFormat(fourcc) => {
-                write!(f, "unsupported pixel format for GPU path: {fourcc}")
-            }
-            Self::Surface(err) => write!(f, "{err}"),
-        }
-    }
-}
-
-impl From for NativeFrameError {
-    fn from(err: IOSurfaceTextureError) -> Self {
-        Self::Surface(err)
-    }
-}
-
-pub enum NativeFrameKind {
-    Nv12 { full_range: bool },
-    Bgra,
-}
-
-pub fn classify_frame(frame: &NativeCameraFrame) -> Result {
-    let format_desc = frame
-        .sample_buf
-        .format_desc()
-        .ok_or(NativeFrameError::NoFormatDesc)?;
-    let mut fourcc = format_desc.media_sub_type().to_be_bytes();
-    match cidre::four_cc_to_str(&mut fourcc) {
-        "420v" => Ok(NativeFrameKind::Nv12 { full_range: false }),
-        "420f" => Ok(NativeFrameKind::Nv12 { full_range: true }),
-        "BGRA" => Ok(NativeFrameKind::Bgra),
-        other => Err(NativeFrameError::UnsupportedFormat(other.to_string())),
-    }
-}
-
-pub struct NativeFrameConverter {
-    cache: IOSurfaceTextureCache,
-    sampler: wgpu::Sampler,
-    nv12_layout: wgpu::BindGroupLayout,
-    single_layout: wgpu::BindGroupLayout,
-    nv12_video_pipeline: wgpu::RenderPipeline,
-    nv12_full_pipeline: wgpu::RenderPipeline,
-    bgra_pipeline: wgpu::RenderPipeline,
-}
-
-impl NativeFrameConverter {
-    pub fn new(device: &wgpu::Device) -> Option {
-        let cache = IOSurfaceTextureCache::new()?;
-
-        let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
-            label: Some("Camera Native Convert Shader"),
-            source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(CONVERT_SHADER)),
-        });
-
-        let sampler_entry = wgpu::BindGroupLayoutEntry {
-            binding: 0,
-            visibility: wgpu::ShaderStages::FRAGMENT,
-            ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
-            count: None,
-        };
-        let texture_entry = |binding: u32| wgpu::BindGroupLayoutEntry {
-            binding,
-            visibility: wgpu::ShaderStages::FRAGMENT,
-            ty: wgpu::BindingType::Texture {
-                sample_type: wgpu::TextureSampleType::Float { filterable: true },
-                view_dimension: wgpu::TextureViewDimension::D2,
-                multisampled: false,
-            },
-            count: None,
-        };
-
-        let nv12_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
-            label: Some("Camera NV12 Layout"),
-            entries: &[sampler_entry, texture_entry(1), texture_entry(2)],
-        });
-        let single_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
-            label: Some("Camera BGRA Layout"),
-            entries: &[sampler_entry, texture_entry(1)],
-        });
-
-        let make_pipeline = |layout: &wgpu::BindGroupLayout, entry_point: &str| {
-            let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
-                label: None,
-                bind_group_layouts: &[layout],
-                push_constant_ranges: &[],
-            });
-            device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
-                label: Some("Camera Native Convert Pipeline"),
-                layout: Some(&pipeline_layout),
-                vertex: wgpu::VertexState {
-                    module: &shader,
-                    entry_point: Some("vs_main"),
-                    buffers: &[],
-                    compilation_options: Default::default(),
-                },
-                fragment: Some(wgpu::FragmentState {
-                    module: &shader,
-                    entry_point: Some(entry_point),
-                    targets: &[Some(wgpu::ColorTargetState {
-                        format: wgpu::TextureFormat::Rgba8Unorm,
-                        blend: None,
-                        write_mask: wgpu::ColorWrites::ALL,
-                    })],
-                    compilation_options: Default::default(),
-                }),
-                primitive: wgpu::PrimitiveState::default(),
-                depth_stencil: None,
-                multisample: Default::default(),
-                multiview: None,
-                cache: None,
-            })
-        };
-
-        let nv12_video_pipeline = make_pipeline(&nv12_layout, "fs_nv12_video");
-        let nv12_full_pipeline = make_pipeline(&nv12_layout, "fs_nv12_full");
-        let bgra_pipeline = make_pipeline(&single_layout, "fs_bgra");
-
-        let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
-            address_mode_u: wgpu::AddressMode::ClampToEdge,
-            address_mode_v: wgpu::AddressMode::ClampToEdge,
-            mag_filter: wgpu::FilterMode::Linear,
-            min_filter: wgpu::FilterMode::Linear,
-            ..Default::default()
-        });
-
-        Some(Self {
-            cache,
-            sampler,
-            nv12_layout,
-            single_layout,
-            nv12_video_pipeline,
-            nv12_full_pipeline,
-            bgra_pipeline,
-        })
-    }
-
-    pub fn render_frame(
-        &self,
-        device: &wgpu::Device,
-        queue: &wgpu::Queue,
-        frame: &NativeCameraFrame,
-        kind: &NativeFrameKind,
-        dst_view: &wgpu::TextureView,
-    ) -> Result<(), NativeFrameError> {
-        let image_buf = frame
-            .sample_buf
-            .image_buf()
-            .ok_or(NativeFrameError::NoImageBuffer)?;
-        let io_surface = image_buf.io_surf().ok_or(NativeFrameError::Surface(
-            IOSurfaceTextureError::NoIOSurface,
-        ))?;
-        let width = image_buf.width() as u32;
-        let height = image_buf.height() as u32;
-
-        let (pipeline, bind_group) = match kind {
-            NativeFrameKind::Nv12 { full_range } => {
-                let y_metal = self.cache.create_y_texture(io_surface, width, height)?;
-                let uv_metal = self.cache.create_uv_texture(io_surface, width, height)?;
-                let y_texture = import_metal_texture_to_wgpu(
-                    device,
-                    &y_metal,
-                    wgpu::TextureFormat::R8Unorm,
-                    width,
-                    height,
-                    Some("Camera Y Plane"),
-                )?;
-                let uv_texture = import_metal_texture_to_wgpu(
-                    device,
-                    &uv_metal,
-                    wgpu::TextureFormat::Rg8Unorm,
-                    width / 2,
-                    height / 2,
-                    Some("Camera UV Plane"),
-                )?;
-                let y_view = y_texture.create_view(&wgpu::TextureViewDescriptor::default());
-                let uv_view = uv_texture.create_view(&wgpu::TextureViewDescriptor::default());
-                let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
-                    label: Some("Camera NV12 Bind Group"),
-                    layout: &self.nv12_layout,
-                    entries: &[
-                        wgpu::BindGroupEntry {
-                            binding: 0,
-                            resource: wgpu::BindingResource::Sampler(&self.sampler),
-                        },
-                        wgpu::BindGroupEntry {
-                            binding: 1,
-                            resource: wgpu::BindingResource::TextureView(&y_view),
-                        },
-                        wgpu::BindGroupEntry {
-                            binding: 2,
-                            resource: wgpu::BindingResource::TextureView(&uv_view),
-                        },
-                    ],
-                });
-                let pipeline = if *full_range {
-                    &self.nv12_full_pipeline
-                } else {
-                    &self.nv12_video_pipeline
-                };
-                (pipeline, bind_group)
-            }
-            NativeFrameKind::Bgra => {
-                let bgra_metal = self.cache.create_bgra_texture(io_surface, width, height)?;
-                let bgra_texture = import_metal_texture_to_wgpu(
-                    device,
-                    &bgra_metal,
-                    wgpu::TextureFormat::Bgra8Unorm,
-                    width,
-                    height,
-                    Some("Camera BGRA"),
-                )?;
-                let view = bgra_texture.create_view(&wgpu::TextureViewDescriptor::default());
-                let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
-                    label: Some("Camera BGRA Bind Group"),
-                    layout: &self.single_layout,
-                    entries: &[
-                        wgpu::BindGroupEntry {
-                            binding: 0,
-                            resource: wgpu::BindingResource::Sampler(&self.sampler),
-                        },
-                        wgpu::BindGroupEntry {
-                            binding: 1,
-                            resource: wgpu::BindingResource::TextureView(&view),
-                        },
-                    ],
-                });
-                (&self.bgra_pipeline, bind_group)
-            }
-        };
-
-        let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
-            label: Some("Camera Native Convert"),
-        });
-        {
-            let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
-                label: Some("Camera Native Convert Pass"),
-                color_attachments: &[Some(wgpu::RenderPassColorAttachment {
-                    view: dst_view,
-                    resolve_target: None,
-                    ops: wgpu::Operations {
-                        load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
-                        store: wgpu::StoreOp::Store,
-                    },
-                })],
-                depth_stencil_attachment: None,
-                timestamp_writes: None,
-                occlusion_query_set: None,
-            });
-            pass.set_pipeline(pipeline);
-            pass.set_bind_group(0, &bind_group, &[]);
-            pass.draw(0..3, 0..1);
-        }
-        queue.submit(std::iter::once(encoder.finish()));
-
-        Ok(())
-    }
-}
diff --git a/apps/desktop/src-tauri/src/captions.rs b/apps/desktop/src-tauri/src/captions.rs
deleted file mode 100644
index b64305aa478..00000000000
--- a/apps/desktop/src-tauri/src/captions.rs
+++ /dev/null
@@ -1,2910 +0,0 @@
-use anyhow::Result;
-use cap_audio::{
-    AudioData, TranscriptionAudioSource, TranscriptionAudioTake, append_transcription_audio,
-};
-use cap_rendering::Video;
-use ffmpeg::{
-    ChannelLayout, codec as avcodec,
-    format::{self as avformat},
-    software::resampling,
-};
-use futures::StreamExt;
-#[cfg(not(all(target_os = "macos", target_arch = "x86_64")))]
-use parakeet_rs::{ParakeetTDT, TimestampMode, Transcriber};
-use serde::{Deserialize, Serialize};
-use specta::Type;
-use std::collections::HashMap;
-use std::fs::File;
-use std::io::Read;
-use std::path::{Component, Path, PathBuf};
-use std::sync::Arc;
-use std::time::Duration;
-use tauri::{AppHandle, Manager};
-use tauri_specta::Event;
-use tempfile::tempdir;
-use tokio::io::AsyncWriteExt;
-use tokio::sync::{Mutex, Notify};
-use tracing::instrument;
-use whisper_rs::{FullParams, SamplingStrategy, WhisperContext, WhisperContextParameters};
-
-pub use cap_project::{
-    CaptionSegment, CaptionSettings, CaptionWord, RecordingMeta, StudioRecordingMeta,
-};
-
-use crate::{general_settings::GeneralSettingsStore, http_client};
-
-#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
-const PARAKEET_UNSUPPORTED_MESSAGE: &str = "Parakeet transcription is not available on Intel macOS";
-
-#[derive(Debug, Serialize, Deserialize, Type, Clone)]
-pub enum TranscriptionEngine {
-    Whisper,
-    Parakeet,
-}
-
-#[derive(Debug, Serialize, Deserialize, Type, Clone)]
-pub struct CaptionData {
-    pub segments: Vec,
-    pub settings: Option,
-}
-
-impl Default for CaptionData {
-    fn default() -> Self {
-        Self {
-            segments: Vec::new(),
-            settings: Some(CaptionSettings::default()),
-        }
-    }
-}
-
-lazy_static::lazy_static! {
-    static ref WHISPER_CONTEXT: Arc>> = Arc::new(Mutex::new(None));
-    static ref MODEL_DOWNLOADS: Mutex> = Mutex::new(HashMap::new());
-    static ref TRANSCRIPTION_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
-}
-
-struct CachedWhisperContext {
-    model_path: String,
-    context: Arc,
-}
-
-#[cfg(not(all(target_os = "macos", target_arch = "x86_64")))]
-lazy_static::lazy_static! {
-    static ref PARAKEET_CONTEXT: Mutex> = Mutex::new(None);
-}
-
-const WHISPER_SAMPLE_RATE: u32 = 16000;
-const TARGET_CAPTION_WORDS_PER_SEGMENT: usize = 6;
-const MAX_CAPTION_WORDS_PER_SEGMENT: usize = 8;
-const MIN_FINAL_CAPTION_WORDS: usize = 3;
-// Whisper/Parakeet sometimes stretch a trailing word's end across a following
-// silence (e.g. a 16s "seconds."), which leaves the rendered caption stuck on
-// screen and duplicates the word across timeline cuts once projected. Real
-// spoken words never approach this, so cap each word's duration to keep timing
-// tied to speech rather than silence.
-const MAX_CAPTION_WORD_DURATION: f32 = 2.5;
-
-#[cfg(not(all(target_os = "macos", target_arch = "x86_64")))]
-struct CachedParakeetContext {
-    model_dir: String,
-    model: Arc>,
-}
-
-#[cfg(not(all(target_os = "macos", target_arch = "x86_64")))]
-fn parakeet_model_dir_matches(cached_model_dir: &str, model_dir: &Path) -> bool {
-    cached_model_dir == model_dir.to_string_lossy()
-}
-
-#[cfg(not(all(target_os = "macos", target_arch = "x86_64")))]
-async fn invalidate_parakeet_cache_for_dir(model_dir: &Path) {
-    let mut ctx = PARAKEET_CONTEXT.lock().await;
-    if ctx
-        .as_ref()
-        .is_some_and(|cached| parakeet_model_dir_matches(&cached.model_dir, model_dir))
-    {
-        tracing::info!(
-            "Invalidating cached Parakeet context for {}",
-            model_dir.display()
-        );
-        *ctx = None;
-    }
-}
-
-#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
-async fn invalidate_parakeet_cache_for_dir(_model_dir: &Path) {}
-
-async fn invalidate_whisper_cache_for_path(model_path: &Path) {
-    let cached_context = {
-        let mut context = WHISPER_CONTEXT.lock().await;
-        if context
-            .as_ref()
-            .is_some_and(|cached| Path::new(&cached.model_path) == model_path)
-        {
-            tracing::info!("Releasing deleted Whisper model from cache");
-            context.take()
-        } else {
-            None
-        }
-    };
-    drop(cached_context);
-}
-
-pub async fn release_ml_models() {
-    {
-        let mut ctx = WHISPER_CONTEXT.lock().await;
-        if ctx.is_some() {
-            tracing::info!("Releasing Whisper context to free memory");
-            *ctx = None;
-        }
-    }
-    #[cfg(not(all(target_os = "macos", target_arch = "x86_64")))]
-    {
-        let mut ctx = PARAKEET_CONTEXT.lock().await;
-        if ctx.is_some() {
-            tracing::info!("Releasing Parakeet context to free memory");
-            *ctx = None;
-        }
-    }
-}
-
-fn normalize_relative_components(path: &Path) -> Result {
-    let mut normalized = PathBuf::new();
-
-    for component in path.components() {
-        match component {
-            Component::Normal(part) => normalized.push(part),
-            Component::CurDir => {}
-            Component::ParentDir => {
-                return Err("Path is outside the app data directory".to_string());
-            }
-            Component::RootDir => {
-                return Err("Path is outside the app data directory".to_string());
-            }
-            Component::Prefix(_) => {
-                return Err("Path is outside the app data directory".to_string());
-            }
-        }
-    }
-
-    Ok(normalized)
-}
-
-fn resolve_path_with_base(base_dir: &Path, path: &str) -> Result {
-    if !base_dir.exists() {
-        std::fs::create_dir_all(base_dir)
-            .map_err(|e| format!("Failed to create app data directory: {e}"))?;
-    }
-
-    let canonical_base = base_dir
-        .canonicalize()
-        .map_err(|e| format!("Failed to resolve app data directory: {e}"))?;
-    let requested = PathBuf::from(path);
-    let candidate = if requested.is_absolute() {
-        requested
-    } else {
-        canonical_base.join(normalize_relative_components(&requested)?)
-    };
-
-    let mut suffix = Vec::new();
-    let mut current = candidate.as_path();
-
-    while !current.exists() {
-        let file_name = current
-            .file_name()
-            .ok_or_else(|| "Path is outside the app data directory".to_string())?;
-        suffix.push(file_name.to_os_string());
-        current = current
-            .parent()
-            .ok_or_else(|| "Path is outside the app data directory".to_string())?;
-    }
-
-    let mut resolved = current
-        .canonicalize()
-        .map_err(|e| format!("Failed to resolve path: {e}"))?;
-
-    if !resolved.starts_with(&canonical_base) {
-        return Err("Path is outside the app data directory".to_string());
-    }
-
-    for component in suffix.into_iter().rev() {
-        resolved.push(component);
-    }
-
-    Ok(resolved)
-}
-
-fn validate_model_path(app: &AppHandle, path: &str) -> Result {
-    let app_data_dir = app
-        .path()
-        .app_local_data_dir()
-        .map_err(|_| "Failed to get app local data directory".to_string())?;
-
-    resolve_path_with_base(&app_data_dir, path)
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument]
-pub async fn create_dir(path: String, _recursive: bool) -> Result<(), String> {
-    std::fs::create_dir_all(path).map_err(|e| format!("Failed to create directory: {e}"))
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument]
-pub async fn save_model_file(path: String, data: Vec) -> Result<(), String> {
-    std::fs::write(&path, &data).map_err(|e| format!("Failed to write model file: {e}"))
-}
-
-enum AudioExtractionSource {
-    ProjectDirectory { base_path: PathBuf },
-    MediaFile(PathBuf),
-}
-
-fn resolve_audio_extraction_source(video_path: &str) -> Result {
-    let path = PathBuf::from(video_path);
-    let metadata =
-        std::fs::metadata(&path).map_err(|e| format!("Failed to read video path metadata: {e}"))?;
-
-    if metadata.is_dir() {
-        let meta_path = path.join("recording-meta.json");
-        if !meta_path.is_file() {
-            return Err("Recording directory is missing recording-meta.json".to_string());
-        }
-
-        return Ok(AudioExtractionSource::ProjectDirectory { base_path: path });
-    }
-
-    if metadata.is_file() {
-        return Ok(AudioExtractionSource::MediaFile(path));
-    }
-
-    Err("Video path is neither a file nor a recording directory".to_string())
-}
-
-async fn extract_audio_from_video(video_path: &str, output_path: &PathBuf) -> Result<(), String> {
-    log::info!("=== EXTRACT AUDIO START ===");
-    log::info!("Attempting to extract audio from: {video_path}");
-    log::info!("Output path: {output_path:?}");
-
-    match resolve_audio_extraction_source(video_path)? {
-        AudioExtractionSource::ProjectDirectory { base_path } => {
-            log::info!("Detected recording project directory");
-
-            let recording_meta = RecordingMeta::load_for_project(&base_path)
-                .map_err(|e| format!("Failed to read recording metadata: {e}"))?;
-            let studio = recording_meta
-                .studio_meta()
-                .ok_or_else(|| "Only studio recordings can be transcribed".to_string())?;
-            studio.ensure_ordinary_media_access(&base_path)?;
-
-            let mut final_samples = Vec::new();
-            let mut any_audio = false;
-            match studio {
-                StudioRecordingMeta::SingleSegment { segment } => {
-                    let display_duration = Video::new(
-                        segment.display.path.to_path(&base_path),
-                        segment.display.start_time.unwrap_or_default(),
-                    )
-                    .map_err(|error| format!("Failed to read display video: {error}"))?
-                    .duration;
-                    let mut sources = Vec::new();
-                    if let Some(audio) = &segment.audio {
-                        let path = audio.path.to_path(&base_path);
-                        if path.exists() {
-                            match AudioData::from_file(&path) {
-                                Ok(decoded) => {
-                                    any_audio = true;
-                                    sources.push(TranscriptionAudioSource {
-                                        samples: decoded.samples().to_vec(),
-                                        channels: decoded.channels() as usize,
-                                        offset_secs: 0.0,
-                                    });
-                                }
-                                Err(error) => {
-                                    log::warn!("Failed to process audio source {path:?}: {error}")
-                                }
-                            }
-                        }
-                    }
-                    let take = TranscriptionAudioTake {
-                        display_duration_secs: display_duration,
-                        sources,
-                    };
-                    append_transcription_audio(&mut final_samples, &take, AudioData::SAMPLE_RATE)
-                        .map_err(|e| format!("Failed to assemble transcription audio: {e}"))?;
-                }
-                StudioRecordingMeta::MultipleSegments { inner } => {
-                    for (segment_idx, segment) in inner.segments.iter().enumerate() {
-                        let display_duration = Video::new(
-                            segment.display.path.to_path(&base_path),
-                            segment.display.start_time.unwrap_or_default(),
-                        )
-                        .map_err(|error| {
-                            format!(
-                                "Failed to read display video for segment {segment_idx}: {error}"
-                            )
-                        })?
-                        .duration;
-                        let offsets = segment.calculate_audio_offsets();
-                        let mut sources = Vec::new();
-                        let mut push_source = |path: &cap_project::AudioMeta, offset_secs: f64| {
-                            let path = path.path.to_path(&base_path);
-                            if !path.exists() {
-                                return;
-                            }
-                            match AudioData::from_file(&path) {
-                                Ok(decoded) => {
-                                    any_audio = true;
-                                    sources.push(TranscriptionAudioSource {
-                                        samples: decoded.samples().to_vec(),
-                                        channels: decoded.channels() as usize,
-                                        offset_secs,
-                                    });
-                                }
-                                Err(error) => {
-                                    log::warn!("Failed to process audio source {path:?}: {error}")
-                                }
-                            }
-                        };
-
-                        if let Some(system_audio) = &segment.system_audio {
-                            push_source(system_audio, f64::from(offsets.system_audio));
-                        }
-                        if let Some(mic) = &segment.mic {
-                            push_source(mic, f64::from(offsets.mic));
-                        }
-
-                        let take = TranscriptionAudioTake {
-                            display_duration_secs: display_duration,
-                            sources,
-                        };
-                        append_transcription_audio(
-                            &mut final_samples,
-                            &take,
-                            AudioData::SAMPLE_RATE,
-                        )
-                        .map_err(|e| format!("Failed to assemble transcription audio: {e}"))?;
-                    }
-                }
-            }
-
-            if !any_audio {
-                return Err("No audio sources found in the recording metadata".to_string());
-            }
-
-            let mut mixed_samples = final_samples;
-            let channel_count = 1_usize;
-
-            if mixed_samples.is_empty() {
-                log::error!("No audio samples after processing all sources");
-                return Err("Failed to process any audio sources".to_string());
-            }
-
-            let gain = normalize_audio_for_transcription(&mut mixed_samples);
-            if (gain - 1.0).abs() > 0.01 {
-                log::info!("Applied transcription audio gain: {gain:.2}x");
-            }
-
-            log::info!("Final mixed audio: {} samples", mixed_samples.len());
-            let mix_rms = (mixed_samples.iter().map(|&s| s * s).sum::()
-                / mixed_samples.len() as f32)
-                .sqrt();
-            log::info!("Mixed audio RMS: {mix_rms:.4}");
-
-            if mix_rms < 0.001 {
-                log::warn!(
-                    "WARNING: Mixed audio RMS is very low ({mix_rms:.6}) - audio may be nearly silent!"
-                );
-            }
-
-            let mut output = avformat::output(&output_path)
-                .map_err(|e| format!("Failed to create output file: {e}"))?;
-
-            let codec = avcodec::encoder::find_by_name("pcm_s16le")
-                .ok_or_else(|| "PCM encoder not found".to_string())?;
-
-            let mut encoder = avcodec::Context::new()
-                .encoder()
-                .audio()
-                .map_err(|e| format!("Failed to create encoder: {e}"))?;
-
-            encoder.set_rate(WHISPER_SAMPLE_RATE as i32);
-            let channel_layout = ChannelLayout::MONO;
-            encoder.set_channel_layout(channel_layout);
-            encoder.set_format(avformat::Sample::I16(avformat::sample::Type::Packed));
-
-            let mut encoder = encoder
-                .open_as(codec)
-                .map_err(|e| format!("Failed to open encoder: {e}"))?;
-
-            let mut stream = output
-                .add_stream(codec)
-                .map_err(|e| format!("Failed to add stream: {e}"))?;
-            stream.set_parameters(&encoder);
-
-            output
-                .write_header()
-                .map_err(|e| format!("Failed to write header: {e}"))?;
-
-            let mut resampler = resampling::Context::get(
-                avformat::Sample::F32(avformat::sample::Type::Packed),
-                channel_layout,
-                AudioData::SAMPLE_RATE,
-                avformat::Sample::I16(avformat::sample::Type::Packed),
-                channel_layout,
-                WHISPER_SAMPLE_RATE,
-            )
-            .map_err(|e| format!("Failed to create resampler: {e}"))?;
-
-            let frame_size = encoder.frame_size() as usize;
-            let frame_size = if frame_size == 0 { 1024 } else { frame_size };
-
-            log::info!(
-                "Using frame size: {}, total samples: {}, channel count: {}",
-                frame_size,
-                mixed_samples.len(),
-                channel_count
-            );
-
-            let mut frame = ffmpeg::frame::Audio::new(
-                avformat::Sample::I16(avformat::sample::Type::Packed),
-                frame_size,
-                ChannelLayout::MONO,
-            );
-            frame.set_rate(WHISPER_SAMPLE_RATE);
-
-            if !mixed_samples.is_empty() && frame_size * channel_count > 0 {
-                for (chunk_idx, chunk) in
-                    mixed_samples.chunks(frame_size * channel_count).enumerate()
-                {
-                    if chunk_idx % 100 == 0 {
-                        log::info!("Processing chunk {}, size: {}", chunk_idx, chunk.len());
-                    }
-
-                    let mut input_frame = ffmpeg::frame::Audio::new(
-                        avformat::Sample::F32(avformat::sample::Type::Packed),
-                        chunk.len() / channel_count,
-                        channel_layout,
-                    );
-                    input_frame.set_rate(AudioData::SAMPLE_RATE);
-
-                    let bytes = unsafe {
-                        std::slice::from_raw_parts(
-                            chunk.as_ptr() as *const u8,
-                            std::mem::size_of_val(chunk),
-                        )
-                    };
-                    input_frame.data_mut(0)[0..bytes.len()].copy_from_slice(bytes);
-
-                    let mut output_frame = ffmpeg::frame::Audio::new(
-                        avformat::Sample::I16(avformat::sample::Type::Packed),
-                        frame_size,
-                        ChannelLayout::MONO,
-                    );
-                    output_frame.set_rate(WHISPER_SAMPLE_RATE);
-
-                    match resampler.run(&input_frame, &mut output_frame) {
-                        Ok(_) => {
-                            if chunk_idx % 100 == 0 {
-                                log::info!(
-                                    "Successfully resampled chunk {}, output samples: {}",
-                                    chunk_idx,
-                                    output_frame.samples()
-                                );
-                            }
-                        }
-                        Err(e) => {
-                            log::error!("Failed to resample chunk {chunk_idx}: {e}");
-                            continue;
-                        }
-                    }
-
-                    if let Err(e) = encoder.send_frame(&output_frame) {
-                        log::error!("Failed to send frame to encoder: {e}");
-                        continue;
-                    }
-
-                    loop {
-                        let mut packet = ffmpeg::Packet::empty();
-                        match encoder.receive_packet(&mut packet) {
-                            Ok(_) => {
-                                if let Err(e) = packet.write_interleaved(&mut output) {
-                                    log::error!("Failed to write packet: {e}");
-                                }
-                            }
-                            Err(_) => break,
-                        }
-                    }
-                }
-            }
-
-            encoder
-                .send_eof()
-                .map_err(|e| format!("Failed to send EOF: {e}"))?;
-
-            loop {
-                let mut packet = ffmpeg::Packet::empty();
-                let received = encoder.receive_packet(&mut packet);
-
-                if received.is_err() {
-                    break;
-                }
-
-                {
-                    if let Err(e) = packet.write_interleaved(&mut output) {
-                        return Err(format!("Failed to write final packet: {e}"));
-                    }
-                }
-            }
-
-            output
-                .write_trailer()
-                .map_err(|e| format!("Failed to write trailer: {e}"))?;
-
-            log::info!("=== EXTRACT AUDIO END (from recording project) ===");
-            Ok(())
-        }
-        AudioExtractionSource::MediaFile(video_path) => {
-            let mut input = avformat::input(&video_path)
-                .map_err(|e| format!("Failed to open video file: {e}"))?;
-
-            let stream = input
-                .streams()
-                .best(ffmpeg::media::Type::Audio)
-                .ok_or_else(|| "No audio stream found".to_string())?;
-
-            let codec_params = stream.parameters();
-
-            let decoder_ctx = avcodec::Context::from_parameters(codec_params.clone())
-                .map_err(|e| format!("Failed to create decoder context: {e}"))?;
-
-            let mut decoder = decoder_ctx
-                .decoder()
-                .audio()
-                .map_err(|e| format!("Failed to create decoder: {e}"))?;
-
-            let decoder_format = decoder.format();
-            let decoder_channel_layout = decoder.channel_layout();
-            let decoder_rate = decoder.rate();
-
-            let channel_layout = ChannelLayout::MONO;
-
-            let mut encoder_ctx = avcodec::Context::new()
-                .encoder()
-                .audio()
-                .map_err(|e| format!("Failed to create encoder: {e}"))?;
-
-            encoder_ctx.set_rate(WHISPER_SAMPLE_RATE as i32);
-            encoder_ctx.set_channel_layout(channel_layout);
-            encoder_ctx.set_format(avformat::Sample::I16(avformat::sample::Type::Packed));
-
-            let codec = avcodec::encoder::find_by_name("pcm_s16le")
-                .ok_or_else(|| "PCM encoder not found".to_string())?;
-
-            let mut encoder = encoder_ctx
-                .open_as(codec)
-                .map_err(|e| format!("Failed to open encoder: {e}"))?;
-
-            let mut output = avformat::output(&output_path)
-                .map_err(|e| format!("Failed to create output file: {e}"))?;
-
-            let stream_params = {
-                let mut output_stream = output
-                    .add_stream(codec)
-                    .map_err(|e| format!("Failed to add stream: {e}"))?;
-
-                output_stream.set_parameters(&encoder);
-
-                (output_stream.index(), output_stream.id())
-            };
-
-            output
-                .write_header()
-                .map_err(|e| format!("Failed to write header: {e}"))?;
-
-            let mut resampler = resampling::Context::get(
-                decoder_format,
-                decoder_channel_layout,
-                decoder_rate,
-                avformat::Sample::I16(avformat::sample::Type::Packed),
-                channel_layout,
-                WHISPER_SAMPLE_RATE,
-            )
-            .map_err(|e| format!("Failed to create resampler: {e}"))?;
-
-            let mut decoded_frame = ffmpeg::frame::Audio::empty();
-            let mut resampled_frame = ffmpeg::frame::Audio::new(
-                avformat::Sample::I16(avformat::sample::Type::Packed),
-                encoder.frame_size() as usize,
-                channel_layout,
-            );
-
-            let input_stream_index = stream.index();
-
-            let mut packet_queue = Vec::new();
-
-            {
-                for (stream_idx, packet) in input.packets() {
-                    if stream_idx.index() == input_stream_index
-                        && let Some(data) = packet.data()
-                    {
-                        let mut cloned_packet = ffmpeg::Packet::copy(data);
-                        if let Some(pts) = packet.pts() {
-                            cloned_packet.set_pts(Some(pts));
-                        }
-                        if let Some(dts) = packet.dts() {
-                            cloned_packet.set_dts(Some(dts));
-                        }
-                        packet_queue.push(cloned_packet);
-                    }
-                }
-            }
-
-            for packet_res in packet_queue {
-                if let Err(e) = decoder.send_packet(&packet_res) {
-                    log::warn!("Failed to send packet to decoder: {e}");
-                    continue;
-                }
-
-                while decoder.receive_frame(&mut decoded_frame).is_ok() {
-                    if let Err(e) = resampler.run(&decoded_frame, &mut resampled_frame) {
-                        log::warn!("Failed to resample audio: {e}");
-                        continue;
-                    }
-
-                    if let Err(e) = encoder.send_frame(&resampled_frame) {
-                        log::warn!("Failed to send frame to encoder: {e}");
-                        continue;
-                    }
-
-                    loop {
-                        let mut packet = ffmpeg::Packet::empty();
-                        match encoder.receive_packet(&mut packet) {
-                            Ok(_) => {
-                                packet.set_stream(stream_params.0);
-
-                                if let Err(e) = packet.write_interleaved(&mut output) {
-                                    log::error!("Failed to write packet: {e}");
-                                }
-                            }
-                            Err(_) => break,
-                        }
-                    }
-                }
-            }
-
-            decoder
-                .send_eof()
-                .map_err(|e| format!("Failed to send EOF to decoder: {e}"))?;
-
-            while decoder.receive_frame(&mut decoded_frame).is_ok() {
-                resampler
-                    .run(&decoded_frame, &mut resampled_frame)
-                    .map_err(|e| format!("Failed to resample final audio: {e}"))?;
-
-                encoder
-                    .send_frame(&resampled_frame)
-                    .map_err(|e| format!("Failed to send final frame: {e}"))?;
-
-                loop {
-                    let mut packet = ffmpeg::Packet::empty();
-                    let received = encoder.receive_packet(&mut packet);
-
-                    if received.is_err() {
-                        break;
-                    }
-
-                    packet
-                        .write_interleaved(&mut output)
-                        .map_err(|e| format!("Failed to write final packet: {e}"))?;
-                }
-            }
-
-            output
-                .write_trailer()
-                .map_err(|e| format!("Failed to write trailer: {e}"))?;
-
-            log::info!("=== EXTRACT AUDIO END (from video) ===");
-            Ok(())
-        }
-    }
-}
-
-fn lock_transcription_worker_slot() -> std::sync::MutexGuard<'static, ()> {
-    TRANSCRIPTION_LOCK
-        .lock()
-        .unwrap_or_else(std::sync::PoisonError::into_inner)
-}
-
-fn get_whisper_context_blocking(model_path: &str) -> Result, String> {
-    cap_utils::local_captions::ensure_whisper_cpu_support()?;
-    let mut context_guard = WHISPER_CONTEXT.blocking_lock();
-
-    if let Some(ref existing) = *context_guard
-        && existing.model_path == model_path
-    {
-        log::info!("Reusing cached Whisper context");
-        return Ok(existing.context.clone());
-    }
-
-    log::info!("Initializing Whisper context with model: {model_path}");
-    let ctx = WhisperContext::new_with_params(model_path, WhisperContextParameters::default())
-        .map_err(|e| format!("Failed to load Whisper model: {e}"))?;
-
-    let ctx_arc = Arc::new(ctx);
-    *context_guard = Some(CachedWhisperContext {
-        model_path: model_path.to_string(),
-        context: ctx_arc.clone(),
-    });
-
-    Ok(ctx_arc)
-}
-
-#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
-fn release_whisper_context_after_transcription() {
-    let mut ctx = WHISPER_CONTEXT.blocking_lock();
-    *ctx = None;
-}
-
-#[cfg(not(all(target_os = "macos", target_arch = "aarch64")))]
-fn release_whisper_context_after_transcription() {}
-
-fn is_special_token(token_text: &str) -> bool {
-    let trimmed = token_text.trim();
-    if trimmed.is_empty() {
-        return true;
-    }
-
-    let is_special = trimmed.contains('[')
-        || trimmed.contains(']')
-        || trimmed.contains("_TT_")
-        || trimmed.contains("_BEG_")
-        || trimmed.contains("<|");
-
-    if is_special {
-        log::debug!("Filtering special token: {token_text:?}");
-    }
-
-    is_special
-}
-
-fn caption_token_attaches_to_previous(text: &str) -> bool {
-    let Some(first_char) = text.trim().chars().next() else {
-        return false;
-    };
-
-    caption_char_attaches_to_previous(first_char)
-}
-
-fn caption_char_attaches_to_previous(value: char) -> bool {
-    matches!(
-        value,
-        ',' | '.'
-            | '!'
-            | '?'
-            | ';'
-            | ':'
-            | '%'
-            | ')'
-            | ']'
-            | '}'
-            | '\''
-            | '’'
-            | '、'
-            | '。'
-            | '!'
-            | '?'
-            | ';'
-            | ':'
-            | ','
-    )
-}
-
-fn caption_boundary_word_is_weak(word: &CaptionWord) -> bool {
-    let normalized = word
-        .text
-        .trim()
-        .chars()
-        .filter(|c| c.is_alphanumeric())
-        .collect::()
-        .to_lowercase();
-
-    normalized.len() <= 1
-        || matches!(
-            normalized.as_str(),
-            "an" | "as"
-                | "at"
-                | "be"
-                | "by"
-                | "do"
-                | "he"
-                | "if"
-                | "in"
-                | "is"
-                | "it"
-                | "me"
-                | "my"
-                | "of"
-                | "on"
-                | "or"
-                | "so"
-                | "to"
-                | "up"
-                | "we"
-        )
-}
-
-fn normalize_caption_words(words: Vec) -> Vec {
-    let mut normalized: Vec = Vec::with_capacity(words.len());
-
-    for word in words {
-        let text = word.text.trim();
-        if text.is_empty() {
-            continue;
-        }
-
-        if caption_token_attaches_to_previous(text)
-            && let Some(previous) = normalized.last_mut()
-        {
-            previous.text.push_str(text);
-            previous.end = word.end;
-        } else {
-            normalized.push(CaptionWord {
-                text: text.to_string(),
-                start: word.start,
-                end: word.end,
-            });
-        }
-    }
-
-    for word in &mut normalized {
-        word.end = word.end.min(word.start + MAX_CAPTION_WORD_DURATION);
-    }
-
-    normalized
-}
-
-fn caption_text_from_words<'a>(words: impl IntoIterator) -> String {
-    let mut text = String::new();
-
-    for word in words {
-        let word_text = word.text.trim();
-        if word_text.is_empty() {
-            continue;
-        }
-
-        if !text.is_empty() && !caption_token_attaches_to_previous(word_text) {
-            text.push(' ');
-        }
-        text.push_str(word_text);
-    }
-
-    text
-}
-
-fn caption_word_chunks(words: &[CaptionWord]) -> Vec<&[CaptionWord]> {
-    let mut chunks = Vec::new();
-    let mut start = 0;
-
-    while start < words.len() {
-        let remaining = words.len() - start;
-        if remaining <= TARGET_CAPTION_WORDS_PER_SEGMENT {
-            chunks.push(&words[start..]);
-            break;
-        }
-
-        let mut end = (start + TARGET_CAPTION_WORDS_PER_SEGMENT).min(words.len());
-        while end < words.len()
-            && caption_boundary_word_is_weak(&words[end - 1])
-            && end - start < MAX_CAPTION_WORDS_PER_SEGMENT
-        {
-            end += 1;
-        }
-
-        let remaining_after = words.len() - end;
-        if remaining_after > 0
-            && remaining_after < MIN_FINAL_CAPTION_WORDS
-            && caption_boundary_word_is_weak(&words[end])
-        {
-            end = words.len();
-        }
-
-        chunks.push(&words[start..end]);
-        start = end;
-    }
-
-    chunks
-}
-
-fn normalize_audio_for_transcription(samples: &mut [f32]) -> f32 {
-    if samples.is_empty() {
-        return 1.0;
-    }
-
-    let peak = samples
-        .iter()
-        .fold(0.0_f32, |max, sample| max.max(sample.abs()));
-    if peak <= f32::EPSILON {
-        return 1.0;
-    }
-
-    let rms =
-        (samples.iter().map(|sample| sample * sample).sum::() / samples.len() as f32).sqrt();
-    if rms <= f32::EPSILON {
-        return 1.0;
-    }
-
-    let target_rms = 0.08_f32;
-    let desired_gain = (target_rms / rms).clamp(1.0, 8.0);
-    let peak_limited_gain = 0.98 / peak;
-    let gain = desired_gain.min(peak_limited_gain);
-
-    if (gain - 1.0).abs() > 0.01 {
-        for sample in samples {
-            *sample = (*sample * gain).clamp(-0.98, 0.98);
-        }
-    }
-
-    gain
-}
-
-fn process_with_whisper(
-    audio_path: &PathBuf,
-    context: Arc,
-    language: &str,
-    transcription_hints: &[String],
-) -> Result {
-    log::info!("=== WHISPER TRANSCRIPTION START ===");
-    log::info!("Processing audio file: {audio_path:?}");
-    log::info!("Language setting: {language}");
-
-    let mut params = FullParams::new(SamplingStrategy::BeamSearch {
-        beam_size: 5,
-        patience: 1.0,
-    });
-
-    params.set_translate(false);
-    params.set_print_special(false);
-    params.set_print_progress(false);
-    params.set_print_realtime(false);
-    params.set_token_timestamps(true);
-    params.set_language(Some(if language == "auto" { "auto" } else { language }));
-    params.set_max_len(i32::MAX);
-
-    if let Some(initial_prompt) = build_initial_prompt(transcription_hints) {
-        params.set_initial_prompt(&initial_prompt);
-    }
-
-    log::info!(
-        "Whisper params - translate: false, token_timestamps: true, beam_size: 5, max_len: MAX"
-    );
-
-    let mut audio_file = File::open(audio_path)
-        .map_err(|e| format!("Failed to open audio file: {e} at path: {audio_path:?}"))?;
-    let mut audio_data = Vec::new();
-    audio_file
-        .read_to_end(&mut audio_data)
-        .map_err(|e| format!("Failed to read audio file: {e}"))?;
-
-    log::info!("Processing audio file of size: {} bytes", audio_data.len());
-
-    let mut audio_data_f32 = Vec::new();
-    for i in (0..audio_data.len()).step_by(2) {
-        if i + 1 < audio_data.len() {
-            let sample = i16::from_le_bytes([audio_data[i], audio_data[i + 1]]) as f32 / 32768.0;
-            audio_data_f32.push(sample);
-        }
-    }
-
-    let gain = normalize_audio_for_transcription(&mut audio_data_f32);
-    if (gain - 1.0).abs() > 0.01 {
-        log::info!("Applied Whisper input gain: {gain:.2}x");
-    }
-
-    let duration_seconds = audio_data_f32.len() as f32 / WHISPER_SAMPLE_RATE as f32;
-    log::info!(
-        "Converted {} samples to f32 format (duration: {:.2}s at {}Hz)",
-        audio_data_f32.len(),
-        duration_seconds,
-        WHISPER_SAMPLE_RATE
-    );
-
-    if !audio_data_f32.is_empty() {
-        let min_sample = audio_data_f32.iter().fold(f32::MAX, |a, &b| a.min(b));
-        let max_sample = audio_data_f32.iter().fold(f32::MIN, |a, &b| a.max(b));
-        let avg_sample = audio_data_f32.iter().sum::() / audio_data_f32.len() as f32;
-        let rms = (audio_data_f32.iter().map(|&s| s * s).sum::()
-            / audio_data_f32.len() as f32)
-            .sqrt();
-        log::info!(
-            "Audio samples - min: {min_sample:.4}, max: {max_sample:.4}, avg: {avg_sample:.6}, RMS: {rms:.4}"
-        );
-
-        if rms < 0.001 {
-            log::warn!("WARNING: Audio RMS is very low ({rms:.6}) - audio may be nearly silent!");
-        }
-
-        log::info!("First 20 audio samples:");
-        for (i, sample) in audio_data_f32.iter().take(20).enumerate() {
-            log::info!("  Sample[{i}] = {sample:.6}");
-        }
-    }
-
-    let mut state = context
-        .create_state()
-        .map_err(|e| format!("Failed to create Whisper state: {e}"))?;
-
-    state
-        .full(params, &audio_data_f32[..])
-        .map_err(|e| format!("Failed to run Whisper transcription: {e}"))?;
-
-    let num_segments = state
-        .full_n_segments()
-        .map_err(|e| format!("Failed to get number of segments: {e}"))?;
-
-    log::info!("Found {num_segments} segments");
-
-    let mut segments = Vec::new();
-
-    for i in 0..num_segments {
-        let raw_text = state
-            .full_get_segment_text(i)
-            .map_err(|e| format!("Failed to get segment text: {e}"))?;
-
-        let start_i64 = state
-            .full_get_segment_t0(i)
-            .map_err(|e| format!("Failed to get segment start time: {e}"))?;
-        let end_i64 = state
-            .full_get_segment_t1(i)
-            .map_err(|e| format!("Failed to get segment end time: {e}"))?;
-
-        let start_time = (start_i64 as f32) / 100.0;
-        let end_time = (end_i64 as f32) / 100.0;
-
-        // The transcript text itself stays out of the log: log files are
-        // uploaded from the Feedback page, and this is a verbatim record of
-        // what the user said on camera.
-        log::info!(
-            "=== Segment {}: start={:.2}s, end={:.2}s, chars={}",
-            i,
-            start_time,
-            end_time,
-            raw_text.trim().chars().count()
-        );
-
-        let mut words = Vec::new();
-        let num_tokens = state
-            .full_n_tokens(i)
-            .map_err(|e| format!("Failed to get token count: {e}"))?;
-
-        log::info!("  Segment {i} has {num_tokens} tokens");
-
-        let mut current_word = String::new();
-        let mut word_start: Option = None;
-        let mut word_end: f32 = start_time;
-
-        for t in 0..num_tokens {
-            let token_text = state.full_get_token_text(i, t).unwrap_or_default();
-            let token_id = state.full_get_token_id(i, t).unwrap_or(0);
-            let token_prob = state.full_get_token_prob(i, t).unwrap_or(0.0);
-
-            if is_special_token(&token_text) {
-                log::debug!(
-                    "  Token[{t}]: id={token_id}, text={token_text:?} -> SKIPPED (special)"
-                );
-                continue;
-            }
-
-            let token_data = state.full_get_token_data(i, t).ok();
-
-            if let Some(data) = token_data {
-                let token_start = (data.t0 as f32) / 100.0;
-                let token_end = (data.t1 as f32) / 100.0;
-
-                // debug, not info: release builds filter at info, and these
-                // carry the transcript verbatim into an uploadable log.
-                log::debug!(
-                    "  Token[{t}]: id={token_id}, text={token_text:?}, t0={token_start:.2}s, t1={token_end:.2}s, prob={token_prob:.4}"
-                );
-
-                if token_text.starts_with(' ') || token_text.starts_with('\n') {
-                    if !current_word.is_empty()
-                        && let Some(ws) = word_start
-                    {
-                        log::debug!(
-                            "    -> Completing word: '{}' ({:.2}s - {:.2}s)",
-                            current_word.trim(),
-                            ws,
-                            word_end
-                        );
-                        words.push(CaptionWord {
-                            text: current_word.trim().to_string(),
-                            start: ws,
-                            end: word_end,
-                        });
-                    }
-                    current_word = token_text.trim().to_string();
-                    word_start = Some(token_start);
-                    log::debug!("    -> Starting new word: '{current_word}' at {token_start:.2}s");
-                } else {
-                    if word_start.is_none() {
-                        word_start = Some(token_start);
-                        log::debug!("    -> Word start set to {token_start:.2}s");
-                    }
-                    current_word.push_str(&token_text);
-                    log::debug!("    -> Appending to word: '{current_word}'");
-                }
-                word_end = token_end;
-            } else {
-                log::warn!("  Token[{t}]: id={token_id}, text={token_text:?} -> NO TIMING DATA");
-            }
-        }
-
-        if !current_word.trim().is_empty()
-            && let Some(ws) = word_start
-        {
-            log::info!(
-                "    -> Final word: '{}' ({:.2}s - {:.2}s)",
-                current_word.trim(),
-                ws,
-                word_end
-            );
-            words.push(CaptionWord {
-                text: current_word.trim().to_string(),
-                start: ws,
-                end: word_end,
-            });
-        }
-
-        let words = normalize_caption_words(words);
-
-        log::info!("  Segment {} produced {} words", i, words.len());
-        for (w_idx, word) in words.iter().enumerate() {
-            log::info!(
-                "    Word[{}]: '{}' ({:.2}s - {:.2}s)",
-                w_idx,
-                word.text,
-                word.start,
-                word.end
-            );
-        }
-
-        if words.is_empty() {
-            log::warn!("  Segment {i} has no words, skipping");
-            continue;
-        }
-
-        for (chunk_idx, chunk_words) in caption_word_chunks(&words).into_iter().enumerate() {
-            let segment_text = caption_text_from_words(chunk_words);
-
-            let segment_start = chunk_words
-                .first()
-                .map(|word| word.start)
-                .unwrap_or(start_time);
-            let segment_end = chunk_words.last().map(|word| word.end).unwrap_or(end_time);
-
-            segments.push(CaptionSegment {
-                id: format!("segment-{i}-{chunk_idx}"),
-                start: segment_start,
-                end: segment_end,
-                text: segment_text,
-                words: chunk_words.to_vec(),
-            });
-        }
-    }
-
-    log::info!("=== WHISPER TRANSCRIPTION COMPLETE ===");
-    log::info!("Total segments: {}", segments.len());
-
-    let total_words: usize = segments.iter().map(|s| s.words.len()).sum();
-    log::info!("Total words: {total_words}");
-
-    log::info!("=== FINAL TRANSCRIPTION SUMMARY ===");
-    for segment in &segments {
-        log::info!(
-            "Segment '{}' ({:.2}s - {:.2}s): {}",
-            segment.id,
-            segment.start,
-            segment.end,
-            segment.text
-        );
-    }
-    log::info!("=== END SUMMARY ===");
-
-    Ok(CaptionData {
-        segments,
-        settings: Some(cap_project::CaptionSettings::default()),
-    })
-}
-
-fn build_initial_prompt(transcription_hints: &[String]) -> Option {
-    let mut normalized = Vec::new();
-
-    for hint in transcription_hints {
-        let value = hint.replace('\0', "").trim().to_string();
-        if value.is_empty() || normalized.contains(&value) {
-            continue;
-        }
-        normalized.push(value);
-    }
-
-    if normalized.is_empty() {
-        None
-    } else {
-        Some(format!(
-            "Preferred spellings, names, and capitalization for this transcript: {}",
-            normalized.join("; ")
-        ))
-    }
-}
-
-#[cfg(not(all(target_os = "macos", target_arch = "x86_64")))]
-fn process_with_parakeet(
-    audio_path: &std::path::Path,
-    model_dir: &str,
-) -> Result {
-    tracing::info!("Processing audio file: {audio_path:?}");
-    tracing::info!("Model directory: {model_dir}");
-
-    let cached_model = {
-        let guard = PARAKEET_CONTEXT.blocking_lock();
-        guard.as_ref().and_then(|cached| {
-            if cached.model_dir == model_dir {
-                Some(Arc::clone(&cached.model))
-            } else {
-                None
-            }
-        })
-    };
-
-    let model_arc = if let Some(model) = cached_model {
-        tracing::info!("Reusing cached Parakeet TDT model");
-        model
-    } else {
-        tracing::info!("Loading Parakeet TDT model from: {model_dir}");
-        cap_camera_effects::initialize_onnx_runtime().map_err(|error| format!("{error:#}"))?;
-        let model = ParakeetTDT::from_pretrained(model_dir, None).map_err(|e| format!("{e}"))?;
-        let loaded_model = Arc::new(std::sync::Mutex::new(model));
-
-        let mut guard = PARAKEET_CONTEXT.blocking_lock();
-        if let Some(cached) = guard
-            .as_ref()
-            .filter(|cached| cached.model_dir == model_dir)
-        {
-            tracing::info!("Reusing cached Parakeet TDT model");
-            Arc::clone(&cached.model)
-        } else {
-            *guard = Some(CachedParakeetContext {
-                model_dir: model_dir.to_string(),
-                model: Arc::clone(&loaded_model),
-            });
-            tracing::info!("Parakeet TDT model loaded successfully");
-            loaded_model
-        }
-    };
-
-    let result = {
-        let mut parakeet = model_arc
-            .lock()
-            .map_err(|e| format!("Failed to lock Parakeet model: {e}"))?;
-        parakeet
-            .transcribe_file(audio_path, Some(TimestampMode::Words))
-            .map_err(|e| format!("Parakeet transcription failed: {e}"))?
-    };
-
-    tracing::info!("Transcription text: {}", result.text);
-    tracing::info!("Got {} timed tokens", result.tokens.len());
-
-    let words = normalize_caption_words(
-        result
-            .tokens
-            .iter()
-            .filter(|t| !t.text.trim().is_empty())
-            .map(|t| CaptionWord {
-                text: t.text.trim().to_string(),
-                start: t.start,
-                end: t.end,
-            })
-            .collect(),
-    );
-
-    if words.is_empty() {
-        tracing::warn!("Parakeet produced no words");
-        return Err("No speech detected in the audio".to_string());
-    }
-
-    let mut segments = Vec::new();
-
-    for (chunk_idx, chunk) in caption_word_chunks(&words).into_iter().enumerate() {
-        let segment_text = caption_text_from_words(chunk);
-        let segment_start = chunk.first().map(|w| w.start).unwrap_or(0.0);
-        let segment_end = chunk.last().map(|w| w.end).unwrap_or(0.0);
-
-        segments.push(CaptionSegment {
-            id: format!("segment-{chunk_idx}"),
-            start: segment_start,
-            end: segment_end,
-            text: segment_text,
-            words: chunk.to_vec(),
-        });
-    }
-
-    tracing::info!("Total segments: {}", segments.len());
-    tracing::info!(
-        "Total words: {}",
-        segments.iter().map(|s| s.words.len()).sum::()
-    );
-
-    Ok(CaptionData {
-        segments,
-        settings: Some(cap_project::CaptionSettings::default()),
-    })
-}
-
-#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
-fn process_with_parakeet(
-    _audio_path: &std::path::Path,
-    _model_dir: &str,
-) -> Result {
-    Err(PARAKEET_UNSUPPORTED_MESSAGE.to_string())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument]
-pub async fn transcribe_audio(
-    app: AppHandle,
-    video_path: String,
-    model_path: String,
-    language: String,
-    engine: TranscriptionEngine,
-) -> Result {
-    log::info!("=== TRANSCRIBE AUDIO COMMAND START ===");
-    log::info!("Video path: {}", video_path);
-    log::info!("Model path: {}", model_path);
-    log::info!("Language: {}", language);
-
-    let validated_model_path = validate_model_path(&app, &model_path)?;
-
-    if !std::path::Path::new(&video_path).exists() {
-        log::error!("Video file not found at path: {video_path}");
-        return Err(format!("Video file not found at path: {video_path}"));
-    }
-
-    if !validated_model_path.exists() {
-        log::error!("Model file not found at path: {model_path}");
-        return Err(format!("Model file not found at path: {model_path}"));
-    }
-
-    let model_path = validated_model_path.to_string_lossy().to_string();
-
-    let temp_dir = tempdir().map_err(|e| format!("Failed to create temporary directory: {e}"))?;
-    let audio_path = temp_dir.path().join("audio.wav");
-    log::info!("Temp audio path: {:?}", audio_path);
-
-    match extract_audio_from_video(&video_path, &audio_path).await {
-        Ok(_) => log::info!("Successfully extracted audio to {audio_path:?}"),
-        Err(e) => {
-            log::error!("Failed to extract audio: {e}");
-            return Err(format!("Failed to extract audio from video: {e}"));
-        }
-    }
-
-    if !audio_path.exists() {
-        log::error!("Audio file was not created at {audio_path:?}");
-        return Err("Failed to create audio file for transcription".to_string());
-    }
-
-    let audio_metadata = std::fs::metadata(&audio_path).ok();
-    if let Some(meta) = &audio_metadata {
-        log::info!(
-            "Audio file created at: {:?}, size: {} bytes",
-            audio_path,
-            meta.len()
-        );
-    }
-
-    let transcription_result = match engine {
-        TranscriptionEngine::Parakeet => {
-            log::info!("Using Parakeet TDT engine");
-            let model_dir = model_path.clone();
-            tokio::task::spawn_blocking(move || {
-                let _guard = lock_transcription_worker_slot();
-                process_with_parakeet(&audio_path, &model_dir)
-            })
-            .await
-            .map_err(|e| format!("Parakeet task panicked: {e}"))?
-        }
-        TranscriptionEngine::Whisper => {
-            let transcription_hints = GeneralSettingsStore::get(&app)
-                .ok()
-                .flatten()
-                .map(|settings| settings.transcription_hints)
-                .unwrap_or_default();
-
-            log::info!("Starting Whisper transcription in blocking task...");
-            tokio::task::spawn_blocking(move || {
-                let _guard = lock_transcription_worker_slot();
-                let context = match get_whisper_context_blocking(&model_path) {
-                    Ok(ctx) => {
-                        log::info!("Whisper context ready");
-                        ctx
-                    }
-                    Err(e) => {
-                        log::error!("Failed to initialize Whisper context: {e}");
-                        return Err(format!("Failed to initialize transcription model: {e}"));
-                    }
-                };
-                let result =
-                    process_with_whisper(&audio_path, context, &language, &transcription_hints);
-                release_whisper_context_after_transcription();
-                result
-            })
-            .await
-            .map_err(|e| format!("Whisper task panicked: {e}"))?
-        }
-    };
-
-    match transcription_result {
-        Ok(captions) => {
-            log::info!("=== TRANSCRIBE AUDIO RESULT ===");
-            log::info!(
-                "Transcription produced {} segments",
-                captions.segments.len()
-            );
-
-            for (idx, segment) in captions.segments.iter().enumerate() {
-                log::info!(
-                    "  Result Segment[{}]: '{}' ({} words)",
-                    idx,
-                    segment.text,
-                    segment.words.len()
-                );
-            }
-
-            if captions.segments.is_empty() {
-                log::warn!("No caption segments were generated");
-                return Err("No speech detected in the audio".to_string());
-            }
-
-            log::info!("=== TRANSCRIBE AUDIO COMMAND END (success) ===");
-            Ok(captions)
-        }
-        Err(e) => {
-            log::error!("Failed to process audio with Whisper: {e}");
-            log::info!("=== TRANSCRIBE AUDIO COMMAND END (error) ===");
-            Err(format!("Failed to transcribe audio: {e}"))
-        }
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-pub async fn save_captions(
-    app: AppHandle,
-    video_id: String,
-    captions: CaptionData,
-) -> Result<(), String> {
-    tracing::info!("=== SAVE CAPTIONS START ===");
-    tracing::info!("Saving captions for video_id: {}", video_id);
-    tracing::info!("Received {} segments to save", captions.segments.len());
-
-    for (idx, segment) in captions.segments.iter().enumerate() {
-        tracing::info!(
-            "  Segment[{}] '{}': '{}' ({} words, {:.2}s - {:.2}s)",
-            idx,
-            segment.id,
-            segment.text,
-            segment.words.len(),
-            segment.start,
-            segment.end
-        );
-        for (w_idx, word) in segment.words.iter().enumerate() {
-            tracing::debug!(
-                "    Word[{}]: '{}' ({:.2}s - {:.2}s)",
-                w_idx,
-                word.text,
-                word.start,
-                word.end
-            );
-        }
-    }
-
-    let captions_dir = app_captions_dir(&app, &video_id)?;
-
-    if !captions_dir.exists() {
-        tracing::info!("Creating captions directory: {:?}", captions_dir);
-        std::fs::create_dir_all(&captions_dir).map_err(|e| {
-            tracing::error!("Failed to create captions directory: {}", e);
-            format!("Failed to create captions directory: {e}")
-        })?;
-    }
-
-    let captions_path = captions_dir.join("captions.json");
-
-    tracing::info!("Writing captions to: {:?}", captions_path);
-
-    let settings = captions.settings.unwrap_or_default();
-
-    let mut json_obj = serde_json::Map::new();
-
-    let segments_array = serde_json::to_value(
-        captions
-            .segments
-            .iter()
-            .map(|seg| {
-                let mut segment = serde_json::Map::new();
-                segment.insert("id".to_string(), serde_json::Value::String(seg.id.clone()));
-                segment.insert(
-                    "start".to_string(),
-                    serde_json::Value::Number(
-                        serde_json::Number::from_f64(seg.start as f64).unwrap(),
-                    ),
-                );
-                segment.insert(
-                    "end".to_string(),
-                    serde_json::Value::Number(
-                        serde_json::Number::from_f64(seg.end as f64).unwrap(),
-                    ),
-                );
-                segment.insert(
-                    "text".to_string(),
-                    serde_json::Value::String(seg.text.clone()),
-                );
-                let words_array: Vec = seg
-                    .words
-                    .iter()
-                    .map(|w| {
-                        serde_json::json!({
-                            "text": w.text,
-                            "start": w.start,
-                            "end": w.end
-                        })
-                    })
-                    .collect();
-                segment.insert("words".to_string(), serde_json::Value::Array(words_array));
-                segment
-            })
-            .collect::>(),
-    )
-    .map_err(|e| {
-        tracing::error!("Failed to serialize captions segments: {}", e);
-        format!("Failed to serialize captions: {e}")
-    })?;
-
-    json_obj.insert("segments".to_string(), segments_array);
-
-    let mut settings_obj = serde_json::Map::new();
-    settings_obj.insert(
-        "enabled".to_string(),
-        serde_json::Value::Bool(settings.enabled),
-    );
-    settings_obj.insert(
-        "font".to_string(),
-        serde_json::Value::String(settings.font.clone()),
-    );
-    settings_obj.insert(
-        "size".to_string(),
-        serde_json::Value::Number(serde_json::Number::from(settings.size)),
-    );
-    settings_obj.insert(
-        "color".to_string(),
-        serde_json::Value::String(settings.color.clone()),
-    );
-    settings_obj.insert(
-        "backgroundColor".to_string(),
-        serde_json::Value::String(settings.background_color.clone()),
-    );
-    settings_obj.insert(
-        "backgroundOpacity".to_string(),
-        serde_json::Value::Number(serde_json::Number::from(settings.background_opacity)),
-    );
-    settings_obj.insert(
-        "position".to_string(),
-        serde_json::Value::String(settings.position.clone()),
-    );
-    settings_obj.insert(
-        "italic".to_string(),
-        serde_json::Value::Bool(settings.italic),
-    );
-    settings_obj.insert(
-        "fontWeight".to_string(),
-        serde_json::Value::Number(serde_json::Number::from(settings.font_weight)),
-    );
-    settings_obj.insert(
-        "outline".to_string(),
-        serde_json::Value::Bool(settings.outline),
-    );
-    settings_obj.insert(
-        "outlineColor".to_string(),
-        serde_json::Value::String(settings.outline_color.clone()),
-    );
-    settings_obj.insert(
-        "exportWithSubtitles".to_string(),
-        serde_json::Value::Bool(settings.export_with_subtitles),
-    );
-    settings_obj.insert(
-        "highlightColor".to_string(),
-        serde_json::Value::String(settings.highlight_color.clone()),
-    );
-    settings_obj.insert(
-        "fadeDuration".to_string(),
-        serde_json::Value::Number(
-            serde_json::Number::from_f64(settings.fade_duration as f64).unwrap(),
-        ),
-    );
-    settings_obj.insert(
-        "lingerDuration".to_string(),
-        serde_json::Value::Number(
-            serde_json::Number::from_f64(settings.linger_duration as f64).unwrap(),
-        ),
-    );
-    settings_obj.insert(
-        "wordTransitionDuration".to_string(),
-        serde_json::Value::Number(
-            serde_json::Number::from_f64(settings.word_transition_duration as f64).unwrap(),
-        ),
-    );
-    settings_obj.insert(
-        "activeWordHighlight".to_string(),
-        serde_json::Value::Bool(settings.active_word_highlight),
-    );
-
-    json_obj.insert(
-        "settings".to_string(),
-        serde_json::Value::Object(settings_obj),
-    );
-
-    let json = serde_json::to_string_pretty(&json_obj).map_err(|e| {
-        tracing::error!("Failed to serialize captions: {}", e);
-        format!("Failed to serialize captions: {e}")
-    })?;
-
-    std::fs::write(captions_path, json).map_err(|e| {
-        tracing::error!("Failed to write captions file: {}", e);
-        format!("Failed to write captions file: {e}")
-    })?;
-
-    tracing::info!("Successfully saved captions");
-    tracing::info!("=== SAVE CAPTIONS END ===");
-    Ok(())
-}
-
-pub fn parse_captions_json(json: &str) -> Result {
-    match serde_json::from_str::(json) {
-        Ok(json_value) => {
-            if let Some(segments_array) = json_value.get("segments").and_then(|v| v.as_array()) {
-                let mut segments = Vec::new();
-
-                for segment in segments_array {
-                    if let (Some(id), Some(start), Some(end), Some(text)) = (
-                        segment.get("id").and_then(|v| v.as_str()),
-                        segment.get("start").and_then(|v| v.as_f64()),
-                        segment.get("end").and_then(|v| v.as_f64()),
-                        segment.get("text").and_then(|v| v.as_str()),
-                    ) {
-                        let mut words = Vec::new();
-                        if let Some(words_array) = segment.get("words").and_then(|v| v.as_array()) {
-                            for word in words_array {
-                                if let (Some(w_text), Some(w_start), Some(w_end)) = (
-                                    word.get("text").and_then(|v| v.as_str()),
-                                    word.get("start").and_then(|v| v.as_f64()),
-                                    word.get("end").and_then(|v| v.as_f64()),
-                                ) {
-                                    words.push(cap_project::CaptionWord {
-                                        text: w_text.to_string(),
-                                        start: w_start as f32,
-                                        end: w_end as f32,
-                                    });
-                                }
-                            }
-                        }
-                        segments.push(cap_project::CaptionSegment {
-                            id: id.to_string(),
-                            start: start as f32,
-                            end: end as f32,
-                            text: text.to_string(),
-                            words,
-                        });
-                    }
-                }
-
-                let settings = if let Some(settings_obj) = json_value.get("settings") {
-                    let enabled = settings_obj
-                        .get("enabled")
-                        .and_then(|v| v.as_bool())
-                        .unwrap_or_default();
-                    let font = settings_obj
-                        .get("font")
-                        .and_then(|v| v.as_str())
-                        .unwrap_or("System Sans-Serif")
-                        .to_string();
-                    let size = settings_obj
-                        .get("size")
-                        .and_then(|v| v.as_u64())
-                        .unwrap_or(24) as u32;
-                    let color = settings_obj
-                        .get("color")
-                        .and_then(|v| v.as_str())
-                        .unwrap_or("#A0A0A0")
-                        .to_string();
-
-                    let background_color = settings_obj
-                        .get("backgroundColor")
-                        .or_else(|| settings_obj.get("background_color"))
-                        .and_then(|v| v.as_str())
-                        .unwrap_or("#000000")
-                        .to_string();
-
-                    let background_opacity = settings_obj
-                        .get("backgroundOpacity")
-                        .or_else(|| settings_obj.get("background_opacity"))
-                        .and_then(|v| v.as_u64())
-                        .unwrap_or(80) as u32;
-
-                    let position = settings_obj
-                        .get("position")
-                        .and_then(|v| v.as_str())
-                        .unwrap_or("bottom")
-                        .to_string();
-                    let italic = settings_obj
-                        .get("italic")
-                        .and_then(|v| v.as_bool())
-                        .unwrap_or(false);
-                    let font_weight = settings_obj
-                        .get("fontWeight")
-                        .or_else(|| settings_obj.get("font_weight"))
-                        .and_then(|v| v.as_u64())
-                        .unwrap_or(700) as u32;
-                    let outline = settings_obj
-                        .get("outline")
-                        .and_then(|v| v.as_bool())
-                        .unwrap_or(false);
-
-                    let outline_color = settings_obj
-                        .get("outlineColor")
-                        .or_else(|| settings_obj.get("outline_color"))
-                        .and_then(|v| v.as_str())
-                        .unwrap_or("#000000")
-                        .to_string();
-
-                    let export_with_subtitles = settings_obj
-                        .get("exportWithSubtitles")
-                        .or_else(|| settings_obj.get("export_with_subtitles"))
-                        .and_then(|v| v.as_bool())
-                        .unwrap_or(false);
-
-                    let highlight_color = settings_obj
-                        .get("highlightColor")
-                        .or_else(|| settings_obj.get("highlight_color"))
-                        .and_then(|v| v.as_str())
-                        .unwrap_or("#FFFFFF")
-                        .to_string();
-
-                    let fade_duration = settings_obj
-                        .get("fadeDuration")
-                        .or_else(|| settings_obj.get("fade_duration"))
-                        .and_then(|v| v.as_f64())
-                        .unwrap_or(0.15) as f32;
-
-                    let linger_duration = settings_obj
-                        .get("lingerDuration")
-                        .or_else(|| settings_obj.get("linger_duration"))
-                        .and_then(|v| v.as_f64())
-                        .unwrap_or(0.4) as f32;
-
-                    let word_transition_duration = settings_obj
-                        .get("wordTransitionDuration")
-                        .or_else(|| settings_obj.get("word_transition_duration"))
-                        .and_then(|v| v.as_f64())
-                        .unwrap_or(0.25) as f32;
-
-                    let active_word_highlight = settings_obj
-                        .get("activeWordHighlight")
-                        .or_else(|| settings_obj.get("active_word_highlight"))
-                        .and_then(|v| v.as_bool())
-                        .unwrap_or(false);
-
-                    let preset = settings_obj
-                        .get("preset")
-                        .and_then(|v| v.as_str())
-                        .unwrap_or("classic")
-                        .to_string();
-
-                    let animation = settings_obj
-                        .get("animation")
-                        .and_then(|v| v.as_str())
-                        .unwrap_or("bounce")
-                        .to_string();
-
-                    let highlight_style = settings_obj
-                        .get("highlightStyle")
-                        .or_else(|| settings_obj.get("highlight_style"))
-                        .and_then(|v| v.as_str())
-                        .unwrap_or("color")
-                        .to_string();
-
-                    let uppercase = settings_obj
-                        .get("uppercase")
-                        .and_then(|v| v.as_bool())
-                        .unwrap_or(false);
-
-                    let manual_position = settings_obj
-                        .get("manualPosition")
-                        .or_else(|| settings_obj.get("manual_position"))
-                        .and_then(|value| {
-                            Some(cap_project::XY {
-                                x: value.get("x")?.as_f64()? as f32,
-                                y: value.get("y")?.as_f64()? as f32,
-                            })
-                        });
-
-                    cap_project::CaptionSettings {
-                        enabled,
-                        font,
-                        size,
-                        color,
-                        background_color,
-                        background_opacity,
-                        position,
-                        italic,
-                        font_weight,
-                        outline,
-                        outline_color,
-                        export_with_subtitles,
-                        highlight_color,
-                        fade_duration,
-                        linger_duration,
-                        word_transition_duration,
-                        active_word_highlight,
-                        manual_position,
-                        preset,
-                        animation,
-                        highlight_style,
-                        uppercase,
-                    }
-                } else {
-                    cap_project::CaptionSettings::default()
-                };
-
-                Ok(cap_project::CaptionsData {
-                    segments,
-                    settings,
-                    ..Default::default()
-                })
-            } else {
-                Err("Missing or invalid segments array in captions file".to_string())
-            }
-        }
-        Err(e) => Err(format!("Failed to parse captions JSON: {e}")),
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-pub async fn load_captions(
-    app: AppHandle,
-    video_id: String,
-) -> Result, String> {
-    tracing::info!("=== LOAD CAPTIONS START ===");
-    tracing::info!("Loading captions for video_id: {}", video_id);
-
-    let captions_dir = app_captions_dir(&app, &video_id)?;
-    let captions_path = captions_dir.join("captions.json");
-
-    if !captions_path.exists() {
-        tracing::info!("No captions file found at: {:?}", captions_path);
-        tracing::info!("=== LOAD CAPTIONS END (no file) ===");
-        return Ok(None);
-    }
-
-    tracing::info!("Reading captions from: {:?}", captions_path);
-    let json = match std::fs::read_to_string(captions_path.clone()) {
-        Ok(j) => j,
-        Err(e) => {
-            tracing::error!("Failed to read captions file: {}", e);
-            return Err(format!("Failed to read captions file: {e}"));
-        }
-    };
-
-    tracing::info!("Captions JSON length: {} bytes", json.len());
-
-    tracing::info!("Parsing captions JSON");
-    match parse_captions_json(&json) {
-        Ok(project_captions) => {
-            tracing::info!(
-                "Successfully loaded {} caption segments",
-                project_captions.segments.len()
-            );
-
-            for (idx, segment) in project_captions.segments.iter().enumerate() {
-                tracing::info!(
-                    "  Loaded Segment[{}] '{}': '{}' ({} words, {:.2}s - {:.2}s)",
-                    idx,
-                    segment.id,
-                    segment.text,
-                    segment.words.len(),
-                    segment.start,
-                    segment.end
-                );
-            }
-
-            let tauri_captions = CaptionData {
-                segments: project_captions.segments,
-                settings: Some(project_captions.settings),
-            };
-
-            tracing::info!("=== LOAD CAPTIONS END (success) ===");
-            Ok(Some(tauri_captions))
-        }
-        Err(e) => {
-            tracing::error!("Failed to parse captions: {}", e);
-            tracing::info!("=== LOAD CAPTIONS END (error) ===");
-            Err(format!("Failed to parse captions: {e}"))
-        }
-    }
-}
-
-fn app_captions_dir(app: &AppHandle, video_id: &str) -> Result {
-    tracing::info!("Getting captions directory for video_id: {}", video_id);
-
-    let app_dir = app
-        .path()
-        .app_data_dir()
-        .map_err(|_| "Failed to get app data directory".to_string())?;
-
-    let clean_video_id = video_id.trim_end_matches(".cap");
-    let captions_dir = app_dir.join("captions").join(clean_video_id);
-
-    tracing::info!("Captions directory path: {:?}", captions_dir);
-    Ok(captions_dir)
-}
-
-#[derive(Debug, Serialize, Type, tauri_specta::Event, Clone)]
-pub struct DownloadProgress {
-    pub progress: f64,
-    pub message: String,
-}
-
-#[derive(Debug, Serialize, Type, Clone, PartialEq, Eq)]
-#[serde(rename_all = "camelCase")]
-pub enum ModelDownloadState {
-    Downloading,
-    Completed,
-    Failed,
-}
-
-#[derive(Debug, Serialize, Type, Clone)]
-#[serde(rename_all = "camelCase")]
-pub struct ModelDownloadStatus {
-    pub state: ModelDownloadState,
-    pub progress: f64,
-    pub message: String,
-}
-
-#[derive(Clone)]
-struct ActiveModelDownload {
-    status: ModelDownloadStatus,
-    notify: Arc,
-}
-
-fn model_download_key(path: &Path) -> String {
-    path.to_string_lossy().into_owned()
-}
-
-fn model_download_status(
-    state: ModelDownloadState,
-    progress: f64,
-    message: String,
-) -> ModelDownloadStatus {
-    ModelDownloadStatus {
-        state,
-        progress: progress.clamp(0.0, 100.0),
-        message,
-    }
-}
-
-async fn begin_model_download(key: &str, message: String) -> bool {
-    let mut downloads = MODEL_DOWNLOADS.lock().await;
-    if downloads
-        .get(key)
-        .is_some_and(|entry| entry.status.state == ModelDownloadState::Downloading)
-    {
-        return false;
-    }
-
-    downloads.insert(
-        key.to_string(),
-        ActiveModelDownload {
-            status: model_download_status(ModelDownloadState::Downloading, 0.0, message),
-            notify: Arc::new(Notify::new()),
-        },
-    );
-    true
-}
-
-async fn wait_for_model_download(key: &str) -> Result<(), String> {
-    loop {
-        let entry = {
-            let downloads = MODEL_DOWNLOADS.lock().await;
-            downloads.get(key).cloned()
-        };
-
-        let Some(entry) = entry else {
-            return Ok(());
-        };
-
-        match entry.status.state {
-            ModelDownloadState::Downloading => {
-                tokio::select! {
-                    _ = entry.notify.notified() => {}
-                    _ = tokio::time::sleep(Duration::from_millis(250)) => {}
-                }
-            }
-            ModelDownloadState::Completed => return Ok(()),
-            ModelDownloadState::Failed => return Err(entry.status.message),
-        }
-    }
-}
-
-async fn set_model_download_status(app: &AppHandle, key: &str, status: ModelDownloadStatus) {
-    let notify = {
-        let mut downloads = MODEL_DOWNLOADS.lock().await;
-        downloads.get_mut(key).map(|entry| {
-            entry.status = status.clone();
-            entry.notify.clone()
-        })
-    };
-
-    let _ = DownloadProgress {
-        progress: status.progress,
-        message: status.message.clone(),
-    }
-    .emit(app);
-
-    if status.state != ModelDownloadState::Downloading
-        && let Some(notify) = notify
-    {
-        notify.notify_waiters();
-    }
-}
-
-async fn set_model_download_progress(app: &AppHandle, key: &str, progress: f64, message: String) {
-    set_model_download_status(
-        app,
-        key,
-        model_download_status(ModelDownloadState::Downloading, progress, message),
-    )
-    .await;
-}
-
-async fn clear_model_download_status(path: &Path) {
-    let key = model_download_key(path);
-    let mut downloads = MODEL_DOWNLOADS.lock().await;
-    let _ = downloads.remove(&key);
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-pub async fn get_model_download_status(
-    app: AppHandle,
-    target_path: String,
-) -> Result, String> {
-    let validated_path = validate_model_path(&app, &target_path)?;
-    let key = model_download_key(&validated_path);
-    let downloads = MODEL_DOWNLOADS.lock().await;
-    Ok(downloads.get(&key).map(|entry| entry.status.clone()))
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-pub async fn download_whisper_model(
-    app: AppHandle,
-    model_name: String,
-    output_path: String,
-) -> Result<(), String> {
-    let validated_path = validate_model_path(&app, &output_path)?;
-    let key = model_download_key(&validated_path);
-
-    if !begin_model_download(&key, "Preparing model download".to_string()).await {
-        return wait_for_model_download(&key).await;
-    }
-
-    let download_app = app.clone();
-    let download_key = key.clone();
-    tauri::async_runtime::spawn(async move {
-        let result = download_whisper_model_to_path(
-            &download_app,
-            &model_name,
-            &validated_path,
-            &download_key,
-        )
-        .await;
-        let final_status = match &result {
-            Ok(_) => model_download_status(
-                ModelDownloadState::Completed,
-                100.0,
-                "Download complete".to_string(),
-            ),
-            Err(error) => model_download_status(
-                ModelDownloadState::Failed,
-                0.0,
-                format!("Download failed: {error}"),
-            ),
-        };
-        set_model_download_status(&download_app, &download_key, final_status).await;
-    });
-
-    wait_for_model_download(&key).await
-}
-
-async fn download_whisper_model_to_path(
-    app: &AppHandle,
-    model_name: &str,
-    validated_path: &Path,
-    download_key: &str,
-) -> Result<(), String> {
-    let model_parts: &[&str] = match model_name {
-        "tiny" => &[
-            "https://github.com/CapSoftware/transcription-models/releases/download/whisper-v1/ggml-tiny.bin",
-        ],
-        "base" => &[
-            "https://github.com/CapSoftware/transcription-models/releases/download/whisper-v1/ggml-base.bin",
-        ],
-        "small" => &[
-            "https://github.com/CapSoftware/transcription-models/releases/download/whisper-v1/ggml-small.bin",
-        ],
-        "medium" => &[
-            "https://github.com/CapSoftware/transcription-models/releases/download/whisper-v1/ggml-medium.bin.part0",
-            "https://github.com/CapSoftware/transcription-models/releases/download/whisper-v1/ggml-medium.bin.part1",
-        ],
-        _ => &[
-            "https://github.com/CapSoftware/transcription-models/releases/download/whisper-v1/ggml-tiny.bin",
-        ],
-    };
-
-    if let Some(parent) = validated_path.parent() {
-        std::fs::create_dir_all(parent)
-            .map_err(|e| format!("Failed to create parent directories: {e}"))?;
-    }
-
-    let http_client = app.state::();
-    let total_size = total_content_length(&http_client, model_parts).await;
-
-    let mut file = tokio::fs::File::create(&validated_path)
-        .await
-        .map_err(|e| format!("Failed to create file: {e}"))?;
-
-    let mut downloaded: u64 = 0;
-    let part_count = model_parts.len() as f64;
-
-    for (idx, url) in model_parts.iter().enumerate() {
-        let response = http_client
-            .get(*url)
-            .timeout(MODEL_DOWNLOAD_REQUEST_TIMEOUT)
-            .send()
-            .await
-            .map_err(|e| format!("Failed to download model: {e}"))?;
-
-        if !response.status().is_success() {
-            return Err(format!(
-                "Failed to download model: HTTP {}",
-                response.status()
-            ));
-        }
-
-        let part_size = response.content_length().unwrap_or(0);
-        let mut downloaded_part: u64 = 0;
-        let mut stream = response.bytes_stream();
-        while let Some(chunk_result) = stream.next().await {
-            let chunk = chunk_result.map_err(|e| format!("Error while downloading: {e}"))?;
-
-            file.write_all(&chunk)
-                .await
-                .map_err(|e| format!("Error while writing to file: {e}"))?;
-
-            downloaded = downloaded.saturating_add(chunk.len() as u64);
-            downloaded_part = downloaded_part.saturating_add(chunk.len() as u64);
-
-            let progress = if total_size > 0 {
-                (downloaded as f64 / total_size as f64) * 100.0
-            } else if part_size > 0 {
-                ((idx as f64 + downloaded_part as f64 / part_size as f64) / part_count) * 100.0
-            } else {
-                (idx as f64 / part_count) * 100.0
-            };
-
-            set_model_download_progress(
-                app,
-                download_key,
-                progress,
-                format!("Downloading model: {progress:.0}%"),
-            )
-            .await;
-        }
-    }
-
-    file.flush()
-        .await
-        .map_err(|e| format!("Failed to flush file: {e}"))?;
-
-    Ok(())
-}
-
-async fn total_content_length(client: &reqwest::Client, urls: &[&str]) -> u64 {
-    let mut total: u64 = 0;
-    for url in urls {
-        let Ok(resp) = client
-            .head(*url)
-            .timeout(Duration::from_secs(30))
-            .send()
-            .await
-        else {
-            return 0;
-        };
-        if !resp.status().is_success() {
-            return 0;
-        }
-        match resp.content_length() {
-            Some(size) => total = total.saturating_add(size),
-            None => return 0,
-        }
-    }
-    total
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-pub async fn check_model_exists(app: AppHandle, model_path: String) -> Result {
-    let validated_path = validate_model_path(&app, &model_path)?;
-    Ok(validated_path.exists())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-pub async fn delete_whisper_model(app: AppHandle, model_path: String) -> Result<(), String> {
-    let validated_path = validate_model_path(&app, &model_path)?;
-
-    if !validated_path.exists() {
-        return Err(format!("Model file not found: {model_path}"));
-    }
-
-    clear_model_download_status(&validated_path).await;
-
-    tokio::fs::remove_file(&validated_path)
-        .await
-        .map_err(|e| format!("Failed to delete model file: {e}"))?;
-
-    invalidate_whisper_cache_for_path(&validated_path).await;
-
-    Ok(())
-}
-
-const MODEL_DOWNLOAD_REQUEST_TIMEOUT: Duration = Duration::from_secs(60 * 60);
-
-const PARAKEET_TDT_INT8_MODEL_FILES: &[(&str, &[&str])] = &[
-    (
-        "encoder-model.int8.onnx",
-        &[
-            "https://github.com/CapSoftware/transcription-models/releases/download/parakeet-tdt-v1/encoder-model.int8.onnx",
-        ],
-    ),
-    (
-        "decoder_joint-model.int8.onnx",
-        &[
-            "https://github.com/CapSoftware/transcription-models/releases/download/parakeet-tdt-v1/decoder_joint-model.int8.onnx",
-        ],
-    ),
-    (
-        "vocab.txt",
-        &[
-            "https://github.com/CapSoftware/transcription-models/releases/download/parakeet-tdt-v1/vocab.txt",
-        ],
-    ),
-];
-
-const PARAKEET_TDT_FULL_MODEL_FILES: &[(&str, &[&str])] = &[
-    (
-        "encoder-model.onnx",
-        &[
-            "https://github.com/CapSoftware/transcription-models/releases/download/parakeet-tdt-v1/encoder-model.onnx",
-        ],
-    ),
-    (
-        "encoder-model.onnx.data",
-        &[
-            "https://github.com/CapSoftware/transcription-models/releases/download/parakeet-tdt-v1/encoder-model.onnx.data.part0",
-            "https://github.com/CapSoftware/transcription-models/releases/download/parakeet-tdt-v1/encoder-model.onnx.data.part1",
-        ],
-    ),
-    (
-        "decoder_joint-model.onnx",
-        &[
-            "https://github.com/CapSoftware/transcription-models/releases/download/parakeet-tdt-v1/decoder_joint-model.onnx",
-        ],
-    ),
-    (
-        "vocab.txt",
-        &[
-            "https://github.com/CapSoftware/transcription-models/releases/download/parakeet-tdt-v1/vocab.txt",
-        ],
-    ),
-];
-
-const PARAKEET_MODEL_CLEANUP_FILES: &[&str] = &[
-    "encoder-model.onnx",
-    "encoder-model.onnx.data",
-    "decoder_joint-model.onnx",
-    "encoder-model.int8.onnx",
-    "decoder_joint-model.int8.onnx",
-    "nemo128.onnx",
-    "vocab.txt",
-];
-
-const PARAKEET_KNOWN_PART_SIZES: &[(&str, u64)] = &[
-    ("encoder-model.int8.onnx", 652_183_999),
-    ("decoder_joint-model.int8.onnx", 18_202_004),
-    ("encoder-model.onnx", 41_770_866),
-    ("encoder-model.onnx.data.part0", 1_300_000_000),
-    ("encoder-model.onnx.data.part1", 1_135_420_160),
-    ("decoder_joint-model.onnx", 72_520_893),
-    ("vocab.txt", 93_939),
-];
-
-fn parakeet_known_part_size(url: &str) -> Option {
-    PARAKEET_KNOWN_PART_SIZES.iter().find_map(|(name, size)| {
-        if url.ends_with(name) {
-            Some(*size)
-        } else {
-            None
-        }
-    })
-}
-
-fn parakeet_model_files_for_dir(
-    output_dir: &std::path::Path,
-) -> &'static [(&'static str, &'static [&'static str])] {
-    let dir_name = output_dir.file_name().and_then(|name| name.to_str());
-
-    match dir_name {
-        Some("parakeet-best-max") => PARAKEET_TDT_FULL_MODEL_FILES,
-        _ => PARAKEET_TDT_INT8_MODEL_FILES,
-    }
-}
-
-fn parakeet_staging_dir(validated_dir: &std::path::Path) -> PathBuf {
-    validated_dir.with_file_name(format!(
-        "{}.downloading",
-        validated_dir
-            .file_name()
-            .and_then(|n| n.to_str())
-            .unwrap_or("model")
-    ))
-}
-
-async fn parakeet_model_file_sizes(
-    http_client: &reqwest::Client,
-    model_files: &'static [(&'static str, &'static [&'static str])],
-) -> Result, String> {
-    let mut sizes = Vec::with_capacity(model_files.len());
-    for (filename, urls) in model_files {
-        let mut file_size = 0_u64;
-        for url in *urls {
-            let resp = http_client
-                .head(*url)
-                .timeout(Duration::from_secs(30))
-                .send()
-                .await
-                .map_err(|e| format!("Failed to get size for {filename}: {e}"))?;
-
-            if !resp.status().is_success() {
-                return Err(format!(
-                    "Failed to get size for {filename}: HTTP {}",
-                    resp.status()
-                ));
-            }
-
-            let part_size = resp
-                .content_length()
-                .filter(|size| *size > 0)
-                .or_else(|| parakeet_known_part_size(url))
-                .unwrap_or(0);
-            file_size = file_size.saturating_add(part_size);
-        }
-        sizes.push((*filename, file_size));
-    }
-    Ok(sizes)
-}
-
-fn parakeet_model_files_match(dir: &std::path::Path, expected_files: &[(&str, u64)]) -> bool {
-    expected_files.iter().all(|(filename, expected_size)| {
-        let Ok(metadata) = std::fs::metadata(dir.join(filename)) else {
-            return false;
-        };
-
-        metadata.is_file() && (*expected_size == 0 || metadata.len() == *expected_size)
-    })
-}
-
-fn finalize_parakeet_model_download(
-    validated_dir: &std::path::Path,
-    staging_dir: &std::path::Path,
-    model_files: &'static [(&'static str, &'static [&'static str])],
-) -> Result<(), String> {
-    std::fs::create_dir_all(validated_dir)
-        .map_err(|e| format!("Failed to create model directory: {e}"))?;
-
-    for filename in PARAKEET_MODEL_CLEANUP_FILES {
-        let file_path = validated_dir.join(filename);
-        if file_path.exists() {
-            let _ = std::fs::remove_file(&file_path);
-        }
-    }
-
-    for (filename, _) in model_files {
-        let src = staging_dir.join(filename);
-        let dst = validated_dir.join(filename);
-        std::fs::rename(&src, &dst)
-            .map_err(|e| format!("Failed to move {filename} to final location: {e}"))?;
-    }
-
-    let _ = std::fs::remove_dir_all(staging_dir);
-
-    Ok(())
-}
-
-#[cfg(not(all(target_os = "macos", target_arch = "x86_64")))]
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-pub async fn download_parakeet_model(app: AppHandle, output_dir: String) -> Result<(), String> {
-    let validated_dir = validate_model_path(&app, &output_dir)?;
-    let key = model_download_key(&validated_dir);
-
-    if !begin_model_download(&key, "Preparing model download".to_string()).await {
-        return wait_for_model_download(&key).await;
-    }
-
-    let download_app = app.clone();
-    let download_key = key.clone();
-    tauri::async_runtime::spawn(async move {
-        let result =
-            download_parakeet_model_to_dir(&download_app, &validated_dir, &download_key).await;
-        let final_status = match &result {
-            Ok(_) => model_download_status(
-                ModelDownloadState::Completed,
-                100.0,
-                "Download complete".to_string(),
-            ),
-            Err(error) => model_download_status(
-                ModelDownloadState::Failed,
-                0.0,
-                format!("Download failed: {error}"),
-            ),
-        };
-        set_model_download_status(&download_app, &download_key, final_status).await;
-    });
-
-    wait_for_model_download(&key).await
-}
-
-#[cfg(not(all(target_os = "macos", target_arch = "x86_64")))]
-async fn download_parakeet_model_to_dir(
-    app: &AppHandle,
-    validated_dir: &Path,
-    download_key: &str,
-) -> Result<(), String> {
-    std::fs::create_dir_all(validated_dir)
-        .map_err(|e| format!("Failed to create model directory: {e}"))?;
-
-    let http_client = app.state::();
-    let model_files = parakeet_model_files_for_dir(validated_dir);
-    let expected_file_sizes = parakeet_model_file_sizes(&http_client, model_files).await?;
-
-    let staging_dir = parakeet_staging_dir(validated_dir);
-    if parakeet_model_files_match(&staging_dir, &expected_file_sizes) {
-        tracing::info!("Finalizing previously completed Parakeet model download");
-        finalize_parakeet_model_download(validated_dir, &staging_dir, model_files)?;
-        invalidate_parakeet_cache_for_dir(validated_dir).await;
-        return Ok(());
-    }
-
-    if staging_dir.exists() {
-        std::fs::remove_dir_all(&staging_dir)
-            .map_err(|e| format!("Failed to clean staging directory: {e}"))?;
-    }
-    std::fs::create_dir_all(&staging_dir)
-        .map_err(|e| format!("Failed to create staging directory: {e}"))?;
-
-    let total_size = expected_file_sizes
-        .iter()
-        .fold(0_u64, |acc, (_, size)| acc.saturating_add(*size));
-
-    let mut downloaded_total: u64 = 0;
-
-    let download_result: Result<(), String> = async {
-        for (idx, (filename, urls)) in model_files.iter().enumerate() {
-            let file_path = staging_dir.join(filename);
-            let mut file = tokio::fs::File::create(&file_path)
-                .await
-                .map_err(|e| format!("Failed to create {filename}: {e}"))?;
-
-            for url in *urls {
-                tracing::info!("Downloading {filename} part from {url}");
-
-                let response = http_client
-                    .get(*url)
-                    .timeout(MODEL_DOWNLOAD_REQUEST_TIMEOUT)
-                    .send()
-                    .await
-                    .map_err(|e| format!("Failed to download {filename}: {e}"))?;
-
-                if !response.status().is_success() {
-                    return Err(format!(
-                        "Failed to download {filename}: HTTP {}",
-                        response.status()
-                    ));
-                }
-
-                let mut stream = response.bytes_stream();
-                while let Some(chunk_result) = stream.next().await {
-                    let chunk =
-                        chunk_result.map_err(|e| format!("Download error for {filename}: {e}"))?;
-                    file.write_all(&chunk)
-                        .await
-                        .map_err(|e| format!("Write error for {filename}: {e}"))?;
-
-                    downloaded_total = downloaded_total.saturating_add(chunk.len() as u64);
-
-                    let progress = if total_size > 0 {
-                        (downloaded_total as f64 / total_size as f64) * 100.0
-                    } else {
-                        ((idx as f64 + 0.5) / model_files.len() as f64) * 100.0
-                    };
-
-                    set_model_download_progress(
-                        app,
-                        download_key,
-                        progress,
-                        format!("Downloading {filename}: {progress:.0}%"),
-                    )
-                    .await;
-                }
-            }
-
-            file.flush()
-                .await
-                .map_err(|e| format!("Failed to flush {filename}: {e}"))?;
-
-            tracing::info!("Finished downloading {filename}");
-        }
-        Ok(())
-    }
-    .await;
-
-    if let Err(e) = &download_result {
-        tracing::warn!("Download failed, cleaning up staging directory: {e}");
-        let _ = std::fs::remove_dir_all(&staging_dir);
-        return Err(e.clone());
-    }
-
-    if !parakeet_model_files_match(&staging_dir, &expected_file_sizes) {
-        let _ = std::fs::remove_dir_all(&staging_dir);
-        return Err("Downloaded model files did not match expected sizes".to_string());
-    }
-
-    finalize_parakeet_model_download(validated_dir, &staging_dir, model_files)?;
-
-    invalidate_parakeet_cache_for_dir(validated_dir).await;
-
-    Ok(())
-}
-
-#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(_app))]
-pub async fn download_parakeet_model(_app: AppHandle, _output_dir: String) -> Result<(), String> {
-    Err(PARAKEET_UNSUPPORTED_MESSAGE.to_string())
-}
-
-#[cfg(not(all(target_os = "macos", target_arch = "x86_64")))]
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-pub async fn check_parakeet_model_exists(
-    app: AppHandle,
-    model_dir: String,
-) -> Result {
-    let validated_dir = validate_model_path(&app, &model_dir)?;
-
-    if !validated_dir.is_dir() {
-        return Ok(false);
-    }
-
-    let has_vocab = validated_dir.join("vocab.txt").exists();
-    let has_full_model = validated_dir.join("encoder-model.onnx").exists()
-        && validated_dir.join("encoder-model.onnx.data").exists()
-        && validated_dir.join("decoder_joint-model.onnx").exists();
-    let has_int8_model = validated_dir.join("encoder-model.int8.onnx").exists()
-        && validated_dir.join("decoder_joint-model.int8.onnx").exists();
-
-    Ok(has_vocab && (has_full_model || has_int8_model))
-}
-
-#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(_app))]
-pub async fn check_parakeet_model_exists(
-    _app: AppHandle,
-    _model_dir: String,
-) -> Result {
-    Ok(false)
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-pub async fn delete_parakeet_model(app: AppHandle, model_dir: String) -> Result<(), String> {
-    let validated_dir = validate_model_path(&app, &model_dir)?;
-
-    if !validated_dir.exists() {
-        return Err(format!("Model directory not found: {model_dir}"));
-    }
-
-    invalidate_parakeet_cache_for_dir(&validated_dir).await;
-    clear_model_download_status(&validated_dir).await;
-
-    tokio::fs::remove_dir_all(&validated_dir)
-        .await
-        .map_err(|e| format!("Failed to delete model directory: {e}"))?;
-
-    Ok(())
-}
-
-fn captions_to_srt(captions: &CaptionData) -> String {
-    let mut srt = String::new();
-    for (i, segment) in captions.segments.iter().enumerate() {
-        let start_time = format_srt_time(f64::from(segment.start));
-        let end_time = format_srt_time(f64::from(segment.end));
-
-        srt.push_str(&format!(
-            "{}\n{} --> {}\n{}\n\n",
-            i + 1,
-            start_time,
-            end_time,
-            segment.text.trim()
-        ));
-    }
-    srt
-}
-
-fn format_srt_time(seconds: f64) -> String {
-    let hours = (seconds / 3600.0) as i32;
-    let minutes = ((seconds % 3600.0) / 60.0) as i32;
-    let secs = (seconds % 60.0) as i32;
-    let millis = ((seconds % 1.0) * 1000.0) as i32;
-    format!("{hours:02}:{minutes:02}:{secs:02},{millis:03}")
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-pub async fn export_captions_srt(
-    app: AppHandle,
-    video_id: String,
-) -> Result, String> {
-    tracing::info!("Starting SRT export for video_id: {}", video_id);
-
-    let captions = match load_captions(app.clone(), video_id.clone()).await? {
-        Some(c) => {
-            tracing::info!("Found {} caption segments to export", c.segments.len());
-            c
-        }
-        None => {
-            tracing::info!("No captions found for video_id: {}", video_id);
-            return Ok(None);
-        }
-    };
-
-    let captions_with_settings = CaptionData {
-        segments: captions.segments,
-        settings: captions
-            .settings
-            .or_else(|| Some(CaptionSettings::default())),
-    };
-
-    tracing::info!("Converting captions to SRT format");
-    let srt_content = captions_to_srt(&captions_with_settings);
-
-    let captions_dir = app_captions_dir(&app, &video_id)?;
-    let srt_path = captions_dir.join("captions.srt");
-    tracing::info!("Will write SRT file to: {:?}", srt_path);
-
-    match std::fs::write(&srt_path, srt_content) {
-        Ok(_) => {
-            tracing::info!("Successfully wrote SRT file to: {:?}", srt_path);
-            Ok(Some(srt_path))
-        }
-        Err(e) => {
-            tracing::error!("Failed to write SRT file: {}", e);
-            Err(format!("Failed to write SRT file: {e}"))
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::{
-        AudioExtractionSource, CaptionWord, caption_text_from_words, caption_word_chunks,
-        normalize_caption_words, resolve_audio_extraction_source, resolve_path_with_base,
-    };
-    use tempfile::tempdir;
-
-    fn word(text: &str, index: usize) -> CaptionWord {
-        CaptionWord {
-            text: text.to_string(),
-            start: index as f32,
-            end: index as f32 + 0.5,
-        }
-    }
-
-    #[test]
-    fn resolve_path_with_base_rejects_parent_dir_escape() {
-        let dir = tempdir().unwrap();
-        let base = dir.path().join("app-data");
-        std::fs::create_dir_all(base.join("models")).unwrap();
-
-        let escaped = base.join("..").join("outside.bin");
-
-        let result = resolve_path_with_base(&base, escaped.to_string_lossy().as_ref());
-
-        assert!(result.is_err());
-    }
-
-    #[test]
-    fn resolve_path_with_base_allows_nested_model_path() {
-        let dir = tempdir().unwrap();
-        let base = dir.path().join("app-data");
-        std::fs::create_dir_all(base.join("models")).unwrap();
-
-        let target = base.join("models").join("nested").join("model.bin");
-        let expected = base
-            .canonicalize()
-            .unwrap()
-            .join("models")
-            .join("nested")
-            .join("model.bin");
-
-        let resolved = resolve_path_with_base(&base, target.to_string_lossy().as_ref()).unwrap();
-
-        assert_eq!(resolved, expected);
-    }
-
-    #[test]
-    fn audio_extraction_source_accepts_project_directory_without_cap_extension() {
-        let dir = tempdir().unwrap();
-        let project_dir = dir.path().join("recording");
-        std::fs::create_dir_all(&project_dir).unwrap();
-        std::fs::write(project_dir.join("recording-meta.json"), "{}").unwrap();
-
-        match resolve_audio_extraction_source(project_dir.to_string_lossy().as_ref()).unwrap() {
-            AudioExtractionSource::ProjectDirectory { base_path } => {
-                assert_eq!(base_path, project_dir);
-            }
-            AudioExtractionSource::MediaFile(_) => panic!("expected project directory"),
-        }
-    }
-
-    #[test]
-    fn audio_extraction_source_rejects_directory_without_recording_metadata() {
-        let dir = tempdir().unwrap();
-        let result = resolve_audio_extraction_source(dir.path().to_string_lossy().as_ref());
-
-        match result {
-            Ok(_) => panic!("expected missing metadata error"),
-            Err(error) => assert_eq!(error, "Recording directory is missing recording-meta.json"),
-        }
-    }
-
-    #[test]
-    fn audio_extraction_source_accepts_media_file() {
-        let dir = tempdir().unwrap();
-        let media_file = dir.path().join("recording.mp4");
-        std::fs::write(&media_file, []).unwrap();
-
-        match resolve_audio_extraction_source(media_file.to_string_lossy().as_ref()).unwrap() {
-            AudioExtractionSource::MediaFile(path) => assert_eq!(path, media_file),
-            AudioExtractionSource::ProjectDirectory { .. } => panic!("expected media file"),
-        }
-    }
-
-    #[test]
-    fn normalize_caption_words_attaches_punctuation() {
-        let words = normalize_caption_words(vec![
-            word("test", 0),
-            word(",", 1),
-            word("test", 2),
-            word(".", 3),
-        ]);
-
-        assert_eq!(caption_text_from_words(&words), "test, test.");
-        assert_eq!(words.len(), 2);
-    }
-
-    #[test]
-    fn normalize_caption_words_clamps_inflated_trailing_word() {
-        let words = normalize_caption_words(vec![CaptionWord {
-            text: "seconds.".to_string(),
-            start: 53.92,
-            end: 70.16,
-        }]);
-
-        assert_eq!(words.len(), 1);
-        assert!((words[0].end - (53.92 + super::MAX_CAPTION_WORD_DURATION)).abs() < 1e-4);
-    }
-
-    #[test]
-    fn normalize_caption_words_keeps_normal_word_durations() {
-        let words = normalize_caption_words(vec![CaptionWord {
-            text: "hello".to_string(),
-            start: 1.0,
-            end: 1.4,
-        }]);
-
-        assert_eq!(words.len(), 1);
-        assert!((words[0].end - 1.4).abs() < 1e-4);
-    }
-
-    #[test]
-    fn caption_word_chunks_do_not_end_on_short_connector_when_more_words_follow() {
-        let words = [
-            "This", "is", "where", "we", "record", "I", "want", "clean", "captions",
-        ]
-        .iter()
-        .enumerate()
-        .map(|(index, text)| word(text, index))
-        .collect::>();
-
-        let chunks = caption_word_chunks(&words);
-
-        assert_eq!(
-            caption_text_from_words(chunks[0]),
-            "This is where we record I want"
-        );
-        assert_eq!(caption_text_from_words(chunks[1]), "clean captions");
-    }
-
-    #[cfg(not(all(target_os = "macos", target_arch = "x86_64")))]
-    mod parakeet {
-        use super::super::parakeet_model_dir_matches;
-        use tempfile::tempdir;
-
-        #[test]
-        fn parakeet_model_dir_match_uses_full_directory_path() {
-            let dir = tempdir().unwrap();
-            let model_dir = dir.path().join("models").join("parakeet-best");
-
-            assert!(parakeet_model_dir_matches(
-                model_dir.to_string_lossy().as_ref(),
-                &model_dir
-            ));
-            assert!(!parakeet_model_dir_matches(
-                dir.path()
-                    .join("models")
-                    .join("parakeet-best-max")
-                    .to_string_lossy()
-                    .as_ref(),
-                &model_dir
-            ));
-        }
-    }
-}
diff --git a/apps/desktop/src-tauri/src/clean_capture.rs b/apps/desktop/src-tauri/src/clean_capture.rs
deleted file mode 100644
index d2fc47e234f..00000000000
--- a/apps/desktop/src-tauri/src/clean_capture.rs
+++ /dev/null
@@ -1,4536 +0,0 @@
-use std::{
-    path::PathBuf,
-    sync::{
-        Arc, Mutex,
-        atomic::{AtomicBool, Ordering},
-    },
-    time::Duration,
-};
-
-use serde::Serialize;
-use specta::Type;
-use tauri::{AppHandle, Manager, WebviewWindow};
-use tauri_specta::Event;
-use tokio::sync::Notify;
-
-use crate::{CurrentRecordingChanged, windows::CapWindowId};
-
-pub const STOP_SHORTCUT: &str = "Ctrl+Shift+F9";
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Type)]
-#[serde(rename_all = "camelCase")]
-pub enum Phase {
-    AwaitingShortcut,
-    Starting,
-    Recording,
-    Pausing,
-    Paused,
-    Resuming,
-    ResumeFailed,
-    Restarting,
-    Stopping,
-    Restoring,
-}
-
-impl Phase {
-    fn can_stop(self) -> bool {
-        matches!(
-            self,
-            Self::Recording | Self::Paused | Self::Resuming | Self::ResumeFailed
-        )
-    }
-}
-
-#[derive(Clone, Serialize, Type)]
-#[serde(rename_all = "camelCase")]
-pub struct Snapshot {
-    pub generation: u32,
-    pub phase: Option,
-    pub mode: Option,
-    pub shortcut: Option,
-    pub error: Option,
-}
-
-#[derive(Clone)]
-struct SavedWindow {
-    label: String,
-    native_id: u64,
-    visible: bool,
-}
-
-impl SavedWindow {
-    fn visibility_for(&self, native_id: u64) -> Option {
-        (self.native_id == native_id).then_some(self.visible)
-    }
-}
-
-#[derive(Clone, Copy, PartialEq, Eq)]
-pub(crate) enum StopRoute {
-    #[cfg(any(target_os = "linux", test))]
-    Tray,
-    #[cfg(any(target_os = "linux", test))]
-    Portal,
-}
-
-struct Lease {
-    mode: cap_recording::RecordingMode,
-    generation: u32,
-    phase: Phase,
-    pressed: bool,
-    stop_requested: bool,
-    registered_shortcut: bool,
-    wayland: bool,
-    stop_route: Option,
-    stop_description: Option,
-    stop_error: Option,
-    lost_stop_routes: [bool; 2],
-    recording_dir: Option,
-    windows: Vec,
-}
-
-impl StopRoute {
-    fn index(self) -> usize {
-        match self {
-            #[cfg(any(target_os = "linux", test))]
-            Self::Tray => 0,
-            #[cfg(any(target_os = "linux", test))]
-            Self::Portal => 1,
-        }
-    }
-}
-
-impl Lease {
-    fn accept_stop_input(&mut self, route: Option<(u32, StopRoute)>, pressed: bool) -> bool {
-        match route {
-            Some((generation, route))
-                if self.wayland
-                    && self.generation == generation
-                    && !self.lost_stop_routes[route.index()] =>
-            {
-                if self.phase == Phase::AwaitingShortcut {
-                    if pressed {
-                        self.stop_route = Some(route);
-                    } else if self.stop_route != Some(route) {
-                        return false;
-                    }
-                }
-                true
-            }
-            None if !self.wayland => true,
-            _ => false,
-        }
-    }
-
-    #[cfg(any(target_os = "linux", test))]
-    fn lose_stop_route(&mut self, route: StopRoute) -> bool {
-        self.lost_stop_routes[route.index()] = true;
-        let lost = self.stop_route == Some(route) || self.lost_stop_routes.iter().all(|lost| *lost);
-        if lost {
-            self.stop_requested = true;
-        }
-        lost && self.phase.can_stop()
-    }
-}
-
-struct ControlError {
-    generation: u32,
-    dir: PathBuf,
-    message: String,
-}
-
-#[derive(Clone)]
-pub(crate) struct StopNoticeOwner {
-    sequence: u64,
-    directory: PathBuf,
-    generation: Option,
-    confirmed: Arc,
-}
-
-impl StopNoticeOwner {
-    pub(crate) fn is_confirmed(&self) -> bool {
-        self.confirmed.load(Ordering::Acquire)
-    }
-
-    pub(crate) fn same_attempt(&self, other: &Self) -> bool {
-        Arc::ptr_eq(&self.confirmed, &other.confirmed)
-    }
-}
-
-#[derive(Clone)]
-pub(crate) struct StopNoticeTicket {
-    sequence: u64,
-    pub(crate) owner: StopNoticeOwner,
-}
-
-#[derive(Clone, Copy, PartialEq, Eq)]
-pub(crate) enum StopNoticeKind {
-    Unconfirmed,
-    ConfirmedFailure,
-    ControlFailure,
-}
-
-struct StopNotice {
-    ticket: StopNoticeTicket,
-    kind: StopNoticeKind,
-    message: String,
-    previous_message: Option,
-    restoration: Option>,
-}
-
-impl StopNotice {
-    fn error(&self) -> String {
-        let confirmed =
-            self.ticket.owner.is_confirmed() || self.kind == StopNoticeKind::ConfirmedFailure;
-        let status = if confirmed {
-            match (&self.restoration, self.ticket.owner.generation) {
-                (Some(Err(_)), _) => "Recording stopped; window restoration failed",
-                (None, Some(_)) => "Recording stopped; window restoration is pending",
-                _ => "Recording stopped",
-            }
-        } else {
-            "Stop could not be confirmed"
-        };
-        let mut message = format!(
-            "{status} ({}): {}",
-            self.ticket.owner.directory.display(),
-            self.message
-        );
-        if let Some(previous) = &self.previous_message {
-            message.push('\n');
-            message.push_str(previous);
-        }
-        if let Some(Err(error)) = &self.restoration
-            && !self.message.contains(error)
-        {
-            message.push('\n');
-            message.push_str(error);
-        }
-        message
-    }
-}
-
-struct RestorationReceipt {
-    generation: u32,
-    result: Result<(), String>,
-    #[cfg(target_os = "linux")]
-    stop_requested: bool,
-}
-
-impl RestorationReceipt {
-    fn restoration_result(&self) -> Result<(), String> {
-        self.result.clone()
-    }
-
-    #[cfg(target_os = "linux")]
-    fn restart_result(&self) -> Result<(), String> {
-        self.restoration_result()?;
-        if self.stop_requested {
-            Err("Recording restart was cancelled by Stop".into())
-        } else {
-            Ok(())
-        }
-    }
-}
-
-#[derive(Default)]
-struct Inner {
-    generation: u32,
-    lease: Option,
-    control_error: Option,
-    restored: Option,
-    stop_notice_sequence: u64,
-    stop_notice: Option,
-    #[cfg(target_os = "linux")]
-    x11_cleanup_sequence: u64,
-    #[cfg(target_os = "linux")]
-    x11_cleanup: Option,
-}
-
-#[cfg(target_os = "linux")]
-#[derive(Clone, Copy, PartialEq, Eq)]
-struct X11StudioCleanup {
-    generation: u32,
-    sequence: u64,
-    registered_shortcut: bool,
-}
-
-#[derive(Default)]
-pub struct State {
-    #[cfg(target_os = "linux")]
-    pub(crate) instant: Mutex>,
-    #[cfg(target_os = "linux")]
-    pub(crate) portal_stop: tokio::sync::Mutex>,
-    inner: Mutex,
-    changed: Notify,
-}
-
-impl Inner {
-    #[cfg(target_os = "linux")]
-    fn reserve_x11_studio_cleanup(
-        &mut self,
-        generation: u32,
-        windows: Result<(), String>,
-    ) -> Option {
-        if self.x11_cleanup.is_some()
-            || self
-                .restored
-                .as_ref()
-                .is_some_and(|receipt| receipt.generation == generation)
-        {
-            return None;
-        }
-        let lease = self.lease.as_ref().filter(|lease| {
-            self.generation == generation
-                && lease.generation == generation
-                && lease.phase == Phase::Restoring
-                && lease.mode == cap_recording::RecordingMode::Studio
-                && !lease.wayland
-        })?;
-        let registered_shortcut = lease.registered_shortcut;
-        if let Err(error) = windows {
-            let _ = self.complete_instant_restoration(generation, Err(error));
-            return None;
-        }
-        self.x11_cleanup_sequence = self.x11_cleanup_sequence.wrapping_add(1);
-        let cleanup = X11StudioCleanup {
-            generation,
-            sequence: self.x11_cleanup_sequence,
-            registered_shortcut,
-        };
-        self.x11_cleanup = Some(cleanup);
-        Some(cleanup)
-    }
-
-    #[cfg(target_os = "linux")]
-    fn complete_x11_studio_restoration(
-        &mut self,
-        cleanup: X11StudioCleanup,
-        result: Result<(), String>,
-    ) -> bool {
-        if self.x11_cleanup != Some(cleanup)
-            || self.generation != cleanup.generation
-            || self.lease.as_ref().is_none_or(|lease| {
-                lease.generation != cleanup.generation
-                    || lease.phase != Phase::Restoring
-                    || lease.mode != cap_recording::RecordingMode::Studio
-                    || lease.wayland
-                    || lease.registered_shortcut != cleanup.registered_shortcut
-            })
-        {
-            return false;
-        }
-        self.x11_cleanup = None;
-        self.complete_instant_restoration(cleanup.generation, result)
-            .is_some()
-    }
-
-    #[cfg(target_os = "linux")]
-    fn begin_x11_studio_restore_retry(&mut self, pressed: bool) -> Option {
-        if !pressed || self.x11_cleanup.is_some() {
-            return None;
-        }
-        let generation = self.generation;
-        let lease = self.lease.as_mut().filter(|lease| {
-            lease.generation == generation
-                && lease.phase == Phase::Restoring
-                && lease.mode == cap_recording::RecordingMode::Studio
-                && !lease.wayland
-        })?;
-        if !self.restored.as_ref().is_some_and(|receipt| {
-            receipt.generation == lease.generation && receipt.result.is_err()
-        }) {
-            return None;
-        }
-        lease.stop_requested = true;
-        self.restored = None;
-        Some(lease.generation)
-    }
-
-    #[cfg(target_os = "linux")]
-    fn complete_instant_restoration(
-        &mut self,
-        generation: u32,
-        result: Result<(), String>,
-    ) -> Option {
-        if self
-            .lease
-            .as_ref()
-            .is_none_or(|lease| lease.generation != generation || lease.phase != Phase::Restoring)
-        {
-            return None;
-        }
-        let succeeded = result.is_ok();
-        let _ = self.record_stop_restoration(generation, result);
-        if succeeded {
-            let owned = self.lease.take().unwrap().registered_shortcut;
-            self.generation = self.generation.wrapping_add(1);
-            Some(owned)
-        } else {
-            None
-        }
-    }
-
-    fn record_stop_restoration(&mut self, generation: u32, result: Result<(), String>) -> bool {
-        let Some(lease) = self
-            .lease
-            .as_ref()
-            .filter(|lease| lease.generation == generation && lease.phase == Phase::Restoring)
-        else {
-            return false;
-        };
-        if let Some(notice) = &mut self.stop_notice
-            && notice.ticket.owner.generation == Some(generation)
-            && lease.recording_dir.as_ref() == Some(¬ice.ticket.owner.directory)
-        {
-            notice.restoration = Some(result.clone());
-        }
-        self.restored = Some(RestorationReceipt {
-            generation,
-            result,
-            #[cfg(target_os = "linux")]
-            stop_requested: lease.stop_requested,
-        });
-        true
-    }
-
-    fn next_stop_notice_sequence(&mut self) -> u64 {
-        self.stop_notice_sequence = self
-            .stop_notice_sequence
-            .checked_add(1)
-            .expect("Stop notice identity exhausted");
-        self.stop_notice_sequence
-    }
-
-    fn reserve_stop_notice_owner(
-        &mut self,
-        directory: PathBuf,
-        generation: Option,
-    ) -> StopNoticeOwner {
-        StopNoticeOwner {
-            sequence: self.next_stop_notice_sequence(),
-            directory,
-            generation,
-            confirmed: Arc::new(AtomicBool::new(false)),
-        }
-    }
-
-    fn reserve_stop_notice_ticket(&mut self, owner: StopNoticeOwner) -> StopNoticeTicket {
-        StopNoticeTicket {
-            sequence: self.next_stop_notice_sequence(),
-            owner,
-        }
-    }
-
-    fn retain_stop_notice(
-        &mut self,
-        ticket: &StopNoticeTicket,
-        kind: StopNoticeKind,
-        message: String,
-    ) -> bool {
-        if let Some(previous) = &mut self.stop_notice {
-            if previous.ticket.sequence == ticket.sequence
-                && previous.ticket.owner.same_attempt(&ticket.owner)
-            {
-                if previous.message == message
-                    || previous.previous_message.as_ref() == Some(&message)
-                {
-                    return false;
-                }
-                if kind == StopNoticeKind::ConfirmedFailure {
-                    previous.previous_message =
-                        Some(std::mem::replace(&mut previous.message, message));
-                    previous.kind = kind;
-                } else {
-                    previous.previous_message = Some(message);
-                }
-                tracing::info!(project = %ticket.owner.directory.display(), "Retained distinct failure from the same Stop cohort");
-                return true;
-            }
-            if (previous.ticket.owner.sequence, previous.ticket.sequence)
-                >= (ticket.owner.sequence, ticket.sequence)
-            {
-                return false;
-            }
-            tracing::info!(
-                previous_project = %previous.ticket.owner.directory.display(),
-                next_project = %ticket.owner.directory.display(),
-                "Retained Stop notice superseded by a newer failure"
-            );
-        }
-        let restoration = self
-            .restored
-            .as_ref()
-            .filter(|receipt| Some(receipt.generation) == ticket.owner.generation)
-            .map(RestorationReceipt::restoration_result);
-        self.stop_notice = Some(StopNotice {
-            ticket: ticket.clone(),
-            kind,
-            message,
-            previous_message: None,
-            restoration,
-        });
-        true
-    }
-
-    fn owner(&self, dir: &std::path::Path) -> Option {
-        self.lease.as_ref().and_then(|lease| {
-            (lease.recording_dir.as_deref() == Some(dir)).then_some(lease.generation)
-        })
-    }
-    fn queue_stop(&mut self) -> bool {
-        let Some(lease) = self.lease.as_mut() else {
-            return false;
-        };
-        lease.stop_requested = true;
-        let deferred = !lease.phase.can_stop();
-        if !deferred {
-            lease.phase = Phase::Stopping;
-        }
-        deferred
-    }
-
-    fn control_current(&self, generation: u32, dir: &std::path::Path, resume: bool) -> bool {
-        let transition = if resume {
-            Phase::Resuming
-        } else {
-            Phase::Pausing
-        };
-        self.generation == generation
-            && self.lease.as_ref().is_some_and(|lease| {
-                lease.generation == generation
-                    && lease.phase == transition
-                    && lease.recording_dir.as_deref() == Some(dir)
-            })
-    }
-
-    fn complete_control(
-        &mut self,
-        generation: u32,
-        dir: &std::path::Path,
-        resume: bool,
-        outcome: &ControlOutcome,
-    ) -> bool {
-        if !self.control_current(generation, dir, resume) {
-            return false;
-        }
-        self.control_error = match outcome {
-            ControlOutcome::Succeeded | ControlOutcome::StoppedBeforeResume => None,
-            ControlOutcome::HideFailed(message)
-            | ControlOutcome::ActorFailed { error: message, .. } => Some(ControlError {
-                generation,
-                dir: dir.to_path_buf(),
-                message: message.clone(),
-            }),
-        };
-        self.lease.as_mut().unwrap().phase = match (resume, outcome) {
-            (true, ControlOutcome::Succeeded) | (false, ControlOutcome::ActorFailed { .. }) => {
-                Phase::Recording
-            }
-            (true, ControlOutcome::ActorFailed { paused: false, .. }) => Phase::ResumeFailed,
-            _ => Phase::Paused,
-        };
-        true
-    }
-
-    fn may_restore_paused_main(&self, generation: u32, dir: &std::path::Path) -> bool {
-        self.owner(dir) == Some(generation)
-            && self
-                .lease
-                .as_ref()
-                .is_some_and(|lease| lease.phase == Phase::Paused && !lease.stop_requested)
-            && self.may_reveal(generation, "main")
-    }
-
-    fn snapshot(&self) -> Snapshot {
-        let mut errors = Vec::with_capacity(4);
-        if let Some(error) = self.control_error.as_ref().filter(|error| {
-            error.generation == self.generation
-                && self
-                    .lease
-                    .as_ref()
-                    .is_none_or(|lease| lease.recording_dir.as_ref() == Some(&error.dir))
-        }) {
-            errors.push(error.message.clone());
-        }
-        for error in [
-            self.lease
-                .as_ref()
-                .and_then(|lease| lease.stop_error.clone()),
-            self.restored.as_ref().and_then(|receipt| {
-                self.lease
-                    .as_ref()
-                    .filter(|lease| lease.generation == receipt.generation)
-                    .and_then(|_| receipt.result.as_ref().err().cloned())
-            }),
-            self.stop_notice.as_ref().map(StopNotice::error),
-        ]
-        .into_iter()
-        .flatten()
-        {
-            if !errors.contains(&error) {
-                errors.push(error);
-            }
-        }
-        Snapshot {
-            generation: self.generation,
-            phase: self.lease.as_ref().map(|lease| lease.phase),
-            mode: self.lease.as_ref().map(|lease| lease.mode),
-            shortcut: self.lease.as_ref().map(|lease| {
-                lease.stop_description.clone().unwrap_or_else(|| {
-                    if lease.wayland {
-                        "the Cap Stop tray icon".to_string()
-                    } else {
-                        STOP_SHORTCUT.to_string()
-                    }
-                })
-            }),
-            error: (!errors.is_empty()).then(|| errors.join("\n")),
-        }
-    }
-
-    fn may_reveal(&self, generation: u32, label: &str) -> bool {
-        if generation != self.generation {
-            return false;
-        }
-        let Some(lease) = &self.lease else {
-            return true;
-        };
-        if lease.wayland && wayland_blocks_mapping(lease.phase) {
-            return false;
-        }
-        match label.parse::() {
-            Ok(CapWindowId::Main) => {
-                matches!(
-                    lease.phase,
-                    Phase::AwaitingShortcut | Phase::Paused | Phase::Restoring
-                ) && (!lease.stop_requested || lease.phase == Phase::Restoring)
-            }
-            Ok(
-                CapWindowId::Camera
-                | CapWindowId::RecordingControls
-                | CapWindowId::TargetSelectOverlay { .. },
-            ) => false,
-            _ => true,
-        }
-    }
-
-    fn shortcut(&mut self, pressed: bool) -> bool {
-        let Some(lease) = self.lease.as_mut() else {
-            return false;
-        };
-        if lease.phase == Phase::AwaitingShortcut {
-            if pressed {
-                lease.pressed = true;
-            } else if lease.pressed {
-                lease.phase = Phase::Starting;
-                lease.pressed = false;
-            }
-        } else if pressed {
-            lease.stop_requested = true;
-        }
-        true
-    }
-}
-
-pub fn generation(app: &AppHandle) -> u32 {
-    app.try_state::()
-        .map(|state| state.inner.lock().unwrap().generation)
-        .unwrap_or(0)
-}
-
-pub fn phase(app: &AppHandle) -> Option {
-    app.try_state::()
-        .and_then(|state| state.inner.lock().unwrap().lease.as_ref().map(|l| l.phase))
-}
-
-pub fn blocks_idle_cleanup(app: &AppHandle) -> bool {
-    #[cfg(target_os = "linux")]
-    if crate::recording::linux_instant::current(app).is_some() {
-        return true;
-    }
-    phase(app).is_some_and(|phase| phase != Phase::Restoring)
-}
-
-pub fn cancel_closed_preflight(app: &AppHandle) {
-    let state = app.state::();
-    let mut inner = state.inner.lock().unwrap();
-    let Some(lease) = inner
-        .lease
-        .as_mut()
-        .filter(|lease| lease.phase == Phase::AwaitingShortcut)
-    else {
-        return;
-    };
-    lease.stop_requested = true;
-    for saved in &mut lease.windows {
-        if saved.label == CapWindowId::Main.label() {
-            saved.visible = false;
-        }
-    }
-    drop(inner);
-    notify(app);
-}
-
-pub fn is_current(app: &AppHandle, generation: u32) -> bool {
-    app.state::()
-        .inner
-        .lock()
-        .unwrap()
-        .lease
-        .as_ref()
-        .is_some_and(|lease| lease.generation == generation)
-}
-
-pub fn stop_requested(app: &AppHandle, generation: u32) -> bool {
-    app.state::()
-        .inner
-        .lock()
-        .unwrap()
-        .lease
-        .as_ref()
-        .filter(|lease| lease.generation == generation)
-        .is_none_or(|lease| lease.stop_requested)
-}
-
-fn notify(app: &AppHandle) {
-    app.state::().changed.notify_waiters();
-    let _ = CurrentRecordingChanged.emit(app);
-}
-
-pub(crate) fn reserve_stop_notice_owner(
-    app: &AppHandle,
-    directory: PathBuf,
-    generation: Option,
-) -> StopNoticeOwner {
-    app.state::()
-        .inner
-        .lock()
-        .unwrap()
-        .reserve_stop_notice_owner(directory, generation)
-}
-
-pub(crate) fn reserve_stop_notice_ticket(
-    app: &AppHandle,
-    owner: StopNoticeOwner,
-) -> StopNoticeTicket {
-    app.state::()
-        .inner
-        .lock()
-        .unwrap()
-        .reserve_stop_notice_ticket(owner)
-}
-
-pub(crate) fn retain_stop_notice(
-    app: &AppHandle,
-    ticket: &StopNoticeTicket,
-    kind: StopNoticeKind,
-    message: String,
-) {
-    let retained = app
-        .state::()
-        .inner
-        .lock()
-        .unwrap()
-        .retain_stop_notice(ticket, kind, message);
-    if retained {
-        notify(app);
-    }
-}
-
-pub(crate) fn confirm_stop_notice(app: &AppHandle, owner: &StopNoticeOwner) {
-    owner.confirmed.store(true, Ordering::Release);
-    notify(app);
-}
-
-pub fn set_phase(app: &AppHandle, generation: u32, phase: Phase) -> bool {
-    let state = app.state::();
-    let mut inner = state.inner.lock().unwrap();
-    let Some(lease) = inner.lease.as_mut().filter(|l| l.generation == generation) else {
-        return false;
-    };
-    lease.phase = phase;
-    drop(inner);
-    notify(app);
-    true
-}
-
-pub fn publish(app: &AppHandle, generation: u32, dir: PathBuf) -> bool {
-    let state = app.state::();
-    let mut inner = state.inner.lock().unwrap();
-    let Some(lease) = inner.lease.as_mut().filter(|l| l.generation == generation) else {
-        return false;
-    };
-    if lease.phase != Phase::Starting {
-        return false;
-    }
-    lease.recording_dir = Some(dir);
-    lease.phase = Phase::Recording;
-    true
-}
-
-pub fn set_start_directory(app: &AppHandle, generation: u32, dir: PathBuf) -> Result<(), String> {
-    let state = app.state::();
-    let mut inner = state.inner.lock().unwrap();
-    let lease = inner
-        .lease
-        .as_mut()
-        .filter(|lease| lease.generation == generation && lease.phase == Phase::Starting)
-        .ok_or("Recording startup was superseded")?;
-    lease.recording_dir = Some(dir);
-    Ok(())
-}
-
-pub fn owner(app: &AppHandle, dir: &std::path::Path) -> Option {
-    let state = app.state::();
-    let inner = state.inner.lock().unwrap();
-    inner.owner(dir)
-}
-
-pub fn queue_stop(app: &AppHandle) -> bool {
-    let state = app.state::();
-    let mut inner = state.inner.lock().unwrap();
-    if inner.lease.is_none() {
-        return false;
-    }
-    let deferred = inner.queue_stop();
-    drop(inner);
-    notify(app);
-    deferred
-}
-
-pub(crate) fn queue_owned_studio_stop(
-    app: &AppHandle,
-    generation: u32,
-    directory: &std::path::Path,
-) -> bool {
-    let state = app.state::();
-    let mut inner = state.inner.lock().unwrap();
-    if inner.lease.as_ref().is_none_or(|lease| {
-        lease.generation != generation
-            || lease.mode != cap_recording::RecordingMode::Studio
-            || lease.recording_dir.as_deref() != Some(directory)
-            || !(lease.phase.can_stop() || lease.phase == Phase::Stopping)
-    }) {
-        return false;
-    }
-    let _ = inner.queue_stop();
-    drop(inner);
-    notify(app);
-    true
-}
-
-pub fn handle_shortcut(app: &AppHandle, pressed: bool) -> bool {
-    handle_stop_input(app, pressed, None)
-}
-
-#[cfg(target_os = "linux")]
-pub(crate) fn handle_wayland_stop(
-    app: &AppHandle,
-    generation: u32,
-    route: StopRoute,
-    pressed: bool,
-) -> bool {
-    handle_stop_input(app, pressed, Some((generation, route)))
-}
-
-fn handle_stop_input(app: &AppHandle, pressed: bool, route: Option<(u32, StopRoute)>) -> bool {
-    let Some(state) = app.try_state::() else {
-        return false;
-    };
-    let mut inner = state.inner.lock().unwrap();
-    if !inner
-        .lease
-        .as_mut()
-        .is_some_and(|lease| lease.accept_stop_input(route, pressed))
-    {
-        return false;
-    }
-    #[cfg(target_os = "linux")]
-    if let Some(generation) = inner.begin_x11_studio_restore_retry(pressed) {
-        drop(inner);
-        spawn_x11_studio_restore(app.clone(), generation, true);
-        return true;
-    }
-    #[cfg(target_os = "linux")]
-    if pressed
-        && inner.lease.as_ref().is_some_and(|lease| {
-            (lease.mode == cap_recording::RecordingMode::Instant || lease.wayland)
-                && lease.phase == Phase::Restoring
-        })
-        && inner
-            .restored
-            .as_ref()
-            .is_some_and(|receipt| receipt.result.is_err())
-    {
-        let generation = inner.lease.as_ref().unwrap().generation;
-        inner.restored = None;
-        drop(inner);
-        spawn_instant_restore(app.clone(), generation, true);
-        return true;
-    }
-    #[cfg(target_os = "linux")]
-    let instant_stop = pressed
-        && crate::recording::linux_instant::current(app).is_some()
-        && inner
-            .lease
-            .as_ref()
-            .is_some_and(|lease| lease.phase != Phase::AwaitingShortcut);
-    let handled = inner.shortcut(pressed);
-    let studio_stop = pressed
-        .then(|| {
-            inner.lease.as_ref().and_then(|lease| {
-                (lease.mode == cap_recording::RecordingMode::Studio
-                    && (lease.phase.can_stop() || lease.phase == Phase::Stopping))
-                    .then(|| {
-                        lease
-                            .recording_dir
-                            .clone()
-                            .map(|dir| (lease.generation, dir))
-                    })
-                    .flatten()
-            })
-        })
-        .flatten();
-    let stop = handled
-        && pressed
-        && inner
-            .lease
-            .as_ref()
-            .is_some_and(|lease| lease.phase.can_stop());
-    #[cfg(target_os = "linux")]
-    let stop = stop || (handled && instant_stop);
-    drop(inner);
-    if handled {
-        notify(app);
-    }
-    if let Some((generation, directory)) = studio_stop {
-        crate::recording::queue_clean_studio_stop(app, generation, directory);
-    } else if stop {
-        let app = app.clone();
-        drop(tauri::async_runtime::spawn(async move {
-            if let Err(error) = crate::recording::stop_recording(app.clone(), app.state()).await {
-                tracing::error!(%error, "Clean capture shortcut could not stop recording");
-            }
-        }));
-    }
-    handled
-}
-
-pub fn reveal_now(window: &WebviewWindow, expected_generation: u32) -> tauri::Result {
-    reveal_now_with_options(window, expected_generation, false, false)
-}
-
-fn reveal_now_with_options(
-    window: &WebviewWindow,
-    expected_generation: u32,
-    focus: bool,
-    unminimize: bool,
-) -> tauri::Result {
-    let app = window.app_handle();
-    #[cfg(target_os = "linux")]
-    if crate::recording::linux_instant::current(app)
-        .is_some_and(|attempt| attempt.has_capture() && !attempt.ui_ready())
-    {
-        return Ok(false);
-    }
-    let Some(state) = app.try_state::() else {
-        #[cfg(target_os = "macos")]
-        if window.label() == CapWindowId::Main.label() {
-            crate::platform::constrain_main_window_to_visible_frame(&window.as_ref().window())
-                .map_err(|error| tauri::Error::Io(std::io::Error::other(error)))?;
-        }
-        window.show()?;
-        return Ok(true);
-    };
-    let inner = state.inner.lock().unwrap();
-    if !inner.may_reveal(expected_generation, window.label()) {
-        #[cfg(target_os = "linux")]
-        let deferred_editor = inner.lease.as_ref().is_some_and(|lease| {
-            lease.wayland
-                && lease.generation == expected_generation
-                && lease.phase == Phase::Stopping
-                && matches!(window.label().parse(), Ok(CapWindowId::Editor { .. }))
-        });
-        drop(inner);
-        #[cfg(target_os = "linux")]
-        if deferred_editor {
-            use gtk::prelude::*;
-            let native = window.gtk_window()?;
-            remember_wayland_window(app, expected_generation, native.upcast_ref(), true);
-        }
-        return Ok(false);
-    }
-    // Mapping runs on the UI thread; a new capture must acknowledge its queued hide
-    // before starting. Do not retain this mutex across synchronous GTK callbacks.
-    drop(inner);
-    #[cfg(target_os = "macos")]
-    if window.label() == CapWindowId::Main.label() {
-        crate::platform::constrain_main_window_to_visible_frame(&window.as_ref().window())
-            .map_err(|error| tauri::Error::Io(std::io::Error::other(error)))?;
-    }
-    set_native_visibility(window, true)
-        .map_err(|error| tauri::Error::Io(std::io::Error::other(error)))?;
-    if unminimize {
-        window.unminimize()?;
-    }
-    if focus {
-        window.set_focus()?;
-    }
-    Ok(true)
-}
-
-pub async fn reveal(window: WebviewWindow, expected_generation: u32) -> Result {
-    reveal_with_options(window, expected_generation, false, false).await
-}
-
-async fn reveal_with_options(
-    window: WebviewWindow,
-    expected_generation: u32,
-    focus: bool,
-    unminimize: bool,
-) -> Result {
-    #[cfg(target_os = "linux")]
-    if window.label() == CapWindowId::Main.label()
-        && let Some(attempt) = crate::recording::linux_instant::current(window.app_handle())
-        && attempt.has_capture()
-        && !attempt.ui_ready()
-    {
-        crate::recording::linux_instant::control(window.app_handle().clone(), attempt, false)
-            .await?;
-    }
-    let (tx, rx) = tokio::sync::oneshot::channel();
-    let handle = window.clone();
-    window
-        .run_on_main_thread(move || {
-            let _ = tx.send(
-                reveal_now_with_options(&handle, expected_generation, focus, unminimize)
-                    .map_err(|e| e.to_string()),
-            );
-        })
-        .map_err(|e| e.to_string())?;
-    tokio::time::timeout(Duration::from_secs(2), rx)
-        .await
-        .map_err(|_| "Timed out revealing recording window".to_string())?
-        .map_err(|_| "Recording window closed before it could be shown".to_string())?
-}
-
-pub async fn guarded_show(
-    window: WebviewWindow,
-    generation: u32,
-    focus: bool,
-    unminimize: bool,
-) -> tauri::Result<()> {
-    reveal_with_options(window, generation, focus, unminimize)
-        .await
-        .map(|_| ())
-        .map_err(|error| tauri::Error::Io(std::io::Error::other(error)))
-}
-
-async fn finish_main_controls(
-    phase: Option,
-    instant_stop: Option,
-    studio_pause: S,
-) -> Result<(), String>
-where
-    I: std::future::Future>,
-    S: std::future::Future>,
-{
-    if phase != Some(Phase::AwaitingShortcut)
-        && let Some(stop) = instant_stop
-    {
-        return stop.await;
-    }
-    match phase {
-        Some(Phase::Recording) => studio_pause.await,
-        None | Some(Phase::AwaitingShortcut | Phase::Paused | Phase::Restoring) => Ok(()),
-        _ => Err("Recording is changing state. Use Ctrl+Shift+F9 to stop.".into()),
-    }
-}
-
-pub async fn show_main_controls(app: &AppHandle) -> Result<(), String> {
-    #[cfg(target_os = "linux")]
-    let instant_stop = crate::recording::linux_instant::current(app)
-        .filter(|attempt| !attempt.ui_ready())
-        .map(|attempt| crate::recording::linux_instant::control(app.clone(), attempt, false));
-    #[cfg(not(target_os = "linux"))]
-    let instant_stop = None::>>;
-    finish_main_controls(phase(app), instant_stop, control(app, false)).await
-}
-
-pub fn control(
-    app: &AppHandle,
-    resume: bool,
-) -> futures::future::BoxFuture<'_, Result<(), String>> {
-    Box::pin(async move {
-        let app_state = app.state::>();
-        let (handle, dir, generation) = {
-            let app_state = app_state.read().await;
-            let Some(crate::recording::InProgressRecording::Studio { handle, common, .. }) =
-                app_state.current_recording()
-            else {
-                return Err("No Studio recording is available".into());
-            };
-            let generation = owner(app, &common.recording_dir).ok_or("Recording was superseded")?;
-            (handle.clone(), common.recording_dir.clone(), generation)
-        };
-        let expected = if resume {
-            Phase::Paused
-        } else {
-            Phase::Recording
-        };
-        let transition = if resume {
-            Phase::Resuming
-        } else {
-            Phase::Pausing
-        };
-        {
-            let state = app.state::();
-            let mut inner = state.inner.lock().unwrap();
-            let lease = inner
-                .lease
-                .as_mut()
-                .filter(|lease| {
-                    lease.generation == generation
-                        && lease.phase == expected
-                        && lease.recording_dir.as_deref() == Some(dir.as_path())
-                })
-                .ok_or("Recording is already changing state. Use Ctrl+Shift+F9 to stop.")?;
-            lease.phase = transition;
-            inner.control_error = None;
-        }
-        notify(app);
-        let state = app.state::();
-        ControlOperation {
-            resume,
-            generation,
-            dir: &dir,
-            hide: hide(app, generation),
-            change: async {
-                if resume {
-                    handle.resume().await.map_err(|error| error.to_string())
-                } else {
-                    handle.pause().await.map_err(|error| error.to_string())
-                }
-            },
-            paused: async {
-                matches!(
-                    tokio::time::timeout(Duration::from_secs(2), handle.is_paused()).await,
-                    Ok(Ok(true))
-                )
-            },
-            restore: restore_paused_main(app, generation, dir.clone()),
-            stop: async {
-                Box::pin(crate::recording::stop_clean_studio_recording(
-                    app.clone(),
-                    handle.clone(),
-                    generation,
-                    dir.clone(),
-                ))
-                .await
-            },
-            notify: || notify(app),
-        }
-        .run(&state.inner)
-        .await?;
-        let event = if resume {
-            crate::recording::RecordingEvent::Resumed
-        } else {
-            crate::recording::RecordingEvent::Paused
-        };
-        let _ = event.emit(app);
-        Ok(())
-    })
-}
-
-#[derive(Debug)]
-enum ControlOutcome {
-    Succeeded,
-    StoppedBeforeResume,
-    HideFailed(String),
-    ActorFailed { error: String, paused: bool },
-}
-
-struct ControlOperation<'a, H, C, P, R, S, N> {
-    resume: bool,
-    generation: u32,
-    dir: &'a std::path::Path,
-    hide: H,
-    change: C,
-    paused: P,
-    restore: R,
-    stop: S,
-    notify: N,
-}
-
-impl ControlOperation<'_, H, C, P, R, S, N>
-where
-    H: std::future::Future>,
-    C: std::future::Future>,
-    P: std::future::Future,
-    R: std::future::Future>,
-    S: std::future::Future>,
-    N: Fn(),
-{
-    async fn run(self, state: &Mutex) -> Result<(), String> {
-        let hide_result = if self.resume { self.hide.await } else { Ok(()) };
-        let outcome = match hide_result {
-            Err(error) => ControlOutcome::HideFailed(error),
-            Ok(()) => {
-                let stop_requested = {
-                    let inner = state.lock().unwrap();
-                    if !inner.control_current(self.generation, self.dir, self.resume) {
-                        return Err("Recording stopped or changed during the operation".into());
-                    }
-                    inner.lease.as_ref().unwrap().stop_requested
-                };
-                if self.resume && stop_requested {
-                    ControlOutcome::StoppedBeforeResume
-                } else {
-                    match self.change.await {
-                        Ok(()) => ControlOutcome::Succeeded,
-                        Err(error) => ControlOutcome::ActorFailed {
-                            error,
-                            // This acknowledgement relies on Studio's transactional Resume teardown.
-                            paused: self.resume && self.paused.await,
-                        },
-                    }
-                }
-            }
-        };
-        let stop_requested = {
-            let mut inner = state.lock().unwrap();
-            if !inner.complete_control(self.generation, self.dir, self.resume, &outcome) {
-                return Err("Recording stopped or changed during the operation".into());
-            }
-            inner.lease.as_ref().unwrap().stop_requested
-        };
-        (self.notify)();
-        if stop_requested {
-            self.stop.await?;
-            return Err("Recording stopped".into());
-        }
-        match outcome {
-            ControlOutcome::Succeeded => Ok(()),
-            ControlOutcome::StoppedBeforeResume => Err("Recording stopped".into()),
-            ControlOutcome::HideFailed(error)
-            | ControlOutcome::ActorFailed {
-                error,
-                paused: true,
-            } => {
-                if let Err(reveal_error) = self.restore.await {
-                    return Err(format!(
-                        "{error}. Could not restore controls: {reveal_error}. Use {STOP_SHORTCUT} to stop."
-                    ));
-                }
-                Err(error)
-            }
-            ControlOutcome::ActorFailed {
-                error,
-                paused: false,
-            } if self.resume => Err(format!(
-                "{error}. Recording pause could not be confirmed. Controls remain hidden; use {STOP_SHORTCUT} to stop."
-            )),
-            ControlOutcome::ActorFailed { error, .. } => Err(error),
-        }
-    }
-}
-
-async fn restore_paused_main(app: &AppHandle, generation: u32, dir: PathBuf) -> Result<(), String> {
-    let main = CapWindowId::Main
-        .get(app)
-        .ok_or("Recording controls window is unavailable")?;
-    let (tx, rx) = tokio::sync::oneshot::channel();
-    let window = main.clone();
-    main.run_on_main_thread(move || {
-        let allowed = window
-            .app_handle()
-            .state::()
-            .inner
-            .lock()
-            .unwrap()
-            .may_restore_paused_main(generation, &dir);
-        let result = if allowed {
-            reveal_now_with_options(&window, generation, true, true)
-                .map_err(|error| error.to_string())
-        } else {
-            Ok(false)
-        };
-        let _ = tx.send(result);
-    })
-    .map_err(|error| error.to_string())?;
-    let revealed = tokio::time::timeout(Duration::from_secs(2), rx)
-        .await
-        .map_err(|_| "Timed out restoring paused controls".to_string())?
-        .map_err(|_| "Paused controls restore was cancelled".to_string())??;
-    if !revealed {
-        return Err("Recording stopped or changed before controls could be restored".into());
-    }
-    Ok(())
-}
-
-pub async fn is_paused(app: &AppHandle) -> Result {
-    let state = app.state::>();
-    let handle = {
-        let state = state.read().await;
-        match state.current_recording() {
-            Some(crate::recording::InProgressRecording::Studio { handle, .. }) => handle.clone(),
-            _ => return Err("No Studio recording is available".into()),
-        }
-    };
-    handle.is_paused().await.map_err(|error| error.to_string())
-}
-
-pub fn begin_restart(app: &AppHandle, dir: &std::path::Path) -> Result, String> {
-    let state = app.state::();
-    let mut inner = state.inner.lock().unwrap();
-    let Some(lease) = inner.lease.as_mut() else {
-        return Ok(None);
-    };
-    if lease.recording_dir.as_deref() != Some(dir)
-        || !matches!(lease.phase, Phase::Recording | Phase::Paused)
-        || lease.stop_requested
-    {
-        return Err("Recording is changing state. Use Ctrl+Shift+F9 to stop.".into());
-    }
-    lease.phase = Phase::Restarting;
-    lease.recording_dir = None;
-    Ok(Some(lease.generation))
-}
-
-#[cfg(target_os = "linux")]
-fn native_id(window: &WebviewWindow) -> Result {
-    use wgpu::rwh::{HasWindowHandle, RawWindowHandle};
-    if cap_recording::screenshot::uses_wayland_portal() {
-        use gtk::prelude::*;
-        return window
-            .gtk_window()
-            .map(|window| window.as_ptr() as u64)
-            .map_err(|error| error.to_string());
-    }
-    match window.window_handle().map_err(|e| e.to_string())?.as_raw() {
-        RawWindowHandle::Xlib(handle) => Ok(handle.window),
-        RawWindowHandle::Xcb(handle) => Ok(u64::from(handle.window.get())),
-        RawWindowHandle::Wayland(_) => {
-            use gtk::prelude::*;
-            let gtk = window.gtk_window().map_err(|error| error.to_string())?;
-            Ok(gtk.as_ptr() as u64)
-        }
-        _ => Err("Clean capture requires an X11 or Wayland window".into()),
-    }
-}
-
-#[cfg(not(target_os = "linux"))]
-fn native_id(_window: &WebviewWindow) -> Result {
-    Err("Clean Studio capture is only available on X11".into())
-}
-
-fn x11_environment(display: bool, wayland: bool, session: Option<&str>) -> bool {
-    display && !wayland && session.is_some_and(|session| session.eq_ignore_ascii_case("x11"))
-}
-
-pub(crate) async fn wait_for_shortcut(state: &State, generation: u32) -> Result<(), String> {
-    loop {
-        let notified = state.changed.notified();
-        tokio::pin!(notified);
-        notified.as_mut().enable();
-        {
-            let inner = state.inner.lock().unwrap();
-            let lease = inner
-                .lease
-                .as_ref()
-                .filter(|lease| lease.generation == generation)
-                .ok_or("Recording cancelled")?;
-            if lease.stop_requested {
-                return Err(
-                    if lease.wayland && lease.lost_stop_routes.iter().any(|lost| *lost) {
-                        lease.stop_error.clone().unwrap_or_else(|| {
-                            "The recording Stop control became unavailable".into()
-                        })
-                    } else {
-                        "Recording cancelled".into()
-                    },
-                );
-            }
-            if lease.phase == Phase::Starting {
-                return Ok(());
-            }
-        }
-        notified.await;
-    }
-}
-
-#[cfg(target_os = "linux")]
-pub(crate) async fn await_instant_shortcut(
-    state: &State,
-    generation: u32,
-    attempt: &crate::recording::linux_instant::Attempt,
-) -> Result<(), String> {
-    attempt
-        .while_active(wait_for_shortcut(state, generation))
-        .await
-}
-
-#[cfg(all(test, target_os = "linux"))]
-pub(crate) fn instant_preflight_fixture(generation: u32) -> State {
-    State {
-        instant: Mutex::new(None),
-        portal_stop: tokio::sync::Mutex::new(None),
-        inner: Mutex::new(Inner {
-            generation,
-            lease: Some(Lease {
-                mode: cap_recording::RecordingMode::Instant,
-                generation,
-                phase: Phase::AwaitingShortcut,
-                pressed: false,
-                stop_requested: false,
-                registered_shortcut: true,
-                wayland: false,
-                stop_route: None,
-                stop_description: None,
-                stop_error: None,
-                lost_stop_routes: [false; 2],
-                recording_dir: None,
-                windows: Vec::new(),
-            }),
-            ..Inner::default()
-        }),
-        changed: Notify::new(),
-    }
-}
-
-#[cfg(all(test, target_os = "linux"))]
-pub(crate) fn deliver_preflight_shortcut(state: &State) {
-    let mut inner = state.inner.lock().unwrap();
-    assert!(inner.shortcut(true));
-    assert!(inner.shortcut(false));
-    drop(inner);
-    state.changed.notify_waiters();
-}
-
-fn capture_environment_is_x11(
-    mode: cap_recording::RecordingMode,
-    strict_x11: bool,
-    uses_wayland_portal: bool,
-) -> bool {
-    if mode == cap_recording::RecordingMode::Instant {
-        !uses_wayland_portal
-    } else {
-        strict_x11
-    }
-}
-
-fn validate_capture_visibility(
-    mode: cap_recording::RecordingMode,
-    target: &cap_recording::screen_capture::ScreenCaptureTarget,
-    camera_requested: bool,
-    uses_wayland_portal: bool,
-    supported: bool,
-) -> Result {
-    use cap_recording::{RecordingMode, screen_capture::ScreenCaptureTarget};
-    let needs_visibility = match target {
-        ScreenCaptureTarget::Display { .. } | ScreenCaptureTarget::Area { .. } => {
-            matches!(mode, RecordingMode::Studio | RecordingMode::Instant)
-        }
-        ScreenCaptureTarget::Window { .. } => {
-            mode == RecordingMode::Instant && camera_requested && !uses_wayland_portal
-        }
-        ScreenCaptureTarget::CameraOnly => false,
-    };
-    if !needs_visibility {
-        return Ok(false);
-    }
-    if !supported {
-        return Err("This display backend cannot acknowledge hidden recording windows. Recording has not started and selected inputs are unchanged.".into());
-    }
-    Ok(true)
-}
-
-pub async fn prepare(
-    app: &AppHandle,
-    inputs: &crate::recording::StartRecordingInputs,
-    restart: Option,
-) -> Result, String> {
-    if !cfg!(target_os = "linux") {
-        return Ok(None);
-    }
-    if let Some(generation) = restart {
-        if phase(app) != Some(Phase::Restarting) || stop_requested(app, generation) {
-            return Err("Recording restart was cancelled".into());
-        }
-        set_phase(app, generation, Phase::Starting);
-        return Ok(Some(generation));
-    }
-    if phase(app).is_some() {
-        return Err("Finish or cancel the current recording before starting another".into());
-    }
-    #[cfg(target_os = "linux")]
-    let uses_wayland_portal = cap_recording::screenshot::uses_wayland_portal();
-    #[cfg(not(target_os = "linux"))]
-    let uses_wayland_portal = false;
-    if !validate_capture_visibility(
-        inputs.mode,
-        &inputs.capture_target,
-        app.state::()
-            .snapshot()
-            .camera
-            .value
-            .is_some(),
-        uses_wayland_portal,
-        capture_environment_is_x11(
-            inputs.mode,
-            x11_environment(
-                std::env::var_os("DISPLAY").is_some(),
-                std::env::var_os("WAYLAND_DISPLAY").is_some(),
-                std::env::var("XDG_SESSION_TYPE").ok().as_deref(),
-            ),
-            uses_wayland_portal,
-        ) || uses_wayland_portal,
-    )? {
-        return Ok(None);
-    }
-    #[cfg(target_os = "linux")]
-    let instant_attempt = if inputs.mode == cap_recording::RecordingMode::Instant {
-        let attempt = crate::recording::linux_instant::current(app)
-            .ok_or("Instant preflight owner was lost")?;
-        attempt.checked(Ok(()))?;
-        Some(attempt)
-    } else {
-        None
-    };
-    let main = CapWindowId::Main
-        .get(app)
-        .ok_or("Open Cap before starting this recording")?;
-
-    let app_state = app.state::>();
-    let mut app_state = app_state.write().await;
-    if !matches!(app_state.recording_state, crate::RecordingState::None) {
-        return Err("Recording already in progress".into());
-    }
-    let state = app.state::();
-    let generation = {
-        let mut inner = state.inner.lock().unwrap();
-        if inner.lease.is_some() {
-            return Err("Recording preflight already in progress".into());
-        }
-        inner.generation = inner.generation.wrapping_add(1);
-        inner.control_error = None;
-        let generation = inner.generation;
-        inner.restored = None;
-        inner.lease = Some(Lease {
-            mode: inputs.mode,
-            generation,
-            phase: Phase::AwaitingShortcut,
-            pressed: false,
-            stop_requested: false,
-            registered_shortcut: false,
-            wayland: uses_wayland_portal,
-            stop_route: None,
-            stop_description: None,
-            stop_error: None,
-            lost_stop_routes: [false; 2],
-            recording_dir: None,
-            windows: Vec::new(),
-        });
-        generation
-    };
-    app_state.set_pending_recording(inputs.mode, inputs.capture_target.clone())?;
-    drop(app_state);
-    let result = async {
-        let saved = save_windows(app, generation).await?;
-        state.inner.lock().unwrap().lease.as_mut().unwrap().windows = saved;
-        #[cfg(target_os = "linux")]
-        if uses_wayland_portal {
-            crate::hotkeys::reserve_wayland_stop(app, generation).await?;
-        } else {
-            let registered = crate::hotkeys::reserve_clean_capture_stop(app)?;
-            state
-                .inner
-                .lock()
-                .unwrap()
-                .lease
-                .as_mut()
-                .unwrap()
-                .registered_shortcut = registered;
-        }
-        crate::target_select_overlay::close_target_select_overlay_windows(app);
-        if stop_requested(app, generation) {
-            return Err("Recording cancelled".into());
-        }
-        guarded_show(main, generation, true, true)
-            .await
-            .map_err(|error| error.to_string())?;
-        notify(app);
-        #[cfg(target_os = "linux")]
-        if let Some(attempt) = &instant_attempt {
-            await_instant_shortcut(&state, generation, attempt).await?;
-        } else {
-            wait_for_shortcut(&state, generation).await?;
-        }
-        #[cfg(not(target_os = "linux"))]
-        wait_for_shortcut(&state, generation).await?;
-        #[cfg(target_os = "linux")]
-        if uses_wayland_portal {
-            crate::tray::set_clean_stop_mode(app, generation, true).await?;
-        }
-        if inputs.mode == cap_recording::RecordingMode::Studio {
-            hide(app, generation).await?;
-        }
-        Ok(Some(generation))
-    }
-    .await;
-    if result.is_err() {
-        app.state::>()
-            .write()
-            .await
-            .clear_pending_recording();
-        release(app, generation, false);
-    }
-    result
-}
-
-fn hide_windows(app: &AppHandle) -> Result<(), String> {
-    #[cfg(target_os = "linux")]
-    if let Some(generation) = wayland_generation(app) {
-        return hide_wayland_windows(app, generation);
-    }
-    for (label, window) in app.webview_windows() {
-        if matches!(
-            label.parse::(),
-            Ok(CapWindowId::Main
-                | CapWindowId::Camera
-                | CapWindowId::RecordingControls
-                | CapWindowId::TargetSelectOverlay { .. })
-        ) {
-            native_id(&window)?;
-            set_native_visibility(&window, false)?;
-            if window.is_visible().map_err(|e| e.to_string())? {
-                return Err("Cap could not hide its recording windows safely".into());
-            }
-        }
-    }
-    Ok(())
-}
-
-pub async fn hide(app: &AppHandle, generation: u32) -> Result<(), String> {
-    let (tx, rx) = tokio::sync::oneshot::channel();
-    let handle = app.clone();
-    app.run_on_main_thread(move || {
-        let result = (|| {
-            if !is_current(&handle, generation) {
-                return Err("Recording preflight was superseded".to_string());
-            }
-            hide_windows(&handle)?;
-            Ok(())
-        })();
-        let _ = tx.send(result);
-    })
-    .map_err(|e| e.to_string())?;
-    tokio::time::timeout(Duration::from_secs(2), rx)
-        .await
-        .map_err(|_| "Timed out hiding Cap windows".to_string())?
-        .map_err(|_| "Cap window hide task was cancelled".to_string())??;
-    #[cfg(target_os = "linux")]
-    if wayland_generation(app) == Some(generation) {
-        wayland_fence(app, generation, true).await?;
-    }
-    tokio::time::sleep(Duration::from_millis(150)).await;
-    if stop_requested(app, generation) {
-        return Err("Recording cancelled".into());
-    }
-    Ok(())
-}
-
-#[cfg(target_os = "linux")]
-pub(crate) struct InstantSeal {
-    pub generation: u32,
-    pub attempt: crate::recording::linux_instant::Attempt,
-    pub requested: crate::RequestedInputs,
-    pub target: cap_recording::screen_capture::ScreenCaptureTarget,
-    pub capture: crate::linux_instant_camera::PhysicalRect,
-    pub presentation: Option,
-}
-
-#[cfg(target_os = "linux")]
-fn validate_instant_seal(app: &AppHandle, seal: &InstantSeal) -> Result<(), String> {
-    let requested = app.state::();
-    requested.ready_snapshot()?;
-    if !is_current(app, seal.generation)
-        || phase(app) != Some(Phase::Starting)
-        || stop_requested(app, seal.generation)
-        || !requested.is_current(&seal.requested)
-        || crate::recording::linux_instant::current(app)
-            .is_none_or(|attempt| !attempt.same(&seal.attempt))
-    {
-        return Err("Instant preparation was cancelled or changed".into());
-    }
-    seal.attempt.checked(Ok(()))?;
-    if crate::recording::linux_instant::capture_rect(&seal.target)? != seal.capture {
-        return Err("Capture bounds changed while preparing Instant recording".into());
-    }
-    if let Some(presentation) = &seal.presentation {
-        let window = CapWindowId::Camera
-            .get(app)
-            .ok_or("Camera window disappeared")?;
-        presentation.validate_before_hide(&window)?;
-    }
-    Ok(())
-}
-
-#[cfg(target_os = "linux")]
-async fn instant_ui_seal(
-    app: &AppHandle,
-    seal: InstantSeal,
-    hide: bool,
-) -> Result {
-    let (tx, rx) = tokio::sync::oneshot::channel();
-    let handle = app.clone();
-    let attempt = seal.attempt.clone();
-    app.run_on_main_thread(move || {
-        let result = (|| {
-            validate_instant_seal(&handle, &seal)?;
-            if hide {
-                hide_windows(&handle)?;
-            }
-            Ok(seal)
-        })();
-        let _ = tx.send(result);
-    })
-    .map_err(|error| error.to_string())?;
-    let result = tokio::time::timeout(Duration::from_secs(2), rx)
-        .await
-        .map_err(|_| "Instant camera hide acknowledgement timed out".to_string())
-        .and_then(|result| {
-            result.map_err(|_| "Instant camera hide acknowledgement was lost".to_string())
-        })
-        .and_then(|result| result);
-    if result.is_err() {
-        attempt.cancel();
-    }
-    result
-}
-
-#[cfg(target_os = "linux")]
-async fn seal_then_settle(hide: H, settle: S, validate: V) -> Result
-where
-    H: std::future::Future>,
-    S: std::future::Future>,
-    V: FnOnce(T) -> F,
-    F: std::future::Future>,
-{
-    let sealed = hide.await?;
-    settle.await?;
-    validate(sealed).await
-}
-
-#[cfg(target_os = "linux")]
-pub(crate) async fn seal_instant(
-    app: &AppHandle,
-    seal: InstantSeal,
-) -> Result {
-    let attempt = seal.attempt.clone();
-    let generation = seal.generation;
-    seal_then_settle(
-        instant_ui_seal(app, seal, true),
-        attempt.while_active(async {
-            #[cfg(target_os = "linux")]
-            if wayland_generation(app) == Some(generation) {
-                wayland_fence(app, generation, true).await?;
-            }
-            tokio::time::sleep(Duration::from_millis(150)).await;
-            Ok(())
-        }),
-        |seal| instant_ui_seal(app, seal, false),
-    )
-    .await
-}
-
-#[cfg(target_os = "linux")]
-async fn restore_instant_windows(
-    app: &AppHandle,
-    generation: u32,
-    main_only: bool,
-) -> Result<(), String> {
-    let (tx, rx) = tokio::sync::oneshot::channel();
-    let handle = app.clone();
-    app.run_on_main_thread(move || {
-        let result = (|| {
-            if crate::recording::linux_instant::current(&handle)
-                .is_some_and(|attempt| attempt.has_capture() && !attempt.ui_ready())
-            {
-                return Err("Instant capture cleanup is unconfirmed".to_string());
-            }
-            if wayland_generation(&handle) == Some(generation) {
-                return restore_wayland_windows(&handle, generation, main_only);
-            }
-            let windows = {
-                let state = handle.state::();
-                let inner = state.inner.lock().unwrap();
-                inner
-                    .lease
-                    .as_ref()
-                    .filter(|lease| {
-                        lease.generation == generation && lease.phase == Phase::Restoring
-                    })
-                    .ok_or("Instant restoration was superseded")?
-                    .windows
-                    .clone()
-            };
-            let requested = handle
-                .state::()
-                .ready_snapshot();
-            if !main_only {
-                requested.as_ref().map_err(Clone::clone)?;
-            }
-            for saved in windows {
-                let main = saved.label == CapWindowId::Main.label();
-                if main != main_only {
-                    continue;
-                }
-                if !main
-                    && requested
-                        .as_ref()
-                        .is_ok_and(|snapshot| snapshot.camera.value.is_none())
-                {
-                    continue;
-                }
-                let window = match handle.get_webview_window(&saved.label) {
-                    Some(window) => window,
-                    None if wayland_generation(&handle) == Some(generation) && !saved.visible => {
-                        continue;
-                    }
-                    None => return Err("Recording restoration window disappeared".into()),
-                };
-                let visible = saved
-                    .visibility_for(native_id(&window)?)
-                    .ok_or("Instant restoration window identity changed")?;
-                if !main
-                    && !handle
-                        .state::()
-                        .is_current(requested.as_ref().map_err(Clone::clone)?)
-                {
-                    return Err("Requested inputs changed during Instant restoration".into());
-                }
-                set_native_visibility(&window, visible)?;
-                if window.is_visible().map_err(|error| error.to_string())? != visible {
-                    return Err("Instant window restoration was not acknowledged".into());
-                }
-            }
-            Ok(())
-        })();
-        let _ = tx.send(result);
-    })
-    .map_err(|error| error.to_string())?;
-    tokio::time::timeout(Duration::from_secs(2), rx)
-        .await
-        .map_err(|_| "Instant restore acknowledgement timed out".to_string())?
-        .map_err(|_| "Instant restore acknowledgement was lost".to_string())?
-}
-
-#[cfg(target_os = "linux")]
-async fn restore_instant_sequence(
-    main: M,
-    inputs: I,
-    camera: C,
-) -> Result<(), String>
-where
-    M: std::future::Future>,
-    I: FnOnce() -> IF,
-    IF: std::future::Future,
-    C: FnOnce() -> CF,
-    CF: std::future::Future>,
-{
-    main.await?;
-    inputs().await;
-    camera().await
-}
-
-#[cfg(target_os = "linux")]
-fn finish_x11_studio_restoration(
-    inner: &Mutex,
-    generation: u32,
-    windows: Result<(), String>,
-    release_shortcut: impl FnOnce() -> Result<(), String>,
-) -> bool {
-    let cleanup = {
-        let mut inner = inner.lock().unwrap();
-        inner.reserve_x11_studio_cleanup(generation, windows)
-    };
-    let Some(cleanup) = cleanup else {
-        return false;
-    };
-    let result = if cleanup.registered_shortcut {
-        release_shortcut()
-    } else {
-        Ok(())
-    };
-    inner
-        .lock()
-        .unwrap()
-        .complete_x11_studio_restoration(cleanup, result)
-}
-
-#[cfg(target_os = "linux")]
-fn spawn_x11_studio_restore(app: AppHandle, generation: u32, restore_inputs: bool) {
-    drop(tauri::async_runtime::spawn(async move {
-        let result = restore_instant_sequence(
-            restore_instant_windows(&app, generation, true),
-            || async {
-                if restore_inputs {
-                    crate::restore_requested_inputs(&app).await;
-                }
-            },
-            || restore_instant_windows(&app, generation, false),
-        )
-        .await;
-        let handle = app.clone();
-        let scheduled = app.run_on_main_thread(move || {
-            use tauri_plugin_global_shortcut::GlobalShortcutExt;
-
-            {
-                let state = handle.state::();
-                finish_x11_studio_restoration(&state.inner, generation, result, || {
-                    handle
-                        .global_shortcut()
-                        .unregister(STOP_SHORTCUT)
-                        .map_err(|error| {
-                            format!("Recording Stop shortcut cleanup is unconfirmed: {error}")
-                        })
-                });
-            }
-            notify(&handle);
-        });
-        if let Err(error) = scheduled {
-            {
-                let state = app.state::();
-                finish_x11_studio_restoration(
-                    &state.inner,
-                    generation,
-                    Err(format!(
-                        "Recording restoration completion could not be scheduled: {error}"
-                    )),
-                    || Ok(()),
-                );
-            }
-            notify(&app);
-        }
-    }));
-}
-
-#[cfg(target_os = "linux")]
-fn spawn_instant_restore(app: AppHandle, generation: u32, restore_inputs: bool) {
-    drop(tauri::async_runtime::spawn(async move {
-        let result = restore_instant_sequence(
-            restore_instant_windows(&app, generation, true),
-            || async {
-                if restore_inputs {
-                    crate::restore_requested_inputs(&app).await;
-                }
-            },
-            || restore_instant_windows(&app, generation, false),
-        )
-        .await;
-        let result = if wayland_generation(&app) == Some(generation) {
-            match result {
-                Ok(()) => {
-                    async {
-                        wayland_fence(&app, generation, false).await?;
-                        crate::tray::set_clean_stop_mode(&app, generation, false).await?;
-                        crate::hotkeys::release_wayland_stop(&app, generation).await
-                    }
-                    .await
-                }
-                Err(error) => Err(error),
-            }
-        } else {
-            result
-        };
-        let owned = {
-            let state = app.state::();
-            let mut inner = state.inner.lock().unwrap();
-            inner.complete_instant_restoration(generation, result)
-        };
-        if let Some(owned) = owned {
-            crate::hotkeys::release_clean_capture_stop(&app, owned);
-            let _ = app.run_on_main_thread(move || {
-                WAYLAND_WINDOWS.with_borrow_mut(|windows| {
-                    windows.remove(&generation);
-                });
-                WAYLAND_CAPTURE_WINDOWS.with_borrow_mut(|windows| {
-                    windows.remove(&generation);
-                });
-            });
-        }
-        notify(&app);
-    }));
-}
-
-#[cfg(target_os = "linux")]
-pub(crate) async fn wait_restored(app: &AppHandle, generation: u32) -> Result<(), String> {
-    let state = app.state::();
-    wait_for_restoration(&state, generation).await
-}
-
-#[cfg(target_os = "linux")]
-async fn wait_for_restoration(state: &State, generation: u32) -> Result<(), String> {
-    loop {
-        let changed = state.changed.notified();
-        tokio::pin!(changed);
-        changed.as_mut().enable();
-        {
-            let inner = state.inner.lock().unwrap();
-            if let Some(receipt) = &inner.restored
-                && receipt.generation == generation
-            {
-                return receipt.restart_result();
-            }
-            if inner
-                .lease
-                .as_ref()
-                .is_none_or(|lease| lease.generation != generation)
-            {
-                return Err("Instant restoration ownership changed without acknowledgement".into());
-            }
-        }
-        changed.await;
-    }
-}
-
-pub fn release(app: &AppHandle, generation: u32, editor_took_foreground: bool) {
-    release_inner(app, generation, editor_took_foreground, false);
-}
-
-pub fn release_after_recording(app: &AppHandle, generation: u32, editor_took_foreground: bool) {
-    release_inner(app, generation, editor_took_foreground, true);
-}
-
-async fn restore_pass_acknowledged(
-    scheduled: bool,
-    acknowledgement: tokio::sync::oneshot::Receiver>,
-) -> bool {
-    scheduled && matches!(acknowledgement.await, Ok(Ok(())))
-}
-
-fn restore_saved_window(app: &AppHandle, saved: &SavedWindow) -> Result<(), String> {
-    let window = app.get_webview_window(&saved.label).ok_or_else(|| {
-        format!(
-            "Recording window {} disappeared before restoration",
-            saved.label
-        )
-    })?;
-    let visible = saved.visibility_for(native_id(&window)?).ok_or_else(|| {
-        format!(
-            "Recording window {} was replaced before restoration",
-            saved.label
-        )
-    })?;
-    set_native_visibility(&window, visible)?;
-    if window.is_visible().map_err(|error| error.to_string())? != visible {
-        return Err(format!(
-            "Recording window {} restoration was not acknowledged",
-            saved.label
-        ));
-    }
-    Ok(())
-}
-
-fn release_inner(
-    app: &AppHandle,
-    generation: u32,
-    editor_took_foreground: bool,
-    restore_inputs: bool,
-) {
-    #[cfg(target_os = "linux")]
-    if crate::recording::linux_instant::current(app)
-        .is_some_and(|attempt| attempt.has_capture() && !attempt.ui_ready())
-    {
-        return;
-    }
-    {
-        let state = app.state::();
-        let mut inner = state.inner.lock().unwrap();
-        let Some(lease) = inner
-            .lease
-            .as_mut()
-            .filter(|lease| lease.generation == generation && lease.phase != Phase::Restoring)
-        else {
-            return;
-        };
-        if editor_took_foreground
-            && (lease.wayland || lease.mode == cap_recording::RecordingMode::Studio)
-        {
-            for window in &mut lease.windows {
-                if window.label == CapWindowId::Main.label() {
-                    window.visible = false;
-                }
-            }
-        }
-        lease.phase = Phase::Restoring;
-    }
-    notify(app);
-    #[cfg(target_os = "linux")]
-    if app
-        .state::()
-        .inner
-        .lock()
-        .unwrap()
-        .lease
-        .as_ref()
-        .is_some_and(|lease| {
-            lease.generation == generation
-                && (lease.mode == cap_recording::RecordingMode::Instant || lease.wayland)
-        })
-    {
-        spawn_instant_restore(app.clone(), generation, restore_inputs);
-        return;
-    }
-    #[cfg(target_os = "linux")]
-    if app
-        .state::()
-        .inner
-        .lock()
-        .unwrap()
-        .lease
-        .as_ref()
-        .is_some_and(|lease| {
-            lease.generation == generation
-                && lease.mode == cap_recording::RecordingMode::Studio
-                && !lease.wayland
-        })
-    {
-        spawn_x11_studio_restore(app.clone(), generation, restore_inputs);
-        return;
-    }
-    let app = app.clone();
-    drop(tauri::async_runtime::spawn(async move {
-        let (tx, rx) = tokio::sync::oneshot::channel::>();
-        let restoration_error = Arc::new(Mutex::new(None::));
-        let first_error = restoration_error.clone();
-        let handle = app.clone();
-        let scheduled = app.run_on_main_thread(move || {
-            #[cfg(target_os = "linux")]
-            if crate::recording::linux_instant::current(&handle)
-                .is_some_and(|attempt| attempt.has_capture() && !attempt.ui_ready())
-            {
-                let _ = tx.send(Err("Instant cleanup is unconfirmed".to_string()));
-                return;
-            }
-            let saved = {
-                let state = handle.state::();
-                let mut inner = state.inner.lock().unwrap();
-                inner
-                    .lease
-                    .as_mut()
-                    .filter(|lease| lease.generation == generation)
-                    .map(|lease| {
-                        let owned = std::mem::take(&mut lease.registered_shortcut);
-                        (
-                            lease
-                                .windows
-                                .iter()
-                                .find(|saved| saved.label == CapWindowId::Main.label())
-                                .cloned(),
-                            owned,
-                        )
-                    })
-            };
-            if let Some((saved, owned)) = saved {
-                crate::hotkeys::release_clean_capture_stop(&handle, owned);
-                if !editor_took_foreground && let Some(saved) = saved {
-                    let result = restore_saved_window(&handle, &saved);
-                    if let Err(error) = result {
-                        *first_error.lock().unwrap() = Some(error.to_string());
-                        tracing::warn!(%error, "Could not restore Main after recording");
-                    }
-                }
-            }
-            let _ = tx.send(Ok(()));
-        });
-        if !restore_pass_acknowledged(scheduled.is_ok(), rx).await {
-            return;
-        }
-        if restore_inputs {
-            crate::restore_requested_inputs(&app).await;
-        }
-        let requested = app.state::().snapshot();
-        let handle = app.clone();
-        let _ = app.run_on_main_thread(move || {
-            #[cfg(target_os = "linux")]
-            if crate::recording::linux_instant::current(&handle)
-                .is_some_and(|attempt| attempt.has_capture() && !attempt.ui_ready())
-            {
-                return;
-            }
-            let state = handle.state::();
-            let windows = {
-                let inner = state.inner.lock().unwrap();
-                let Some(lease) = inner.lease.as_ref().filter(|lease| {
-                    lease.generation == generation && lease.phase == Phase::Restoring
-                }) else {
-                    return;
-                };
-                lease.windows.clone()
-            };
-            for saved in windows {
-                if saved.label == CapWindowId::Main.label() {
-                    continue;
-                }
-                if matches!(saved.label.parse::(), Ok(CapWindowId::Camera))
-                    && (requested.camera.value.is_none()
-                        || requested.camera.pending
-                        || requested.camera.error.is_some()
-                        || !handle
-                            .state::()
-                            .is_current(&requested))
-                {
-                    continue;
-                }
-                if let Err(error) = restore_saved_window(&handle, &saved) {
-                    restoration_error
-                        .lock()
-                        .unwrap()
-                        .get_or_insert_with(|| error.to_string());
-                    tracing::warn!(%error, "Could not restore clean capture window");
-                }
-            }
-            {
-                let mut inner = state.inner.lock().unwrap();
-                let result = restoration_error.lock().unwrap().take().map_or(Ok(()), Err);
-                if !inner.record_stop_restoration(generation, result) {
-                    return;
-                }
-                inner.lease = None;
-                inner.generation = inner.generation.wrapping_add(1);
-            }
-            notify(&handle);
-        });
-    }));
-}
-
-#[tauri::command]
-#[specta::specta]
-pub fn get_clean_capture_state(app: AppHandle) -> Snapshot {
-    app.state::().inner.lock().unwrap().snapshot()
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn reveal_capture_window(
-    window: WebviewWindow,
-    generation: u32,
-    target_overlay: Option,
-) -> Result {
-    if let Some(label) = target_overlay {
-        if window.label() != CapWindowId::Main.label()
-            || !matches!(
-                label.parse::(),
-                Ok(CapWindowId::TargetSelectOverlay { .. })
-            )
-        {
-            return Err("Only Main can restore a target selection overlay".into());
-        }
-        let target = window
-            .app_handle()
-            .get_webview_window(&label)
-            .ok_or("Target selection overlay no longer exists")?;
-        return reveal(target, generation).await;
-    }
-    if !matches!(
-        window.label().parse::(),
-        Ok(CapWindowId::Main | CapWindowId::Camera | CapWindowId::RecordingControls)
-    ) {
-        return Err("Only Cap recording windows can use this command".into());
-    }
-    if matches!(
-        window.label().parse::(),
-        Ok(CapWindowId::RecordingControls)
-    ) && window
-        .app_handle()
-        .state::>()
-        .read()
-        .await
-        .current_recording()
-        .is_none()
-    {
-        return Ok(false);
-    }
-    let main = matches!(window.label().parse::(), Ok(CapWindowId::Main));
-    reveal_with_options(window, generation, main, main).await
-}
-
-#[cfg(all(test, target_os = "linux"))]
-mod instant_activation_tests {
-    use super::*;
-    use std::sync::{
-        Arc,
-        atomic::{AtomicUsize, Ordering},
-    };
-
-    #[tokio::test]
-    async fn instant_seal_waits_for_hide_ack_then_settle_then_revalidates() {
-        let (hide_tx, hide_rx) = tokio::sync::oneshot::channel();
-        let (settle_tx, settle_rx) = tokio::sync::oneshot::channel();
-        let (settling_tx, settling_rx) = tokio::sync::oneshot::channel();
-        let stage = Arc::new(AtomicUsize::new(0));
-        let observed = stage.clone();
-        let task = tokio::spawn(async move {
-            let validated = observed.clone();
-            seal_then_settle(
-                async { hide_rx.await.map_err(|_| "hide ack lost".to_string()) },
-                async {
-                    observed.store(1, Ordering::SeqCst);
-                    settling_tx.send(()).unwrap();
-                    settle_rx.await.map_err(|_| "settle cancelled".to_string())
-                },
-                |owner| async move {
-                    validated.store(2, Ordering::SeqCst);
-                    Ok(owner)
-                },
-            )
-            .await
-        });
-        tokio::task::yield_now().await;
-        assert_eq!(stage.load(Ordering::SeqCst), 0);
-        assert!(!task.is_finished());
-        hide_tx.send(7).unwrap();
-        settling_rx.await.unwrap();
-        assert_eq!(stage.load(Ordering::SeqCst), 1);
-        assert!(!task.is_finished());
-        settle_tx.send(()).unwrap();
-        assert_eq!(task.await.unwrap().unwrap(), 7);
-        assert_eq!(stage.load(Ordering::SeqCst), 2);
-    }
-
-    #[tokio::test]
-    async fn instant_lost_hide_ack_never_settles_or_builds() {
-        let (tx, rx) = tokio::sync::oneshot::channel::();
-        drop(tx);
-        let result = seal_then_settle(
-            async { rx.await.map_err(|_| "hide ack lost".to_string()) },
-            async { panic!("settle cannot begin before hide acknowledgement") },
-            |_| async { panic!("build validation cannot begin") },
-        )
-        .await;
-        assert_eq!(result.unwrap_err(), "hide ack lost");
-    }
-
-    #[tokio::test]
-    async fn instant_cancelled_settle_does_not_revalidate_or_build() {
-        let result = seal_then_settle(
-            async { Ok(7) },
-            async { Err("cancelled".into()) },
-            |_| async { panic!("cancelled preparation cannot build") },
-        )
-        .await;
-        assert_eq!(result.unwrap_err(), "cancelled");
-    }
-
-    #[tokio::test]
-    async fn instant_changed_effect_or_geometry_after_settle_rejects_owner() {
-        let result = seal_then_settle(async { Ok(7) }, async { Ok(()) }, |owner| async move {
-            assert_eq!(owner, 7);
-            Err("prepared presentation changed".into())
-        })
-        .await;
-        assert_eq!(result.unwrap_err(), "prepared presentation changed");
-    }
-
-    #[tokio::test]
-    async fn instant_restore_waits_for_main_and_camera_acknowledgements() {
-        let (main_tx, main_rx) = tokio::sync::oneshot::channel();
-        let (camera_tx, camera_rx) = tokio::sync::oneshot::channel();
-        let (inputs_tx, inputs_rx) = tokio::sync::oneshot::channel();
-        let stage = Arc::new(AtomicUsize::new(0));
-        let observed = stage.clone();
-        let task = tokio::spawn(async move {
-            restore_instant_sequence(
-                async { main_rx.await.map_err(|_| "main ack lost".to_string()) },
-                || async {
-                    observed.store(1, Ordering::SeqCst);
-                    inputs_tx.send(()).unwrap();
-                },
-                || async { camera_rx.await.map_err(|_| "camera ack lost".to_string()) },
-            )
-            .await
-        });
-        tokio::task::yield_now().await;
-        assert_eq!(stage.load(Ordering::SeqCst), 0);
-        main_tx.send(()).unwrap();
-        inputs_rx.await.unwrap();
-        assert_eq!(stage.load(Ordering::SeqCst), 1);
-        assert!(!task.is_finished());
-        camera_tx.send(()).unwrap();
-        task.await.unwrap().unwrap();
-    }
-
-    #[tokio::test]
-    async fn instant_restore_rejected_or_lost_main_ack_never_restores_inputs() {
-        for rejected in [true, false] {
-            let (tx, rx) = tokio::sync::oneshot::channel::>();
-            if rejected {
-                tx.send(Err("unsafe cleanup".into())).unwrap();
-            } else {
-                drop(tx);
-            }
-            let result = restore_instant_sequence(
-                async { rx.await.map_err(|_| "main ack lost".to_string())? },
-                || async { panic!("inputs must remain untouched") },
-                || async { panic!("camera must remain hidden") },
-            )
-            .await;
-            assert!(result.is_err());
-        }
-    }
-
-    #[tokio::test]
-    async fn instant_open_cap_waits_for_stop_ack_and_never_polls_studio_pause() {
-        let (tx, rx) = tokio::sync::oneshot::channel();
-        let task = tokio::spawn(finish_main_controls(
-            Some(Phase::Recording),
-            Some(async { rx.await.map_err(|_| "stop ack lost".to_string()) }),
-            async { panic!("Instant OpenCap must not pause") },
-        ));
-        tokio::task::yield_now().await;
-        assert!(!task.is_finished());
-        tx.send(()).unwrap();
-        task.await.unwrap().unwrap();
-    }
-
-    #[tokio::test]
-    async fn instant_open_cap_preserves_stop_failure_without_pause_or_reveal_permission() {
-        let result = finish_main_controls(
-            Some(Phase::Starting),
-            Some(async { Err("capture cleanup unconfirmed".into()) }),
-            async { panic!("Instant OpenCap must not pause") },
-        )
-        .await;
-        assert_eq!(result.unwrap_err(), "capture cleanup unconfirmed");
-    }
-
-    #[tokio::test]
-    async fn studio_open_cap_waits_for_pause_ack_before_allowing_reveal() {
-        let (started_tx, started_rx) = tokio::sync::oneshot::channel();
-        let (paused_tx, paused_rx) = tokio::sync::oneshot::channel();
-        let reveals = Arc::new(AtomicUsize::new(0));
-        let observed = reveals.clone();
-        let task = tokio::spawn(async move {
-            finish_main_controls(
-                Some(Phase::Recording),
-                None::>>,
-                async {
-                    started_tx.send(()).unwrap();
-                    paused_rx.await.map_err(|_| "pause ack lost".to_string())
-                },
-            )
-            .await?;
-            observed.fetch_add(1, Ordering::SeqCst);
-            Ok::<(), String>(())
-        });
-        started_rx.await.unwrap();
-        assert!(!task.is_finished());
-        assert_eq!(reveals.load(Ordering::SeqCst), 0);
-        paused_tx.send(()).unwrap();
-        task.await.unwrap().unwrap();
-        assert_eq!(reveals.load(Ordering::SeqCst), 1);
-    }
-
-    #[tokio::test]
-    async fn studio_open_cap_preserves_pause_failure_without_allowing_reveal() {
-        let result: Result<(), String> = async {
-            finish_main_controls(
-                Some(Phase::Recording),
-                None::>>,
-                async { Err("pause acknowledgement failed".into()) },
-            )
-            .await?;
-            panic!("a failed pause must not permit controls to be revealed")
-        }
-        .await;
-        assert_eq!(result.unwrap_err(), "pause acknowledgement failed");
-    }
-
-    #[tokio::test]
-    async fn repeated_studio_open_cap_keeps_the_recording_paused() {
-        for _ in 0..3 {
-            finish_main_controls(
-                Some(Phase::Paused),
-                None::>>,
-                async { panic!("an already paused recording must not be changed") },
-            )
-            .await
-            .unwrap();
-        }
-    }
-
-    #[tokio::test]
-    async fn studio_open_cap_rejects_pending_transitions_without_changing_capture() {
-        for phase in [
-            Phase::Starting,
-            Phase::Pausing,
-            Phase::Resuming,
-            Phase::ResumeFailed,
-            Phase::Restarting,
-            Phase::Stopping,
-        ] {
-            let result = finish_main_controls(
-                Some(phase),
-                None::>>,
-                async { panic!("a pending recording transition must not be changed") },
-            )
-            .await;
-            assert_eq!(
-                result.unwrap_err(),
-                "Recording is changing state. Use Ctrl+Shift+F9 to stop."
-            );
-        }
-    }
-
-    #[tokio::test]
-    async fn open_cap_keeps_preflight_visible_and_studio_pause_semantics() {
-        finish_main_controls(
-            Some(Phase::AwaitingShortcut),
-            Some(async { panic!("preflight must not issue Stop") }),
-            async { panic!("preflight must not issue Pause") },
-        )
-        .await
-        .unwrap();
-        finish_main_controls(
-            Some(Phase::Recording),
-            None::>>,
-            async { Ok(()) },
-        )
-        .await
-        .unwrap();
-    }
-
-    fn restoring() -> Inner {
-        Inner {
-            generation: 7,
-            lease: Some(Lease {
-                mode: cap_recording::RecordingMode::Instant,
-                generation: 7,
-                phase: Phase::Restoring,
-                pressed: false,
-                stop_requested: false,
-                registered_shortcut: true,
-                wayland: false,
-                stop_route: None,
-                stop_description: None,
-                stop_error: None,
-                lost_stop_routes: [false; 2],
-                recording_dir: None,
-                windows: Vec::new(),
-            }),
-            ..Inner::default()
-        }
-    }
-
-    #[test]
-    fn instant_restore_error_retains_lease_shortcut_and_error_until_successful_retry() {
-        let mut inner = restoring();
-        assert_eq!(
-            inner.complete_instant_restoration(7, Err("camera ack lost".into())),
-            None
-        );
-        assert_eq!(inner.snapshot().error.as_deref(), Some("camera ack lost"));
-        assert!(inner.lease.as_ref().unwrap().registered_shortcut);
-        assert_eq!(inner.generation, 7);
-        assert_eq!(inner.complete_instant_restoration(7, Ok(())), Some(true));
-        assert!(inner.lease.is_none());
-        assert_eq!(inner.generation, 8);
-        let receipt = inner.restored.as_ref().unwrap();
-        assert_eq!(receipt.generation, 7);
-        assert_eq!(receipt.restart_result(), Ok(()));
-    }
-
-    #[test]
-    fn instant_stop_during_restoration_prevents_restart_after_successful_window_ack() {
-        let mut inner = restoring();
-        assert!(inner.shortcut(true));
-        assert_eq!(inner.complete_instant_restoration(7, Ok(())), Some(true));
-        assert!(inner.lease.is_none());
-        assert_eq!(inner.generation, 8);
-        assert!(inner.restored.as_ref().unwrap().restart_result().is_err());
-    }
-
-    #[test]
-    fn instant_stale_restore_receipt_cannot_clear_new_lease_or_error() {
-        let mut inner = restoring();
-        assert_eq!(inner.complete_instant_restoration(6, Ok(())), None);
-        assert!(inner.restored.is_none());
-        inner.lease.as_mut().unwrap().phase = Phase::Starting;
-        assert_eq!(inner.complete_instant_restoration(7, Ok(())), None);
-        assert!(inner.lease.as_ref().unwrap().registered_shortcut);
-        assert!(inner.restored.is_none());
-    }
-}
-
-#[cfg(target_os = "linux")]
-thread_local! {
-    static WAYLAND_WINDOWS: std::cell::RefCell>> = std::cell::RefCell::new(std::collections::HashMap::new());
-}
-
-#[cfg(target_os = "linux")]
-pub(crate) fn wayland_generation(app: &AppHandle) -> Option {
-    let state = app.try_state::()?;
-    let inner = state.inner.lock().unwrap();
-    inner
-        .lease
-        .as_ref()
-        .filter(|lease| lease.wayland)
-        .map(|lease| lease.generation)
-}
-
-#[cfg(target_os = "linux")]
-pub(crate) fn describe_wayland_stop(app: &AppHandle, generation: u32, description: String) {
-    let state = app.state::();
-    let mut inner = state.inner.lock().unwrap();
-    if let Some(lease) = inner
-        .lease
-        .as_mut()
-        .filter(|lease| lease.generation == generation && lease.wayland)
-    {
-        lease.stop_description = Some(description);
-    }
-    drop(inner);
-    notify(app);
-}
-
-async fn save_windows(app: &AppHandle, generation: u32) -> Result, String> {
-    let (tx, rx) = tokio::sync::oneshot::channel();
-    let handle = app.clone();
-    app.run_on_main_thread(move || {
-        let result = (|| {
-            if !is_current(&handle, generation) {
-                return Err("Recording preflight was superseded".to_string());
-            }
-            #[cfg(target_os = "linux")]
-            if wayland_generation(&handle) == Some(generation) {
-                install_wayland_window_guard(&handle)?;
-                remember_wayland_windows(&handle, generation)?;
-            }
-            #[cfg(target_os = "linux")]
-            let save_all = wayland_generation(&handle) == Some(generation);
-            #[cfg(not(target_os = "linux"))]
-            let save_all = false;
-            let mut saved = Vec::new();
-            for (label, window) in handle.webview_windows() {
-                if save_all
-                    || matches!(
-                        label.parse::(),
-                        Ok(CapWindowId::Main | CapWindowId::Camera)
-                    )
-                {
-                    #[cfg(target_os = "linux")]
-                    if wayland_generation(&handle) == Some(generation) {
-                        let gtk = window.gtk_window().map_err(|error| error.to_string())?;
-                        WAYLAND_WINDOWS.with_borrow_mut(|windows| {
-                            windows.entry(generation).or_default().push(gtk)
-                        });
-                    }
-                    saved.push(SavedWindow {
-                        label,
-                        native_id: native_id(&window)?,
-                        visible: window.is_visible().map_err(|error| error.to_string())?,
-                    });
-                }
-            }
-            Ok(saved)
-        })();
-        let _ = tx.send(result);
-    })
-    .map_err(|error| error.to_string())?;
-    tokio::time::timeout(Duration::from_secs(2), rx)
-        .await
-        .map_err(|_| "Timed out saving recording windows".to_string())?
-        .map_err(|_| "Recording windows could not be saved".to_string())?
-}
-
-fn set_native_visibility(window: &WebviewWindow, visible: bool) -> Result<(), String> {
-    #[cfg(target_os = "linux")]
-    {
-        use gtk::prelude::*;
-        let gtk = window.gtk_window().map_err(|error| error.to_string())?;
-        // Tao queues GTK visibility changes even on the UI thread; this gate needs
-        // the native change to complete before checking its acknowledgement.
-        if visible {
-            gtk.show_all();
-        } else {
-            gtk.hide();
-        }
-        if gtk.is_visible() != visible || (!visible && gtk.is_mapped()) {
-            return Err("GTK did not acknowledge the recording window visibility change".into());
-        }
-        Ok(())
-    }
-    #[cfg(not(target_os = "linux"))]
-    {
-        if visible {
-            window.show()
-        } else {
-            window.hide()
-        }
-        .map_err(|error| error.to_string())
-    }
-}
-
-#[cfg(target_os = "linux")]
-async fn wayland_fence(app: &AppHandle, generation: u32, hidden: bool) -> Result<(), String> {
-    let (tx, rx) = tokio::sync::oneshot::channel();
-    let handle = app.clone();
-    app.run_on_main_thread(move || {
-        let display = (|| {
-            use gtk::prelude::*;
-            if !is_current(&handle, generation) {
-                return Err("Recording visibility fence was superseded".to_string());
-            }
-            let gtk = if let Some(window) = CapWindowId::Main.get(&handle) {
-                window.gtk_window().map_err(|error| error.to_string())?
-            } else if !hidden && phase(&handle) == Some(Phase::Restoring) {
-                WAYLAND_WINDOWS
-                    .with_borrow(|windows| {
-                        windows
-                            .get(&generation)
-                            .and_then(|windows| windows.first())
-                            .cloned()
-                    })
-                    .ok_or("Retained recording display disappeared")?
-            } else {
-                return Err("Main recording window disappeared".into());
-            };
-            let display = gtk.display();
-            if display.type_().name() != "GdkWaylandDisplay" {
-                return Err(
-                    "The recording window is not connected to the Wayland compositor".into(),
-                );
-            }
-            Ok(display)
-        })();
-        match display {
-            Ok(display) => wayland_ack::start(display, handle, generation, hidden, tx),
-            Err(error) => {
-                let _ = tx.send(Err(error));
-            }
-        }
-    })
-    .map_err(|error| error.to_string())?;
-    tokio::time::timeout(Duration::from_secs(3), rx)
-        .await
-        .map_err(|_| "Wayland visibility acknowledgement timed out".to_string())?
-        .map_err(|_| "Wayland visibility acknowledgement was lost".to_string())??;
-    if !is_current(app, generation) {
-        return Err("Recording visibility acknowledgement was superseded".into());
-    }
-    Ok(())
-}
-
-#[cfg(target_os = "linux")]
-mod wayland_ack {
-    use gtk::{gdk, prelude::*};
-    use std::{
-        cell::{Cell, RefCell},
-        ffi::c_void,
-        rc::Rc,
-        time::Duration,
-    };
-    use wayland_sys::{client::*, common::*};
-
-    type Reply = tokio::sync::oneshot::Sender>;
-    struct Pending {
-        callback: Cell<*mut wl_proxy>,
-        reply: RefCell>,
-        _display: gdk::Display,
-        app: tauri::AppHandle,
-        generation: u32,
-        hidden: bool,
-    }
-    impl Pending {
-        fn finish(&self, result: Result<(), String>) {
-            let callback = self.callback.replace(std::ptr::null_mut());
-            if !callback.is_null() {
-                unsafe {
-                    (wayland_client_handle().wl_proxy_destroy)(callback);
-                }
-            }
-            if let Some(reply) = self.reply.borrow_mut().take() {
-                let _ = reply.send(result);
-            }
-        }
-    }
-    static CALLBACK: wl_interface = wl_interface {
-        name: c"wl_callback".as_ptr(),
-        version: 1,
-        request_count: 0,
-        requests: std::ptr::null(),
-        event_count: 1,
-        events: &wl_message {
-            name: c"done".as_ptr(),
-            signature: c"u".as_ptr(),
-            types: std::ptr::null(),
-        },
-    };
-    unsafe extern "C" fn dispatch(
-        _: *const c_void,
-        data: *mut c_void,
-        opcode: u32,
-        _: *const wl_message,
-        _: *const wl_argument,
-    ) -> i32 {
-        let pending = unsafe {
-            &*((wayland_client_handle().wl_proxy_get_user_data)(data.cast()).cast::())
-        };
-        pending.finish(if opcode == 0 {
-            if pending.hidden {
-                super::verify_wayland_hidden(&pending.app, pending.generation)
-            } else {
-                super::verify_wayland_restored(&pending.app, pending.generation)
-            }
-        } else {
-            Err("Unexpected Wayland visibility acknowledgement".into())
-        });
-        0
-    }
-    pub(super) fn start(
-        display: gdk::Display,
-        app: tauri::AppHandle,
-        generation: u32,
-        hidden: bool,
-        reply: Reply,
-    ) {
-        let Some(client) = wayland_client_option() else {
-            let _ = reply.send(Err("Wayland client library is unavailable".into()));
-            return;
-        };
-        let raw =
-            unsafe { gdk_wayland_sys::gdk_wayland_display_get_wl_display(display.as_ptr().cast()) }
-                .cast::();
-        if raw.is_null() {
-            let _ = reply.send(Err("Wayland display connection is unavailable".into()));
-            return;
-        }
-        let mut args = [wl_argument {
-            o: std::ptr::null(),
-        }];
-        let callback = unsafe {
-            (client.wl_proxy_marshal_array_constructor)(raw.cast(), 0, args.as_mut_ptr(), &CALLBACK)
-        };
-        if callback.is_null() {
-            let _ = reply.send(Err(
-                "Could not queue Wayland visibility acknowledgement".into()
-            ));
-            return;
-        }
-        let pending = Rc::new(Pending {
-            callback: Cell::new(callback),
-            reply: RefCell::new(Some(reply)),
-            _display: display.clone(),
-            app,
-            generation,
-            hidden,
-        });
-        let result = unsafe {
-            (client.wl_proxy_add_dispatcher)(
-                callback,
-                dispatch,
-                std::ptr::null(),
-                Rc::as_ptr(&pending).cast_mut().cast(),
-            )
-        };
-        if result != 0 {
-            pending.finish(Err(
-                "Could not subscribe to Wayland visibility acknowledgement".into(),
-            ));
-            return;
-        }
-        // GDK owns dispatch on this connection. The timeout retains listener data until
-        // either the callback or timeout destroys the proxy, without reading GDK's queue.
-        gtk::glib::timeout_add_local_once(Duration::from_secs(2), move || {
-            pending.finish(Err(
-                "Wayland compositor did not acknowledge window visibility".into(),
-            ))
-        });
-        display.flush();
-    }
-}
-
-#[cfg(target_os = "linux")]
-pub(crate) fn wayland_stop_lost(app: &AppHandle, generation: u32, route: StopRoute, error: String) {
-    let state = app.state::();
-    let mut inner = state.inner.lock().unwrap();
-    let Some(lease) = inner
-        .lease
-        .as_mut()
-        .filter(|lease| lease.generation == generation && lease.wayland)
-    else {
-        return;
-    };
-    let stop = lease.lose_stop_route(route);
-    let studio_stop = (lease.mode == cap_recording::RecordingMode::Studio
-        && (stop || lease.stop_requested && lease.phase == Phase::Stopping))
-        .then(|| lease.recording_dir.clone())
-        .flatten();
-    if lease.stop_requested {
-        lease.stop_error = Some(error);
-    } else if route == StopRoute::Tray {
-        lease.stop_description = Some("the portal shortcut shown by your desktop".into());
-    }
-    drop(inner);
-    notify(app);
-    if let Some(directory) = studio_stop {
-        crate::recording::queue_clean_studio_stop(app, generation, directory);
-    } else if stop {
-        let app = app.clone();
-        drop(tauri::async_runtime::spawn(async move {
-            if let Err(error) = crate::recording::stop_recording(app.clone(), app.state()).await {
-                tracing::error!(%error, "Could not stop recording after losing its Stop control");
-            }
-        }));
-    }
-}
-
-#[cfg(target_os = "linux")]
-fn verify_wayland_hidden(app: &AppHandle, generation: u32) -> Result<(), String> {
-    use gtk::prelude::*;
-    if !is_current(app, generation) || stop_requested(app, generation) {
-        return Err("Recording hide acknowledgement was superseded or cancelled".into());
-    }
-    let main = CapWindowId::Main
-        .get(app)
-        .ok_or("Main recording window disappeared")?
-        .gtk_window()
-        .map_err(|error| error.to_string())?;
-    let display = main.display();
-    for window in wayland_application(app)?.windows() {
-        if window.display() != display || window.is_visible() || window.is_mapped() {
-            return Err("A Cap window is visible or uses another display connection".into());
-        }
-    }
-    Ok(())
-}
-
-#[cfg(target_os = "linux")]
-fn verify_wayland_restored(app: &AppHandle, generation: u32) -> Result<(), String> {
-    use gtk::prelude::*;
-    for (saved, wanted) in wayland_restore_plan(app, generation, true)? {
-        if saved.window.is_visible() != wanted || saved.window.is_mapped() != wanted {
-            return Err("The compositor restore acknowledgement did not match Cap windows".into());
-        }
-    }
-    Ok(())
-}
-
-fn wayland_blocks_mapping(phase: Phase) -> bool {
-    !matches!(
-        phase,
-        Phase::AwaitingShortcut | Phase::Paused | Phase::Restoring
-    )
-}
-
-#[cfg(any(target_os = "linux", test))]
-fn restore_floating_window(label: Option<&str>) -> bool {
-    !matches!(
-        label.and_then(|label| label.parse::().ok()),
-        Some(
-            CapWindowId::RecordingControls
-                | CapWindowId::TargetSelectOverlay { .. }
-                | CapWindowId::WindowCaptureOccluder { .. }
-                | CapWindowId::CaptureArea
-        )
-    )
-}
-
-#[cfg(target_os = "linux")]
-#[derive(Clone)]
-struct RetainedWaylandWindow {
-    window: gtk::Window,
-    label: Option,
-    visible: bool,
-    requested_during_stop: bool,
-}
-
-#[cfg(target_os = "linux")]
-thread_local! {
-    static WAYLAND_GUARD_APPLICATION: std::cell::RefCell>> = const { std::cell::RefCell::new(None) };
-    static WAYLAND_GUARDED_WINDOWS: std::cell::RefCell>> = const { std::cell::RefCell::new(Vec::new()) };
-    static WAYLAND_CAPTURE_WINDOWS: std::cell::RefCell>> = std::cell::RefCell::new(std::collections::HashMap::new());
-}
-
-#[cfg(target_os = "linux")]
-fn wayland_application(app: &AppHandle) -> Result {
-    use gtk::prelude::*;
-    CapWindowId::Main
-        .get(app)
-        .ok_or("Main recording window disappeared")?
-        .gtk_window()
-        .map_err(|error| error.to_string())?
-        .application()
-        .ok_or("Recording GTK application disappeared".into())
-}
-
-#[cfg(target_os = "linux")]
-fn wayland_window_label(app: &AppHandle, native: >k::Window) -> Option {
-    use gtk::prelude::*;
-    app.webview_windows()
-        .into_iter()
-        .find_map(|(label, window)| {
-            window
-                .gtk_window()
-                .ok()
-                .filter(|window| window.upcast_ref::() == native)
-                .map(|_| label)
-        })
-}
-
-#[cfg(target_os = "linux")]
-fn remember_wayland_window(
-    app: &AppHandle,
-    generation: u32,
-    window: >k::Window,
-    during_stop: bool,
-) {
-    use gtk::prelude::*;
-    let label = wayland_window_label(app, window);
-    WAYLAND_CAPTURE_WINDOWS.with_borrow_mut(|windows| {
-        let windows = windows.entry(generation).or_default();
-        if let Some(saved) = windows.iter_mut().find(|saved| saved.window == *window) {
-            if during_stop {
-                saved.requested_during_stop = true;
-            }
-        } else {
-            windows.push(RetainedWaylandWindow {
-                window: window.clone(),
-                label,
-                visible: window.is_visible(),
-                requested_during_stop: during_stop,
-            });
-        }
-    });
-}
-
-#[cfg(target_os = "linux")]
-fn guard_wayland_window(app: &AppHandle, window: >k::Window) {
-    use gtk::prelude::*;
-    let already_guarded = WAYLAND_GUARDED_WINDOWS.with_borrow_mut(|windows| {
-        windows.retain(|window| window.upgrade().is_some());
-        if windows
-            .iter()
-            .any(|saved| saved.upgrade().as_ref() == Some(window))
-        {
-            true
-        } else {
-            windows.push(window.downgrade());
-            false
-        }
-    });
-    if already_guarded {
-        return;
-    }
-    let app = app.clone();
-    window.connect_map(move |window| {
-        let blocked = {
-            let state = app.state::();
-            let inner = state.inner.lock().unwrap();
-            inner
-                .lease
-                .as_ref()
-                .filter(|lease| lease.wayland && wayland_blocks_mapping(lease.phase))
-                .map(|lease| (lease.generation, lease.phase == Phase::Stopping))
-        };
-        if let Some((generation, during_stop)) = blocked {
-            remember_wayland_window(&app, generation, window, during_stop);
-            // GTK's map default handler sends an empty Wayland commit with updates frozen
-            // until initial configure. This synchronous handler unmaps before that dispatch.
-            window.hide();
-        }
-    });
-}
-
-#[cfg(target_os = "linux")]
-fn install_wayland_window_guard(app: &AppHandle) -> Result<(), String> {
-    use gtk::prelude::*;
-    let application = wayland_application(app)?;
-    let installed = WAYLAND_GUARD_APPLICATION
-        .with_borrow(|saved| saved.as_ref().and_then(gtk::glib::WeakRef::upgrade));
-    if let Some(installed) = installed {
-        if installed != application {
-            return Err("Recording GTK application identity changed".into());
-        }
-        return Ok(());
-    }
-    let handle = app.clone();
-    application.connect_window_added(move |_, window| guard_wayland_window(&handle, window));
-    for window in application.windows() {
-        guard_wayland_window(app, &window);
-    }
-    WAYLAND_GUARD_APPLICATION.with_borrow_mut(|saved| *saved = Some(application.downgrade()));
-    Ok(())
-}
-
-#[cfg(target_os = "linux")]
-fn remember_wayland_windows(app: &AppHandle, generation: u32) -> Result<(), String> {
-    use gtk::prelude::*;
-    for window in wayland_application(app)?.windows() {
-        remember_wayland_window(app, generation, &window, false);
-    }
-    Ok(())
-}
-
-#[cfg(target_os = "linux")]
-fn hide_wayland_windows(app: &AppHandle, generation: u32) -> Result<(), String> {
-    use gtk::prelude::*;
-    remember_wayland_windows(app, generation)?;
-    for window in wayland_application(app)?.windows() {
-        window.hide();
-        if window.is_visible() || window.is_mapped() {
-            return Err("GTK could not hide a Cap window".into());
-        }
-    }
-    Ok(())
-}
-
-#[cfg(target_os = "linux")]
-pub(crate) fn admit_wayland_window_creation(app: &AppHandle) -> Result<(), String> {
-    let state = app.state::();
-    let inner = state.inner.lock().unwrap();
-    if inner.lease.as_ref().is_some_and(|lease| {
-        lease.wayland && wayland_blocks_mapping(lease.phase) && lease.phase != Phase::Stopping
-    }) {
-        return Err("Pause or stop recording before opening another Cap window".into());
-    }
-    Ok(())
-}
-
-#[cfg(target_os = "linux")]
-fn wayland_restore_plan(
-    app: &AppHandle,
-    generation: u32,
-    require_inputs: bool,
-) -> Result, String> {
-    use gtk::prelude::*;
-    let saved_main = {
-        let state = app.state::();
-        let inner = state.inner.lock().unwrap();
-        let lease = inner
-            .lease
-            .as_ref()
-            .filter(|lease| lease.generation == generation && lease.phase == Phase::Restoring)
-            .ok_or("Wayland restoration was superseded")?;
-        lease
-            .windows
-            .iter()
-            .find(|window| window.label == CapWindowId::Main.label())
-            .cloned()
-    };
-    let requested = if require_inputs {
-        Some(
-            app.state::()
-                .ready_snapshot()?,
-        )
-    } else {
-        None
-    };
-    let retained = WAYLAND_CAPTURE_WINDOWS
-        .with_borrow(|windows| windows.get(&generation).cloned())
-        .ok_or("Retained Wayland windows disappeared")?;
-    let application = WAYLAND_GUARD_APPLICATION
-        .with_borrow(|saved| saved.as_ref().and_then(gtk::glib::WeakRef::upgrade))
-        .ok_or("Retained GTK application disappeared")?;
-    let current = application.windows();
-    let mut result = Vec::new();
-    for mut saved in retained {
-        let label = wayland_window_label(app, &saved.window);
-        let label_changed = saved.label.is_some() && saved.label != label;
-        if saved.label.is_none() {
-            saved.label = label;
-        }
-        let camera = saved
-            .label
-            .as_deref()
-            .is_some_and(|label| matches!(label.parse(), Ok(CapWindowId::Camera)));
-        let editor = saved
-            .label
-            .as_deref()
-            .is_some_and(|label| matches!(label.parse(), Ok(CapWindowId::Editor { .. })));
-        let mut wanted = (saved.visible || (editor && saved.requested_during_stop))
-            && restore_floating_window(saved.label.as_deref())
-            && (!camera
-                || requested
-                    .as_ref()
-                    .is_some_and(|snapshot| snapshot.camera.value.is_some()));
-        if saved.label.as_deref() == Some("main") {
-            wanted = saved_main.as_ref().is_some_and(|saved| saved.visible);
-        }
-        if wanted && label_changed {
-            return Err("A retained Cap window changed identity".into());
-        }
-        if wanted && !current.contains(&saved.window) {
-            return Err("A retained Cap window disappeared before restoration".into());
-        }
-        result.push((saved, wanted));
-    }
-    if requested.as_ref().is_some_and(|requested| {
-        !app.state::()
-            .is_current(requested)
-    }) {
-        return Err("Requested inputs changed during Wayland restoration".into());
-    }
-    Ok(result)
-}
-
-#[cfg(target_os = "linux")]
-fn restore_wayland_windows(
-    app: &AppHandle,
-    generation: u32,
-    main_only: bool,
-) -> Result<(), String> {
-    use gtk::prelude::*;
-    for (saved, wanted) in wayland_restore_plan(app, generation, !main_only)? {
-        if (saved.label.as_deref() == Some("main")) != main_only {
-            continue;
-        }
-        if wanted {
-            saved.window.show_all();
-            if saved.requested_during_stop
-                && saved
-                    .label
-                    .as_deref()
-                    .is_some_and(|label| matches!(label.parse(), Ok(CapWindowId::Editor { .. })))
-            {
-                saved.window.present();
-            }
-        } else {
-            saved.window.hide();
-        }
-        if saved.window.is_visible() != wanted || (!wanted && saved.window.is_mapped()) {
-            return Err("GTK did not acknowledge Cap window restoration".into());
-        }
-    }
-    Ok(())
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn wayland_blocks_all_floating_labels_while_capture_can_run() {
-        for mode in [
-            cap_recording::RecordingMode::Studio,
-            cap_recording::RecordingMode::Instant,
-        ] {
-            for phase in [
-                Phase::Starting,
-                Phase::Recording,
-                Phase::Pausing,
-                Phase::Resuming,
-                Phase::ResumeFailed,
-                Phase::Restarting,
-                Phase::Stopping,
-            ] {
-                let mut inner = fixture();
-                let lease = inner.lease.as_mut().unwrap();
-                lease.mode = mode;
-                lease.wayland = true;
-                lease.phase = phase;
-                for label in [
-                    "main",
-                    "camera",
-                    "teleprompter",
-                    "settings",
-                    "editor-4",
-                    "unknown-js-window",
-                ] {
-                    assert!(!inner.may_reveal(1, label), "{phase:?}: {label}");
-                }
-            }
-        }
-    }
-
-    #[test]
-    fn x11_floating_admission_is_unchanged() {
-        let mut inner = fixture();
-        inner.lease.as_mut().unwrap().phase = Phase::Recording;
-        assert!(!inner.lease.as_ref().unwrap().wayland);
-        assert!(inner.may_reveal(1, "teleprompter"));
-        assert!(inner.may_reveal(1, "settings"));
-        assert!(!inner.may_reveal(1, "camera"));
-    }
-
-    #[test]
-    fn wayland_restore_keeps_non_camera_window_intent() {
-        for label in ["teleprompter", "settings", "editor-4", "unknown-js-window"] {
-            assert!(restore_floating_window(Some(label)));
-        }
-        assert!(restore_floating_window(None));
-        for label in [
-            "capture-area",
-            "in-progress-recording",
-            "target-select-overlay-1",
-            "window-capture-occluder-1",
-        ] {
-            assert!(!restore_floating_window(Some(label)));
-        }
-    }
-
-    #[test]
-    fn wayland_safe_ui_phases_allow_mapping_but_old_generation_does_not() {
-        for phase in [Phase::AwaitingShortcut, Phase::Paused, Phase::Restoring] {
-            assert!(!wayland_blocks_mapping(phase));
-            let mut inner = fixture();
-            let lease = inner.lease.as_mut().unwrap();
-            lease.wayland = true;
-            lease.phase = phase;
-            assert!(inner.may_reveal(1, "teleprompter"));
-            assert!(!inner.may_reveal(0, "teleprompter"));
-        }
-    }
-
-    #[tokio::test]
-    async fn restore_pass_waits_for_successful_ack_before_following_work() {
-        let (tx, rx) = tokio::sync::oneshot::channel();
-        let work = std::sync::Arc::new(std::sync::atomic::AtomicUsize::new(0));
-        let observed = work.clone();
-        let task = tokio::spawn(async move {
-            if restore_pass_acknowledged(true, rx).await {
-                observed.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
-            }
-        });
-        tokio::task::yield_now().await;
-        assert!(!task.is_finished());
-        assert_eq!(work.load(std::sync::atomic::Ordering::SeqCst), 0);
-        tx.send(Ok(())).unwrap();
-        task.await.unwrap();
-        assert_eq!(work.load(std::sync::atomic::Ordering::SeqCst), 1);
-    }
-
-    #[tokio::test]
-    async fn rejected_restore_pass_does_not_authorize_following_work() {
-        let (tx, rx) = tokio::sync::oneshot::channel();
-        tx.send(Err("Instant cleanup is unconfirmed".into()))
-            .unwrap();
-        assert!(!restore_pass_acknowledged(true, rx).await);
-    }
-
-    #[tokio::test]
-    async fn dropped_restore_ack_does_not_authorize_following_work() {
-        let (tx, rx) = tokio::sync::oneshot::channel();
-        drop(tx);
-        assert!(!restore_pass_acknowledged(true, rx).await);
-    }
-
-    #[tokio::test]
-    async fn unscheduled_restore_pass_does_not_wait_for_an_ack() {
-        let (tx, rx) = tokio::sync::oneshot::channel();
-        assert!(
-            !tokio::time::timeout(
-                std::time::Duration::from_millis(100),
-                restore_pass_acknowledged(false, rx),
-            )
-            .await
-            .unwrap()
-        );
-        assert!(tx.is_closed());
-    }
-
-    #[cfg(target_os = "linux")]
-    fn x11_studio_restoring_fixture() -> Mutex {
-        let mut inner = fixture();
-        inner.lease.as_mut().unwrap().phase = Phase::Restoring;
-        Mutex::new(inner)
-    }
-
-    #[cfg(target_os = "linux")]
-    #[tokio::test]
-    async fn x11_studio_restore_waits_for_windows_before_stop_cleanup_and_receipt() {
-        use std::sync::{
-            Arc,
-            atomic::{AtomicUsize, Ordering},
-        };
-
-        let inner = Arc::new(x11_studio_restoring_fixture());
-        let inputs = Arc::new(AtomicUsize::new(0));
-        let cleanup = Arc::new(AtomicUsize::new(0));
-        let (main_tx, main_rx) = tokio::sync::oneshot::channel::>();
-        let (camera_tx, camera_rx) = tokio::sync::oneshot::channel::>();
-        let (inputs_tx, inputs_rx) = tokio::sync::oneshot::channel();
-        let task = tokio::spawn({
-            let inner = inner.clone();
-            let inputs = inputs.clone();
-            let cleanup = cleanup.clone();
-            async move {
-                let result = restore_instant_sequence(
-                    async { main_rx.await.unwrap() },
-                    || async move {
-                        inputs.fetch_add(1, Ordering::SeqCst);
-                        inputs_tx.send(()).unwrap();
-                    },
-                    || async { camera_rx.await.unwrap() },
-                )
-                .await;
-                assert!(finish_x11_studio_restoration(&inner, 1, result, || {
-                    cleanup.fetch_add(1, Ordering::SeqCst);
-                    Ok(())
-                }));
-            }
-        });
-        tokio::task::yield_now().await;
-        assert!(!task.is_finished());
-        assert_eq!(inputs.load(Ordering::SeqCst), 0);
-        assert_eq!(cleanup.load(Ordering::SeqCst), 0);
-        assert!(inner.lock().unwrap().restored.is_none());
-        main_tx.send(Ok(())).unwrap();
-        inputs_rx.await.unwrap();
-        assert!(!task.is_finished());
-        assert_eq!(inputs.load(Ordering::SeqCst), 1);
-        assert_eq!(cleanup.load(Ordering::SeqCst), 0);
-        assert!(inner.lock().unwrap().lease.is_some());
-        assert!(inner.lock().unwrap().restored.is_none());
-        camera_tx.send(Ok(())).unwrap();
-        task.await.unwrap();
-        let inner = inner.lock().unwrap();
-        assert!(inner.lease.is_none());
-        assert_eq!(inner.generation, 2);
-        let receipt = inner.restored.as_ref().unwrap();
-        assert_eq!(receipt.generation, 1);
-        assert_eq!(receipt.restart_result(), Ok(()));
-        assert_eq!(cleanup.load(Ordering::SeqCst), 1);
-    }
-
-    #[cfg(target_os = "linux")]
-    #[test]
-    fn x11_studio_restore_failures_retain_ownership_and_report_failure_until_retry() {
-        for (windows, cleanup, error, cleanup_calls) in [
-            (
-                Err("window restoration failed".to_string()),
-                Ok(()),
-                "window restoration failed",
-                0,
-            ),
-            (
-                Ok(()),
-                Err("Stop cleanup failed".to_string()),
-                "Stop cleanup failed",
-                1,
-            ),
-        ] {
-            let state = x11_studio_restoring_fixture();
-            let calls = std::cell::Cell::new(0);
-            assert!(!finish_x11_studio_restoration(&state, 1, windows, || {
-                calls.set(calls.get() + 1);
-                cleanup
-            }));
-            assert_eq!(calls.get(), cleanup_calls);
-            {
-                let inner = state.lock().unwrap();
-                assert_eq!(inner.generation, 1);
-                let lease = inner.lease.as_ref().unwrap();
-                assert_eq!(lease.phase, Phase::Restoring);
-                assert!(lease.registered_shortcut);
-                assert!(inner.x11_cleanup.is_none());
-                assert_eq!(inner.snapshot().error.as_deref(), Some(error));
-                let receipt = inner.restored.as_ref().unwrap();
-                assert_eq!(receipt.generation, 1);
-                assert_eq!(receipt.restart_result(), Err(error.to_string()));
-            }
-            assert!(!finish_x11_studio_restoration(&state, 1, Ok(()), || {
-                panic!("a duplicate completion cannot retry cleanup")
-            }));
-            {
-                let mut inner = state.lock().unwrap();
-                assert_eq!(inner.begin_x11_studio_restore_retry(false), None);
-                assert_eq!(inner.begin_x11_studio_restore_retry(true), Some(1));
-                assert!(inner.lease.as_ref().unwrap().stop_requested);
-            }
-            assert!(finish_x11_studio_restoration(&state, 1, Ok(()), || Ok(())));
-            let inner = state.lock().unwrap();
-            assert!(inner.lease.is_none());
-            assert_eq!(inner.generation, 2);
-            assert_eq!(
-                inner.restored.as_ref().unwrap().restart_result(),
-                Err("Recording restart was cancelled by Stop".into())
-            );
-        }
-    }
-
-    #[cfg(target_os = "linux")]
-    #[test]
-    fn x11_studio_stale_and_duplicate_restore_cannot_release_another_owner() {
-        let state = x11_studio_restoring_fixture();
-        assert!(!finish_x11_studio_restoration(&state, 0, Ok(()), || {
-            panic!("a stale generation must not release the shortcut")
-        }));
-        assert!(state.lock().unwrap().restored.is_none());
-        state.lock().unwrap().lease.as_mut().unwrap().phase = Phase::Starting;
-        assert!(!finish_x11_studio_restoration(&state, 1, Ok(()), || {
-            panic!("a live recording must not release the shortcut")
-        }));
-        state.lock().unwrap().lease.as_mut().unwrap().phase = Phase::Restoring;
-        assert!(finish_x11_studio_restoration(&state, 1, Ok(()), || Ok(())));
-        assert!(!finish_x11_studio_restoration(&state, 1, Ok(()), || {
-            panic!("a duplicate completion must not release the shortcut")
-        }));
-        assert_eq!(state.lock().unwrap().generation, 2);
-        let next = x11_studio_restoring_fixture();
-        {
-            let mut inner = next.lock().unwrap();
-            inner.generation = 2;
-            inner.lease.as_mut().unwrap().generation = 2;
-        }
-        assert!(!finish_x11_studio_restoration(&next, 1, Ok(()), || {
-            panic!("an old completion must not release the new shortcut")
-        }));
-        let inner = next.lock().unwrap();
-        assert_eq!(inner.generation, 2);
-        assert!(inner.lease.as_ref().unwrap().registered_shortcut);
-        assert!(inner.restored.is_none());
-    }
-
-    #[cfg(target_os = "linux")]
-    #[test]
-    fn x11_studio_restore_keeps_the_users_existing_stop_shortcut() {
-        let state = x11_studio_restoring_fixture();
-        state
-            .lock()
-            .unwrap()
-            .lease
-            .as_mut()
-            .unwrap()
-            .registered_shortcut = false;
-        assert!(finish_x11_studio_restoration(&state, 1, Ok(()), || {
-            panic!("the user shortcut is not owned by this restoration")
-        }));
-        let inner = state.lock().unwrap();
-        assert_eq!(inner.restored.as_ref().unwrap().restart_result(), Ok(()));
-    }
-
-    #[cfg(target_os = "linux")]
-    #[test]
-    fn x11_studio_stop_during_restoration_prevents_restart_after_cleanup() {
-        let state = x11_studio_restoring_fixture();
-        assert!(state.lock().unwrap().shortcut(true));
-        assert!(finish_x11_studio_restoration(&state, 1, Ok(()), || Ok(())));
-        let inner = state.lock().unwrap();
-        assert!(inner.lease.is_none());
-        assert_eq!(
-            inner.restored.as_ref().unwrap().restart_result(),
-            Err("Recording restart was cancelled by Stop".into())
-        );
-    }
-
-    #[cfg(target_os = "linux")]
-    #[test]
-    fn x11_studio_completion_does_not_accept_instant_or_wayland_leases() {
-        for (mode, wayland) in [
-            (cap_recording::RecordingMode::Instant, false),
-            (cap_recording::RecordingMode::Studio, true),
-        ] {
-            let state = x11_studio_restoring_fixture();
-            {
-                let mut inner = state.lock().unwrap();
-                let lease = inner.lease.as_mut().unwrap();
-                lease.mode = mode;
-                lease.wayland = wayland;
-                assert_eq!(inner.begin_x11_studio_restore_retry(true), None);
-            }
-            assert!(!finish_x11_studio_restoration(&state, 1, Ok(()), || {
-                panic!("another restoration path owns this shortcut")
-            }));
-            let inner = state.lock().unwrap();
-            assert!(inner.restored.is_none());
-            assert!(inner.lease.is_some());
-        }
-    }
-
-    #[cfg(target_os = "linux")]
-    #[test]
-    fn x11_studio_unregister_allows_the_f9_callback_to_lock_and_latch_stop() {
-        let state = x11_studio_restoring_fixture();
-        let (request_tx, request_rx) = std::sync::mpsc::channel();
-        let (reply_tx, reply_rx) = std::sync::mpsc::channel();
-        std::thread::scope(|scope| {
-            let callback_state = &state;
-            let callback = scope.spawn(move || {
-                request_rx.recv_timeout(Duration::from_secs(1)).unwrap();
-                let mut inner = callback_state.lock().unwrap();
-                assert!(inner.x11_cleanup.is_some());
-                assert!(inner.lease.as_ref().unwrap().registered_shortcut);
-                assert!(inner.reserve_x11_studio_cleanup(1, Ok(())).is_none());
-                assert!(inner.shortcut(true));
-                drop(inner);
-                reply_tx.send(()).unwrap();
-            });
-            assert!(finish_x11_studio_restoration(&state, 1, Ok(()), || {
-                request_tx.send(()).unwrap();
-                reply_rx
-                    .recv_timeout(Duration::from_secs(1))
-                    .map_err(|_| "F9 callback could not acquire restoration state".into())
-            }));
-            callback.join().unwrap();
-        });
-        let inner = state.lock().unwrap();
-        assert!(inner.x11_cleanup.is_none());
-        assert!(inner.lease.is_none());
-        assert_eq!(
-            inner.restored.as_ref().unwrap().restart_result(),
-            Err("Recording restart was cancelled by Stop".into())
-        );
-    }
-
-    #[cfg(target_os = "linux")]
-    #[test]
-    fn x11_studio_old_cleanup_completion_cannot_finish_a_retry() {
-        let state = x11_studio_restoring_fixture();
-        let mut inner = state.lock().unwrap();
-        let first = inner.reserve_x11_studio_cleanup(1, Ok(())).unwrap();
-        assert!(inner.reserve_x11_studio_cleanup(1, Ok(())).is_none());
-        assert!(!inner.complete_x11_studio_restoration(first, Err("unregister failed".into())));
-        assert_eq!(inner.begin_x11_studio_restore_retry(true), Some(1));
-        let retry = inner.reserve_x11_studio_cleanup(1, Ok(())).unwrap();
-        assert_ne!(first.sequence, retry.sequence);
-        assert!(!inner.complete_x11_studio_restoration(first, Ok(())));
-        assert!(inner.x11_cleanup == Some(retry));
-        assert!(inner.lease.as_ref().unwrap().registered_shortcut);
-        assert!(inner.complete_x11_studio_restoration(retry, Ok(())));
-        assert!(!inner.complete_x11_studio_restoration(retry, Ok(())));
-        assert_eq!(inner.generation, 2);
-    }
-
-    #[cfg(target_os = "linux")]
-    #[tokio::test]
-    async fn x11_studio_pending_waiter_rejects_restart_after_error_f9_and_retry_success() {
-        let state = State {
-            inner: x11_studio_restoring_fixture(),
-            ..State::default()
-        };
-        let mut waiter = Box::pin(wait_for_restoration(&state, 1));
-        assert!(futures::poll!(&mut waiter).is_pending());
-        assert!(!finish_x11_studio_restoration(
-            &state.inner,
-            1,
-            Err("window acknowledgement failed".into()),
-            || panic!("window failure must retain the Stop shortcut"),
-        ));
-        state.changed.notify_waiters();
-        {
-            let mut inner = state.inner.lock().unwrap();
-            assert_eq!(inner.begin_x11_studio_restore_retry(true), Some(1));
-            assert!(inner.restored.is_none());
-            assert!(inner.lease.as_ref().unwrap().stop_requested);
-        }
-        assert!(finish_x11_studio_restoration(
-            &state.inner,
-            1,
-            Ok(()),
-            || Ok(())
-        ));
-        state.changed.notify_waiters();
-        assert_eq!(
-            waiter.await,
-            Err("Recording restart was cancelled by Stop".into())
-        );
-    }
-
-    fn fixture() -> Inner {
-        Inner {
-            generation: 1,
-            stop_notice: None,
-            stop_notice_sequence: 0,
-            control_error: None,
-            restored: None,
-            #[cfg(target_os = "linux")]
-            x11_cleanup_sequence: 0,
-            #[cfg(target_os = "linux")]
-            x11_cleanup: None,
-            lease: Some(Lease {
-                mode: cap_recording::RecordingMode::Studio,
-                generation: 1,
-                phase: Phase::AwaitingShortcut,
-                pressed: false,
-                stop_requested: false,
-                registered_shortcut: true,
-                wayland: false,
-                stop_route: None,
-                stop_description: None,
-                stop_error: None,
-                lost_stop_routes: [false; 2],
-                recording_dir: None,
-                windows: Vec::new(),
-            }),
-        }
-    }
-
-    #[test]
-    fn requires_delivered_press_then_release() {
-        let mut state = fixture();
-        assert!(state.shortcut(false));
-        assert_eq!(state.lease.as_ref().unwrap().phase, Phase::AwaitingShortcut);
-        assert!(state.shortcut(true));
-        assert_eq!(state.lease.as_ref().unwrap().phase, Phase::AwaitingShortcut);
-        assert!(state.shortcut(false));
-        assert_eq!(state.lease.as_ref().unwrap().phase, Phase::Starting);
-        assert!(!state.lease.as_ref().unwrap().stop_requested);
-        assert!(state.shortcut(true));
-        assert!(state.lease.as_ref().unwrap().stop_requested);
-    }
-
-    #[test]
-    fn delayed_reveal_cannot_cross_generation() {
-        let mut state = fixture();
-        assert!(state.may_reveal(1, "main"));
-        state.generation = 2;
-        state.lease = None;
-        assert!(!state.may_reveal(1, "main"));
-        assert!(!state.may_reveal(1, "camera"));
-        assert!(state.may_reveal(2, "main"));
-    }
-
-    #[test]
-    fn wayland_requires_delivered_current_stop_input() {
-        let mut state = fixture();
-        let lease = state.lease.as_mut().unwrap();
-        lease.wayland = true;
-        assert!(!lease.accept_stop_input(None, true));
-        assert!(!lease.accept_stop_input(Some((2, StopRoute::Tray)), true));
-        assert!(!lease.accept_stop_input(Some((1, StopRoute::Portal)), false));
-        assert_eq!(lease.phase, Phase::AwaitingShortcut);
-        assert!(lease.accept_stop_input(Some((1, StopRoute::Portal)), true));
-        assert!(state.shortcut(true));
-        assert!(
-            !state
-                .lease
-                .as_mut()
-                .unwrap()
-                .accept_stop_input(Some((1, StopRoute::Tray)), false)
-        );
-        assert!(
-            state
-                .lease
-                .as_mut()
-                .unwrap()
-                .accept_stop_input(Some((1, StopRoute::Portal)), false)
-        );
-        assert!(state.shortcut(false));
-        assert_eq!(state.lease.as_ref().unwrap().phase, Phase::Starting);
-    }
-
-    #[test]
-    fn wayland_tray_activation_starts_and_next_activation_stops() {
-        let mut state = fixture();
-        state.lease.as_mut().unwrap().wayland = true;
-        for pressed in [true, false] {
-            assert!(
-                state
-                    .lease
-                    .as_mut()
-                    .unwrap()
-                    .accept_stop_input(Some((1, StopRoute::Tray)), pressed)
-            );
-            assert!(state.shortcut(pressed));
-        }
-        assert_eq!(state.lease.as_ref().unwrap().phase, Phase::Starting);
-        state.lease.as_mut().unwrap().phase = Phase::Recording;
-        assert!(
-            state
-                .lease
-                .as_mut()
-                .unwrap()
-                .accept_stop_input(Some((1, StopRoute::Tray)), true)
-        );
-        assert!(state.shortcut(true));
-        assert!(state.lease.as_ref().unwrap().stop_requested);
-    }
-
-    #[test]
-    fn wayland_loss_cannot_start_or_silently_switch_control() {
-        let mut state = fixture();
-        let lease = state.lease.as_mut().unwrap();
-        lease.wayland = true;
-        assert!(!lease.lose_stop_route(StopRoute::Portal));
-        assert!(!lease.stop_requested);
-        assert!(!lease.accept_stop_input(Some((1, StopRoute::Portal)), true));
-        assert!(lease.accept_stop_input(Some((1, StopRoute::Tray)), true));
-        lease.phase = Phase::Recording;
-        assert!(lease.lose_stop_route(StopRoute::Tray));
-        assert!(lease.stop_requested);
-        assert!(!lease.accept_stop_input(Some((1, StopRoute::Tray)), true));
-    }
-
-    #[test]
-    fn wayland_both_missing_controls_cancel_visible_preflight() {
-        let mut state = fixture();
-        let lease = state.lease.as_mut().unwrap();
-        lease.wayland = true;
-        assert!(!lease.lose_stop_route(StopRoute::Tray));
-        assert!(!lease.lose_stop_route(StopRoute::Portal));
-        assert!(lease.stop_requested);
-        assert_eq!(lease.phase, Phase::AwaitingShortcut);
-    }
-
-    #[test]
-    fn wayland_control_loss_during_start_is_retained_until_cleanup() {
-        let mut state = fixture();
-        let lease = state.lease.as_mut().unwrap();
-        lease.wayland = true;
-        lease.stop_route = Some(StopRoute::Tray);
-        lease.phase = Phase::Starting;
-        assert!(!lease.lose_stop_route(StopRoute::Tray));
-        assert!(lease.stop_requested);
-        assert_eq!(lease.phase, Phase::Starting);
-    }
-
-    #[test]
-    fn only_acknowledged_pause_allows_main() {
-        let mut state = fixture();
-        for phase in [
-            Phase::Starting,
-            Phase::Recording,
-            Phase::Pausing,
-            Phase::Resuming,
-            Phase::Restarting,
-            Phase::Stopping,
-        ] {
-            state.lease.as_mut().unwrap().phase = phase;
-            assert!(!state.may_reveal(1, "main"));
-            assert!(!state.may_reveal(1, "camera"));
-            assert!(!state.may_reveal(1, "in-progress-recording"));
-        }
-        state.lease.as_mut().unwrap().phase = Phase::Paused;
-        assert!(state.may_reveal(1, "main"));
-        assert!(!state.may_reveal(1, "camera"));
-    }
-
-    #[test]
-    fn instant_uses_capture_backend_without_loosening_studio_environment() {
-        use cap_recording::RecordingMode;
-        for strict_x11 in [false, true] {
-            assert!(capture_environment_is_x11(
-                RecordingMode::Instant,
-                strict_x11,
-                false
-            ));
-            assert!(!capture_environment_is_x11(
-                RecordingMode::Instant,
-                strict_x11,
-                true
-            ));
-            for uses_wayland_portal in [false, true] {
-                assert_eq!(
-                    capture_environment_is_x11(
-                        RecordingMode::Studio,
-                        strict_x11,
-                        uses_wayland_portal
-                    ),
-                    strict_x11
-                );
-            }
-        }
-        assert!(!x11_environment(true, false, None));
-        assert!(capture_environment_is_x11(
-            RecordingMode::Instant,
-            x11_environment(true, false, None),
-            false
-        ));
-        assert!(!x11_environment(true, true, Some("x11")));
-        assert!(capture_environment_is_x11(
-            RecordingMode::Instant,
-            x11_environment(true, true, Some("x11")),
-            false
-        ));
-    }
-
-    #[test]
-    fn monitor_visibility_requires_x11_for_both_recording_modes() {
-        use cap_recording::{RecordingMode, screen_capture::ScreenCaptureTarget};
-        let display = ScreenCaptureTarget::Display {
-            id: "1".parse().unwrap(),
-        };
-        let area = ScreenCaptureTarget::Area {
-            screen: "1".parse().unwrap(),
-            bounds: scap_targets::bounds::LogicalBounds::new(
-                scap_targets::bounds::LogicalPosition::new(0.0, 0.0),
-                scap_targets::bounds::LogicalSize::new(100.0, 100.0),
-            ),
-        };
-        let window = ScreenCaptureTarget::Window {
-            id: "1".parse().unwrap(),
-        };
-        for mode in [RecordingMode::Studio, RecordingMode::Instant] {
-            for target in [&display, &area] {
-                assert_eq!(
-                    validate_capture_visibility(mode, target, false, false, true),
-                    Ok(true)
-                );
-                assert!(validate_capture_visibility(mode, target, false, false, false).is_err());
-            }
-            for target in [&window, &ScreenCaptureTarget::CameraOnly] {
-                assert_eq!(
-                    validate_capture_visibility(mode, target, false, false, true),
-                    Ok(false)
-                );
-                assert_eq!(
-                    validate_capture_visibility(mode, target, false, false, false),
-                    Ok(false)
-                );
-            }
-        }
-        assert_eq!(
-            validate_capture_visibility(RecordingMode::Screenshot, &display, false, false, false),
-            Ok(false)
-        );
-    }
-
-    #[test]
-    fn window_camera_visibility_is_required_only_for_x11_instant() {
-        use cap_recording::{RecordingMode, screen_capture::ScreenCaptureTarget};
-        let target = ScreenCaptureTarget::Window {
-            id: "1".parse().unwrap(),
-        };
-        for mode in [
-            RecordingMode::Studio,
-            RecordingMode::Instant,
-            RecordingMode::Screenshot,
-        ] {
-            for camera in [false, true] {
-                for wayland in [false, true] {
-                    let required = mode == RecordingMode::Instant && camera && !wayland;
-                    assert_eq!(
-                        validate_capture_visibility(mode, &target, camera, wayland, true),
-                        Ok(required)
-                    );
-                    let unsupported =
-                        validate_capture_visibility(mode, &target, camera, wayland, false);
-                    if required {
-                        assert!(unsupported.is_err());
-                    } else {
-                        assert_eq!(unsupported, Ok(false));
-                    }
-                }
-            }
-        }
-    }
-
-    #[test]
-    fn refuses_wayland_and_ambiguous_sessions() {
-        assert!(x11_environment(true, false, Some("x11")));
-        assert!(!x11_environment(true, true, Some("x11")));
-        assert!(!x11_environment(true, false, Some("wayland")));
-        assert!(!x11_environment(true, false, None));
-        assert!(!x11_environment(false, false, Some("x11")));
-    }
-
-    #[test]
-    fn cancel_preflight_never_starts() {
-        let mut state = fixture();
-        assert!(state.queue_stop());
-        assert!(state.shortcut(true));
-        assert!(state.shortcut(false));
-        assert!(state.lease.as_ref().unwrap().stop_requested);
-    }
-
-    #[test]
-    fn stop_is_retained_through_start_restart_and_control_transitions() {
-        for phase in [Phase::Starting, Phase::Restarting, Phase::Pausing] {
-            let mut state = fixture();
-            state.lease.as_mut().unwrap().phase = phase;
-            assert!(state.queue_stop());
-            assert!(state.lease.as_ref().unwrap().stop_requested);
-            assert_eq!(state.lease.as_ref().unwrap().phase, phase);
-        }
-    }
-
-    #[test]
-    fn active_stop_claims_cleanup_once() {
-        let mut state = fixture();
-        state.lease.as_mut().unwrap().phase = Phase::Recording;
-        assert!(!state.queue_stop());
-        assert_eq!(state.lease.as_ref().unwrap().phase, Phase::Stopping);
-        assert!(state.queue_stop());
-        assert!(state.lease.as_ref().unwrap().stop_requested);
-    }
-
-    #[test]
-    fn unconfirmed_resume_failure_keeps_main_hidden_and_stop_actionable() {
-        let mut state = fixture();
-        let dir = PathBuf::from("recording-a");
-        let lease = state.lease.as_mut().unwrap();
-        lease.recording_dir = Some(dir.clone());
-        lease.phase = Phase::Resuming;
-        assert!(state.complete_control(
-            1,
-            &dir,
-            true,
-            &ControlOutcome::ActorFailed {
-                error: "actor transport failed".into(),
-                paused: false,
-            }
-        ));
-        assert_eq!(state.lease.as_ref().unwrap().phase, Phase::ResumeFailed);
-        assert!(state.shortcut(true));
-        assert!(state.lease.as_ref().unwrap().phase.can_stop());
-        assert!(!state.may_reveal(1, "main"));
-        assert!(!state.queue_stop());
-        assert_eq!(state.lease.as_ref().unwrap().phase, Phase::Stopping);
-    }
-
-    #[test]
-    fn old_control_acknowledgement_cannot_publish_into_new_recording() {
-        let mut state = fixture();
-        let lease = state.lease.as_mut().unwrap();
-        lease.phase = Phase::Pausing;
-        lease.recording_dir = Some(PathBuf::from("recording-b"));
-        lease.generation = 2;
-        state.generation = 2;
-        assert!(!state.complete_control(
-            1,
-            std::path::Path::new("recording-a"),
-            false,
-            &ControlOutcome::Succeeded
-        ));
-        assert!(!state.complete_control(
-            2,
-            std::path::Path::new("recording-a"),
-            false,
-            &ControlOutcome::Succeeded
-        ));
-        assert_eq!(state.lease.as_ref().unwrap().phase, Phase::Pausing);
-    }
-
-    #[test]
-    fn target_overlays_stay_hidden_even_during_preflight_and_pause() {
-        let mut state = fixture();
-        for phase in [
-            Phase::AwaitingShortcut,
-            Phase::Recording,
-            Phase::Paused,
-            Phase::Restarting,
-            Phase::Restoring,
-        ] {
-            state.lease.as_mut().unwrap().phase = phase;
-            assert!(!state.may_reveal(1, "target-select-overlay-1"));
-        }
-    }
-
-    #[test]
-    fn restore_preserves_hidden_camera_and_rejects_replaced_native_window() {
-        for visible in [false, true] {
-            let saved = SavedWindow {
-                label: "camera".into(),
-                native_id: 42,
-                visible,
-            };
-            assert_eq!(saved.visibility_for(42), Some(visible));
-            assert_eq!(saved.visibility_for(43), None);
-        }
-    }
-
-    #[test]
-    fn startup_failure_cannot_own_a_different_pending_recording() {
-        let mut state = fixture();
-        let old = PathBuf::from("failed-start-a");
-        let new = PathBuf::from("pending-start-b");
-        state.lease.as_mut().unwrap().phase = Phase::Starting;
-        state.lease.as_mut().unwrap().recording_dir = Some(old.clone());
-        assert_eq!(state.owner(&old), Some(1));
-        assert_eq!(state.owner(&new), None);
-        state.lease.as_mut().unwrap().recording_dir = Some(new.clone());
-        state.lease.as_mut().unwrap().generation = 2;
-        state.generation = 2;
-        assert_eq!(state.owner(&old), None);
-        assert_eq!(state.owner(&new), Some(2));
-    }
-
-    #[tokio::test]
-    async fn pending_pause_does_not_reveal_main_and_retains_queued_stop_after_ack() {
-        let state = std::sync::Arc::new(Mutex::new(fixture()));
-        let dir = PathBuf::from("recording-a");
-        {
-            let mut state = state.lock().unwrap();
-            let lease = state.lease.as_mut().unwrap();
-            lease.phase = Phase::Pausing;
-            lease.recording_dir = Some(dir.clone());
-        }
-        let (acknowledge, received) = tokio::sync::oneshot::channel();
-        let pending = {
-            let state = state.clone();
-            tokio::spawn(async move {
-                received.await.unwrap();
-                state
-                    .lock()
-                    .unwrap()
-                    .complete_control(1, &dir, false, &ControlOutcome::Succeeded)
-            })
-        };
-        {
-            let mut state = state.lock().unwrap();
-            assert!(!state.may_reveal(1, "main"));
-            assert!(state.queue_stop());
-        }
-        acknowledge.send(()).unwrap();
-        assert!(pending.await.unwrap());
-        let mut state = state.lock().unwrap();
-        assert!(state.lease.as_ref().unwrap().stop_requested);
-        assert!(!state.queue_stop());
-        assert!(!state.may_reveal(1, "main"));
-    }
-
-    #[tokio::test]
-    async fn stopped_owner_rejects_delayed_resume_acknowledgement() {
-        let state = std::sync::Arc::new(Mutex::new(fixture()));
-        let dir = PathBuf::from("recording-a");
-        {
-            let mut state = state.lock().unwrap();
-            let lease = state.lease.as_mut().unwrap();
-            lease.phase = Phase::Resuming;
-            lease.recording_dir = Some(dir.clone());
-        }
-        let (acknowledge, received) = tokio::sync::oneshot::channel();
-        let pending = {
-            let state = state.clone();
-            tokio::spawn(async move {
-                received.await.unwrap();
-                state
-                    .lock()
-                    .unwrap()
-                    .complete_control(1, &dir, true, &ControlOutcome::Succeeded)
-            })
-        };
-        state.lock().unwrap().lease.as_mut().unwrap().phase = Phase::Restoring;
-        acknowledge.send(()).unwrap();
-        assert!(!pending.await.unwrap());
-        assert_eq!(
-            state.lock().unwrap().lease.as_ref().unwrap().phase,
-            Phase::Restoring
-        );
-    }
-
-    struct RunningControl {
-        state: std::sync::Arc>,
-        stages: tokio::sync::mpsc::UnboundedReceiver<&'static str>,
-        hide: Option>>,
-        change: Option>>,
-        paused: Option>,
-        reveal: Option>,
-        result: tokio::task::JoinHandle>,
-    }
-
-    impl RunningControl {
-        fn start(resume: bool) -> Self {
-            let state = std::sync::Arc::new(Mutex::new(fixture()));
-            {
-                let mut inner = state.lock().unwrap();
-                let lease = inner.lease.as_mut().unwrap();
-                lease.phase = if resume {
-                    Phase::Resuming
-                } else {
-                    Phase::Pausing
-                };
-                lease.recording_dir = Some(PathBuf::from("recording-a"));
-            }
-            let (stages, observed) = tokio::sync::mpsc::unbounded_channel();
-            let (hide, hidden) = tokio::sync::oneshot::channel();
-            let (change, changed) = tokio::sync::oneshot::channel();
-            let (paused, acknowledged) = tokio::sync::oneshot::channel();
-            let (reveal, mapping) = tokio::sync::oneshot::channel();
-            let control_state = state.clone();
-            let result = tokio::spawn(async move {
-                let dir = PathBuf::from("recording-a");
-                ControlOperation {
-                    resume,
-                    generation: 1,
-                    dir: &dir,
-                    hide: async {
-                        stages.send("hide").unwrap();
-                        hidden.await.unwrap()
-                    },
-                    change: async {
-                        stages.send("actor").unwrap();
-                        changed.await.unwrap()
-                    },
-                    paused: async {
-                        stages.send("confirm-paused").unwrap();
-                        acknowledged.await.unwrap()
-                    },
-                    restore: async {
-                        stages.send("queue-main").unwrap();
-                        mapping.await.unwrap();
-                        if control_state
-                            .lock()
-                            .unwrap()
-                            .may_restore_paused_main(1, &dir)
-                        {
-                            stages.send("show-main").unwrap();
-                            Ok(())
-                        } else {
-                            stages.send("suppress-main").unwrap();
-                            Err("Recording changed before mapping".into())
-                        }
-                    },
-                    stop: async {
-                        stages.send("stop").unwrap();
-                        assert!(!control_state.lock().unwrap().queue_stop());
-                        Ok(())
-                    },
-                    notify: || stages.send("notify").unwrap(),
-                }
-                .run(&control_state)
-                .await
-            });
-            Self {
-                state,
-                stages: observed,
-                hide: Some(hide),
-                change: Some(change),
-                paused: Some(paused),
-                reveal: Some(reveal),
-                result,
-            }
-        }
-
-        async fn dispatch_stop(
-            &self,
-        ) -> (
-            tokio::sync::oneshot::Sender<()>,
-            tokio::task::JoinHandle<()>,
-        ) {
-            {
-                let mut inner = self.state.lock().unwrap();
-                assert!(inner.shortcut(true));
-                assert!(inner.lease.as_ref().unwrap().phase.can_stop());
-                assert!(!inner.queue_stop());
-            }
-            let (entered, delivered) = tokio::sync::oneshot::channel();
-            let (acknowledge, joined) = tokio::sync::oneshot::channel();
-            let state = self.state.clone();
-            let stop = tokio::spawn(async move {
-                entered.send(()).unwrap();
-                joined.await.unwrap();
-                let mut inner = state.lock().unwrap();
-                if inner.owner(std::path::Path::new("recording-a")) == Some(1)
-                    && inner.lease.as_ref().unwrap().phase == Phase::Stopping
-                {
-                    inner.lease.as_mut().unwrap().phase = Phase::Restoring;
-                }
-            });
-            tokio::time::timeout(Duration::from_secs(1), delivered)
-                .await
-                .unwrap()
-                .unwrap();
-            (acknowledge, stop)
-        }
-
-        async fn expect(&mut self, stage: &'static str) {
-            assert_eq!(
-                tokio::time::timeout(Duration::from_secs(1), self.stages.recv())
-                    .await
-                    .unwrap(),
-                Some(stage)
-            );
-        }
-
-        async fn finish(self) -> Result<(), String> {
-            tokio::time::timeout(Duration::from_secs(1), self.result)
-                .await
-                .unwrap()
-                .unwrap()
-        }
-    }
-
-    #[tokio::test]
-    async fn resume_hide_failure_restores_main_without_calling_actor() {
-        let mut run = RunningControl::start(true);
-        run.expect("hide").await;
-        run.hide
-            .take()
-            .unwrap()
-            .send(Err("partial unmap failed".into()))
-            .unwrap();
-        run.expect("notify").await;
-        run.expect("queue-main").await;
-        {
-            let inner = run.state.lock().unwrap();
-            assert_eq!(inner.lease.as_ref().unwrap().phase, Phase::Paused);
-            assert!(!inner.may_reveal(1, "camera"));
-            assert!(!inner.may_reveal(1, "in-progress-recording"));
-            assert!(inner.lease.as_ref().unwrap().registered_shortcut);
-        }
-        run.reveal.take().unwrap().send(()).unwrap();
-        run.expect("show-main").await;
-        assert_eq!(run.finish().await.unwrap_err(), "partial unmap failed");
-    }
-
-    #[tokio::test]
-    async fn actor_resume_error_waits_for_quiescent_pause_ack_before_mapping() {
-        let mut run = RunningControl::start(true);
-        run.expect("hide").await;
-        run.hide.take().unwrap().send(Ok(())).unwrap();
-        run.expect("actor").await;
-        run.change
-            .take()
-            .unwrap()
-            .send(Err("segment setup failed".into()))
-            .unwrap();
-        run.expect("confirm-paused").await;
-        assert!(!run.state.lock().unwrap().may_reveal(1, "main"));
-        run.paused.take().unwrap().send(true).unwrap();
-        run.expect("notify").await;
-        run.expect("queue-main").await;
-        run.reveal.take().unwrap().send(()).unwrap();
-        run.expect("show-main").await;
-        assert_eq!(run.finish().await.unwrap_err(), "segment setup failed");
-    }
-
-    #[tokio::test]
-    async fn unknown_resume_error_does_not_map_and_stop_remains_executable() {
-        let mut run = RunningControl::start(true);
-        run.expect("hide").await;
-        run.hide.take().unwrap().send(Ok(())).unwrap();
-        run.expect("actor").await;
-        run.change
-            .take()
-            .unwrap()
-            .send(Err("transport failed".into()))
-            .unwrap();
-        run.expect("confirm-paused").await;
-        run.paused.take().unwrap().send(false).unwrap();
-        run.expect("notify").await;
-        let state = run.state.clone();
-        assert!(
-            run.finish()
-                .await
-                .unwrap_err()
-                .contains("pause could not be confirmed")
-        );
-        let mut state = state.lock().unwrap();
-        assert_eq!(state.lease.as_ref().unwrap().phase, Phase::ResumeFailed);
-        assert!(state.shortcut(true));
-        assert!(state.lease.as_ref().unwrap().phase.can_stop());
-        assert!(!state.may_reveal(1, "main"));
-        assert!(!state.queue_stop());
-    }
-
-    #[tokio::test]
-    async fn stop_during_hide_executes_before_resume_and_rejects_late_hide() {
-        for hidden in [Ok(()), Err("hide failed".into())] {
-            let mut run = RunningControl::start(true);
-            run.expect("hide").await;
-            let (ack, stopped) = run.dispatch_stop().await;
-            assert!(!run.result.is_finished());
-            ack.send(()).unwrap();
-            stopped.await.unwrap();
-            run.hide.take().unwrap().send(hidden).unwrap();
-            assert!(run.finish().await.unwrap_err().contains("changed during"));
-        }
-    }
-
-    #[tokio::test]
-    async fn stop_during_pause_confirmation_executes_without_waiting_for_it() {
-        for paused in [true, false] {
-            let mut run = RunningControl::start(true);
-            run.expect("hide").await;
-            run.hide.take().unwrap().send(Ok(())).unwrap();
-            run.expect("actor").await;
-            run.change
-                .take()
-                .unwrap()
-                .send(Err("setup failed".into()))
-                .unwrap();
-            run.expect("confirm-paused").await;
-            let (ack, stopped) = run.dispatch_stop().await;
-            assert!(!run.result.is_finished());
-            ack.send(()).unwrap();
-            stopped.await.unwrap();
-            run.paused.take().unwrap().send(paused).unwrap();
-            assert!(run.finish().await.unwrap_err().contains("changed during"));
-        }
-    }
-
-    #[tokio::test]
-    async fn pending_resume_does_not_block_stop_and_late_result_cannot_publish() {
-        for resumed in [Ok(()), Err("cancelled setup".into())] {
-            let mut run = RunningControl::start(true);
-            run.expect("hide").await;
-            run.hide.take().unwrap().send(Ok(())).unwrap();
-            run.expect("actor").await;
-            let (ack, stopped) = run.dispatch_stop().await;
-            assert!(!run.result.is_finished());
-            assert_eq!(
-                run.state.lock().unwrap().lease.as_ref().unwrap().phase,
-                Phase::Stopping
-            );
-            ack.send(()).unwrap();
-            stopped.await.unwrap();
-            assert!(!run.result.is_finished());
-            let failed = resumed.is_err();
-            run.change.take().unwrap().send(resumed).unwrap();
-            if failed {
-                run.expect("confirm-paused").await;
-                run.paused.take().unwrap().send(true).unwrap();
-            }
-            let state = run.state.clone();
-            assert!(run.finish().await.unwrap_err().contains("changed during"));
-            let inner = state.lock().unwrap();
-            assert_eq!(inner.lease.as_ref().unwrap().phase, Phase::Restoring);
-            assert!(inner.snapshot().error.is_none());
-        }
-    }
-
-    #[tokio::test]
-    async fn delayed_pause_confirmation_cannot_publish_to_new_owner() {
-        let mut run = RunningControl::start(true);
-        run.expect("hide").await;
-        run.hide.take().unwrap().send(Ok(())).unwrap();
-        run.expect("actor").await;
-        run.change
-            .take()
-            .unwrap()
-            .send(Err("setup failed".into()))
-            .unwrap();
-        run.expect("confirm-paused").await;
-        {
-            let mut inner = run.state.lock().unwrap();
-            inner.generation = 2;
-            let lease = inner.lease.as_mut().unwrap();
-            lease.generation = 2;
-            lease.recording_dir = Some(PathBuf::from("recording-b"));
-        }
-        run.paused.take().unwrap().send(true).unwrap();
-        let state = run.state.clone();
-        assert!(run.finish().await.unwrap_err().contains("changed during"));
-        assert_eq!(
-            state.lock().unwrap().lease.as_ref().unwrap().phase,
-            Phase::Resuming
-        );
-    }
-
-    #[tokio::test]
-    async fn delayed_main_mapping_rechecks_owner_phase_and_stop() {
-        for mutation in 0..4 {
-            let mut run = RunningControl::start(true);
-            run.expect("hide").await;
-            run.hide
-                .take()
-                .unwrap()
-                .send(Err("hide failed".into()))
-                .unwrap();
-            run.expect("notify").await;
-            run.expect("queue-main").await;
-            {
-                let mut inner = run.state.lock().unwrap();
-                match mutation {
-                    0 => {
-                        inner.generation = 2;
-                        inner.lease.as_mut().unwrap().generation = 2;
-                    }
-                    1 => {
-                        inner.lease.as_mut().unwrap().recording_dir =
-                            Some(PathBuf::from("recording-b"))
-                    }
-                    2 => inner.lease.as_mut().unwrap().phase = Phase::Resuming,
-                    _ => inner.lease.as_mut().unwrap().stop_requested = true,
-                }
-            }
-            run.reveal.take().unwrap().send(()).unwrap();
-            run.expect("suppress-main").await;
-            assert!(
-                run.finish()
-                    .await
-                    .unwrap_err()
-                    .contains("Could not restore controls")
-            );
-        }
-    }
-
-    #[tokio::test]
-    async fn ordinary_pause_and_successful_resume_never_use_failure_restore() {
-        for resume in [false, true] {
-            let mut run = RunningControl::start(resume);
-            if resume {
-                run.expect("hide").await;
-                run.hide.take().unwrap().send(Ok(())).unwrap();
-            }
-            run.expect("actor").await;
-            run.change.take().unwrap().send(Ok(())).unwrap();
-            run.expect("notify").await;
-            let state = run.state.clone();
-            assert!(run.finish().await.is_ok());
-            assert_eq!(
-                state.lock().unwrap().lease.as_ref().unwrap().phase,
-                if resume {
-                    Phase::Recording
-                } else {
-                    Phase::Paused
-                }
-            );
-        }
-    }
-
-    #[tokio::test]
-    async fn stale_hide_completion_never_invokes_actor_or_restores_main() {
-        for success in [false, true] {
-            let mut run = RunningControl::start(true);
-            run.expect("hide").await;
-            run.state.lock().unwrap().lease.as_mut().unwrap().phase = Phase::Restoring;
-            run.hide
-                .take()
-                .unwrap()
-                .send(if success {
-                    Ok(())
-                } else {
-                    Err("hide failed".into())
-                })
-                .unwrap();
-            assert!(run.finish().await.unwrap_err().contains("changed during"));
-        }
-    }
-
-    #[tokio::test]
-    async fn failed_pause_does_not_run_resume_probe_or_restore() {
-        let mut run = RunningControl::start(false);
-        run.expect("actor").await;
-        run.change
-            .take()
-            .unwrap()
-            .send(Err("pause failed".into()))
-            .unwrap();
-        run.expect("notify").await;
-        let state = run.state.clone();
-        assert_eq!(run.finish().await.unwrap_err(), "pause failed");
-        assert_eq!(
-            state.lock().unwrap().lease.as_ref().unwrap().phase,
-            Phase::Recording
-        );
-        assert!(!state.lock().unwrap().may_reveal(1, "main"));
-    }
-
-    #[test]
-    fn control_error_survives_stop_and_release_but_not_a_new_owner() {
-        let mut inner = fixture();
-        let dir = PathBuf::from("recording-a");
-        inner.lease.as_mut().unwrap().recording_dir = Some(dir.clone());
-        inner.lease.as_mut().unwrap().phase = Phase::Resuming;
-        assert!(inner.complete_control(
-            1,
-            &dir,
-            true,
-            &ControlOutcome::ActorFailed {
-                error: "capture setup failed".into(),
-                paused: false
-            }
-        ));
-        assert_eq!(
-            inner.snapshot().error.as_deref(),
-            Some("capture setup failed")
-        );
-        assert!(!inner.queue_stop());
-        assert_eq!(
-            inner.snapshot().error.as_deref(),
-            Some("capture setup failed")
-        );
-        inner.lease = None;
-        assert_eq!(
-            inner.snapshot().error.as_deref(),
-            Some("capture setup failed")
-        );
-        inner.generation = 2;
-        assert!(inner.snapshot().error.is_none());
-    }
-}
diff --git a/apps/desktop/src-tauri/src/cli.rs b/apps/desktop/src-tauri/src/cli.rs
deleted file mode 100644
index d258d170dd0..00000000000
--- a/apps/desktop/src-tauri/src/cli.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-pub use cap_cli_install::CliInstallStatus;
-
-#[tauri::command]
-#[specta::specta]
-pub fn get_cli_install_status() -> Result {
-    cap_cli_install::status()
-}
-
-#[tauri::command]
-#[specta::specta]
-pub fn install_cli() -> Result {
-    cap_cli_install::install()
-}
-
-#[tauri::command]
-#[specta::specta]
-pub fn uninstall_cli() -> Result {
-    cap_cli_install::uninstall()
-}
diff --git a/apps/desktop/src-tauri/src/clip_thumbnails.rs b/apps/desktop/src-tauri/src/clip_thumbnails.rs
deleted file mode 100644
index 65860a5ad13..00000000000
--- a/apps/desktop/src-tauri/src/clip_thumbnails.rs
+++ /dev/null
@@ -1,455 +0,0 @@
-use std::{path::Path, sync::LazyLock};
-
-use cap_project::{RecordingMetaInner, StudioRecordingMeta};
-use tokio::sync::Semaphore;
-
-use crate::editor_window::WindowEditorInstance;
-
-const THUMB_MAX_WIDTH: u32 = 240;
-const THUMB_JPEG_QUALITY: u8 = 70;
-const SEEK_DECODE_PACKET_LIMIT: usize = 4096;
-const SEEK_DECODE_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(2);
-
-static THUMBNAIL_SEMAPHORE: LazyLock = LazyLock::new(|| Semaphore::new(4));
-
-#[tauri::command]
-#[specta::specta]
-#[tracing::instrument(skip(editor_instance))]
-pub async fn get_clip_thumbnail(
-    editor_instance: WindowEditorInstance,
-    recording_segment: u32,
-    time: f64,
-) -> Result {
-    let project_path = editor_instance.project_path.clone();
-    let meta = editor_instance.meta();
-
-    let RecordingMetaInner::Studio(studio) = &meta.inner else {
-        return Err("Clip thumbnails are only available for studio recordings".to_string());
-    };
-
-    let display_path = match studio.as_ref() {
-        StudioRecordingMeta::SingleSegment { segment } => meta.path(&segment.display.path),
-        StudioRecordingMeta::MultipleSegments { inner } => {
-            let segment = inner
-                .segments
-                .get(recording_segment as usize)
-                .ok_or_else(|| format!("Recording segment {recording_segment} not found"))?;
-            meta.path(&segment.display.path)
-        }
-    };
-
-    let time = time.max(0.0);
-    let cache_path = project_path
-        .join("thumbnails")
-        .join("clips-v2")
-        .join(format!(
-            "seg{recording_segment}_{}.jpg",
-            (time * 1000.0).round() as i64
-        ));
-
-    if tokio::fs::try_exists(&cache_path).await.unwrap_or(false) {
-        return Ok(cache_path.to_string_lossy().into_owned());
-    }
-
-    let permit = THUMBNAIL_SEMAPHORE
-        .acquire()
-        .await
-        .map_err(|e| format!("Failed to acquire thumbnail permit: {e}"))?;
-
-    if tokio::fs::try_exists(&cache_path).await.unwrap_or(false) {
-        return Ok(cache_path.to_string_lossy().into_owned());
-    }
-
-    let output = cache_path.clone();
-    tokio::task::spawn_blocking(move || {
-        let _permit = permit;
-        decode_clip_thumbnail(&display_path, time, &output)
-    })
-    .await
-    .map_err(|e| format!("Thumbnail task failed: {e}"))??;
-
-    Ok(cache_path.to_string_lossy().into_owned())
-}
-
-fn decode_clip_thumbnail(input: &Path, time: f64, output: &Path) -> Result<(), String> {
-    decode_clip_thumbnail_with_budget(
-        input,
-        time,
-        output,
-        SEEK_DECODE_PACKET_LIMIT,
-        SEEK_DECODE_TIMEOUT,
-    )
-}
-
-fn decode_clip_thumbnail_with_budget(
-    input: &Path,
-    time: f64,
-    output: &Path,
-    packet_limit: usize,
-    timeout: std::time::Duration,
-) -> Result<(), String> {
-    use ffmpeg::rescale::{Rescale, TIME_BASE};
-
-    let mut ictx =
-        ffmpeg::format::input(input).map_err(|e| format!("Failed to open video: {e}"))?;
-
-    let stream = ictx
-        .streams()
-        .best(ffmpeg::media::Type::Video)
-        .ok_or("No video stream found")?;
-    let stream_index = stream.index();
-    let stream_time_base = stream.time_base();
-    let stream_start = match stream.start_time() {
-        ffmpeg::ffi::AV_NOPTS_VALUE => 0,
-        timestamp => timestamp,
-    };
-    let target_timestamp = ((time * 1_000_000.0) as i64)
-        .rescale((1, 1_000_000), stream_time_base)
-        .saturating_add(stream_start);
-
-    let mut decoder = ffmpeg::codec::context::Context::from_parameters(stream.parameters())
-        .map_err(|e| e.to_string())?
-        .decoder()
-        .video()
-        .map_err(|e| e.to_string())?;
-
-    let src_width = decoder.width();
-    let src_height = decoder.height();
-    if src_width == 0 || src_height == 0 {
-        return Err("Invalid video dimensions".to_string());
-    }
-
-    let scale = (THUMB_MAX_WIDTH as f32 / src_width as f32).min(1.0);
-    let target_width = ((src_width as f32 * scale).round() as u32).max(1);
-    let target_height = ((src_height as f32 * scale).round() as u32).max(1);
-
-    let mut scaler = ffmpeg::software::scaling::context::Context::get(
-        decoder.format(),
-        src_width,
-        src_height,
-        ffmpeg::format::Pixel::RGB24,
-        target_width,
-        target_height,
-        ffmpeg::software::scaling::flag::Flags::BILINEAR,
-    )
-    .map_err(|e| e.to_string())?;
-
-    if time > 0.0 {
-        let position_us = (time * 1_000_000.0) as i64;
-        let seek_target = target_timestamp.rescale(stream_time_base, TIME_BASE);
-        decoder.flush();
-        ictx.seek(seek_target, ..seek_target)
-            .map_err(|e| format!("Failed to seek to {position_us}us: {e}"))?;
-    }
-
-    let mut frame = ffmpeg::frame::Video::empty();
-    let mut decoded = ffmpeg::frame::Video::empty();
-    let mut got_frame = false;
-    let mut reached_target = false;
-    let mut decoder_finished = false;
-    let mut packets_tried = 0usize;
-    let decode_started = std::time::Instant::now();
-
-    'outer: for (packet_stream, packet) in ictx.packets() {
-        if decode_started.elapsed() >= timeout {
-            return Err("Thumbnail decode time budget exhausted".to_string());
-        }
-        if packet_stream.index() != stream_index {
-            continue;
-        }
-
-        packets_tried += 1;
-
-        if decoder.send_packet(&packet).is_err() {
-            if packets_tried >= packet_limit {
-                return Err("Thumbnail decode packet budget exhausted".to_string());
-            }
-            continue;
-        }
-
-        loop {
-            if decode_started.elapsed() >= timeout {
-                return Err("Thumbnail decode time budget exhausted".to_string());
-            }
-            match decoder.receive_frame(&mut decoded) {
-                Ok(()) => {
-                    std::mem::swap(&mut frame, &mut decoded);
-                    got_frame = true;
-                    if thumbnail_frame_reaches_target(&frame, target_timestamp) {
-                        reached_target = true;
-                        break 'outer;
-                    }
-                }
-                Err(ffmpeg::Error::Other { errno }) if errno == ffmpeg::ffi::EAGAIN => break,
-                Err(ffmpeg::Error::Eof) => {
-                    decoder_finished = true;
-                    break 'outer;
-                }
-                Err(e) => {
-                    if packets_tried >= packet_limit {
-                        return Err(format!("Failed to decode frame: {e}"));
-                    }
-                    break;
-                }
-            }
-        }
-
-        if packets_tried >= packet_limit {
-            return Err("Thumbnail decode packet budget exhausted".to_string());
-        }
-    }
-
-    if !reached_target && !decoder_finished {
-        decoder
-            .send_eof()
-            .map_err(|e| format!("Failed to flush decoder: {e}"))?;
-        loop {
-            if decode_started.elapsed() >= timeout {
-                return Err("Thumbnail decode time budget exhausted".to_string());
-            }
-            match decoder.receive_frame(&mut decoded) {
-                Ok(()) => {
-                    std::mem::swap(&mut frame, &mut decoded);
-                    got_frame = true;
-                    if thumbnail_frame_reaches_target(&frame, target_timestamp) {
-                        break;
-                    }
-                }
-                Err(ffmpeg::Error::Eof) => break,
-                Err(ffmpeg::Error::Other { errno }) if errno == ffmpeg::ffi::EAGAIN => break,
-                Err(e) => return Err(format!("Failed to flush decoder: {e}")),
-            }
-        }
-    }
-
-    if !got_frame {
-        return Err("No decodable frames found".to_string());
-    }
-
-    let mut rgb_frame = ffmpeg::frame::Video::empty();
-    scaler
-        .run(&frame, &mut rgb_frame)
-        .map_err(|e| e.to_string())?;
-
-    let width = rgb_frame.width() as usize;
-    let height = rgb_frame.height() as usize;
-    let src_stride = rgb_frame.stride(0);
-    let dst_stride = width * 3;
-    if src_stride < dst_stride {
-        return Err(format!(
-            "Unexpected RGB stride: src_stride={src_stride}, expected >= {dst_stride}"
-        ));
-    }
-    let mut img_buffer = vec![0u8; height * dst_stride];
-    for y in 0..height {
-        let src_slice = &rgb_frame.data(0)[y * src_stride..y * src_stride + dst_stride];
-        img_buffer[y * dst_stride..(y + 1) * dst_stride].copy_from_slice(src_slice);
-    }
-
-    use image::ImageEncoder;
-
-    let mut jpeg_bytes = Vec::new();
-    image::codecs::jpeg::JpegEncoder::new_with_quality(&mut jpeg_bytes, THUMB_JPEG_QUALITY)
-        .write_image(
-            &img_buffer,
-            width as u32,
-            height as u32,
-            image::ExtendedColorType::Rgb8,
-        )
-        .map_err(|e| format!("Failed to encode thumbnail: {e}"))?;
-
-    persist_clip_thumbnail(output, &jpeg_bytes)
-}
-
-fn thumbnail_frame_reaches_target(frame: &ffmpeg::frame::Video, target_timestamp: i64) -> bool {
-    frame
-        .timestamp()
-        .or_else(|| frame.pts())
-        .is_none_or(|timestamp| timestamp >= target_timestamp)
-}
-
-fn persist_clip_thumbnail(output: &Path, jpeg_bytes: &[u8]) -> Result<(), String> {
-    use std::io::Write;
-
-    let parent = output.parent().unwrap_or_else(|| Path::new("."));
-    std::fs::create_dir_all(parent)
-        .map_err(|e| format!("Failed to create thumbnail directory: {e}"))?;
-
-    let mut staged = tempfile::NamedTempFile::new_in(parent)
-        .map_err(|e| format!("Failed to stage thumbnail: {e}"))?;
-    staged
-        .write_all(jpeg_bytes)
-        .map_err(|e| format!("Failed to write thumbnail: {e}"))?;
-    staged
-        .persist(output)
-        .map_err(|e| format!("Failed to persist thumbnail: {e}"))?;
-
-    Ok(())
-}
-
-#[cfg(test)]
-mod persistence_tests {
-    use super::*;
-    use std::sync::{Arc, Barrier};
-
-    #[test]
-    fn concurrent_identical_thumbnails_are_all_persisted() {
-        let root = tempfile::tempdir().unwrap();
-        let output = root.path().join("clips").join("segment.jpg");
-        let barrier = Arc::new(Barrier::new(4));
-        let pixels = [35; 24 * 24 * 3];
-        let mut jpeg = Vec::new();
-        image::codecs::jpeg::JpegEncoder::new(&mut jpeg)
-            .encode(&pixels, 24, 24, image::ExtendedColorType::Rgb8)
-            .unwrap();
-
-        std::thread::scope(|scope| {
-            let tasks = (0..4)
-                .map(|_| {
-                    let output = &output;
-                    let jpeg = &jpeg;
-                    let barrier = barrier.clone();
-                    scope.spawn(move || {
-                        barrier.wait();
-                        persist_clip_thumbnail(output, jpeg)
-                    })
-                })
-                .collect::>();
-
-            for task in tasks {
-                task.join().unwrap().unwrap();
-            }
-        });
-
-        assert_eq!(std::fs::read(&output).unwrap(), jpeg);
-        assert_eq!(image::open(&output).unwrap().width(), 24);
-        assert_eq!(
-            std::fs::read_dir(output.parent().unwrap()).unwrap().count(),
-            1
-        );
-    }
-
-    #[test]
-    fn replacing_cached_thumbnail_preserves_contents() {
-        let root = tempfile::tempdir().unwrap();
-        let output = root.path().join("segment.jpg");
-        persist_clip_thumbnail(&output, b"old thumbnail").unwrap();
-        persist_clip_thumbnail(&output, b"replacement thumbnail").unwrap();
-        assert_eq!(std::fs::read(&output).unwrap(), b"replacement thumbnail");
-        assert_eq!(std::fs::read_dir(root.path()).unwrap().count(), 1);
-    }
-}
-
-#[cfg(test)]
-mod decoding_tests {
-    use super::*;
-    use std::{
-        path::PathBuf,
-        sync::{Arc, Barrier},
-    };
-
-    fn fixture() -> (tempfile::TempDir, PathBuf) {
-        fixture_from_bytes(include_bytes!("../test-data/clip-thumbnail-gop.mp4"))
-    }
-
-    fn fixture_from_bytes(bytes: &[u8]) -> (tempfile::TempDir, PathBuf) {
-        ffmpeg::init().unwrap();
-        let root = tempfile::tempdir().unwrap();
-        let input = root.path().join("gop.mp4");
-        std::fs::write(&input, bytes).unwrap();
-        (root, input)
-    }
-
-    #[test]
-    fn split_thumbnails_use_requested_time_inside_keyframe_interval() {
-        let (root, input) = fixture();
-        for (time, expected_channel) in [(0.0, 0), (1.5, 1), (2.5, 2), (3.0, 2)] {
-            let output = root.path().join(format!("{time}.jpg"));
-            decode_clip_thumbnail(&input, time, &output).unwrap();
-            let image = image::open(&output).unwrap().to_rgb8();
-            let pixel = image.get_pixel(80, 45).0;
-            assert!(
-                pixel[expected_channel] > 100,
-                "requested {time}s, got {pixel:?}"
-            );
-            for (channel, value) in pixel.iter().enumerate() {
-                if channel != expected_channel {
-                    assert!(*value < 20, "requested {time}s, got {pixel:?}");
-                }
-            }
-        }
-    }
-
-    #[test]
-    fn simultaneous_decodes_of_one_clip_all_produce_valid_thumbnail() {
-        let (root, input) = fixture();
-        let output = root.path().join("same-clip.jpg");
-        let barrier = Arc::new(Barrier::new(4));
-
-        std::thread::scope(|scope| {
-            let tasks = (0..4)
-                .map(|_| {
-                    let input = &input;
-                    let output = &output;
-                    let barrier = barrier.clone();
-                    scope.spawn(move || {
-                        barrier.wait();
-                        decode_clip_thumbnail(input, 1.5, output)
-                    })
-                })
-                .collect::>();
-            for task in tasks {
-                task.join().unwrap().unwrap();
-            }
-        });
-
-        let image = image::open(output).unwrap().to_rgb8();
-        let pixel = image.get_pixel(80, 45).0;
-        assert!(pixel[1] > 100 && pixel[0] < 20 && pixel[2] < 20);
-    }
-
-    #[test]
-    fn long_gop_thumbnails_reach_requested_time_and_preserve_eof_fallback() {
-        let (root, input) =
-            fixture_from_bytes(include_bytes!("../test-data/clip-thumbnail-long-gop.mp4"));
-        for time in [8.5, 10.0, 11.0] {
-            let output = root.path().join(format!("{time}.jpg"));
-            decode_clip_thumbnail(&input, time, &output).unwrap();
-            let pixel = image::open(&output).unwrap().to_rgb8().get_pixel(80, 45).0;
-            assert!(
-                pixel[2] > 100 && pixel[1] < 20 && pixel[0] < 20,
-                "requested {time}s, got {pixel:?}"
-            );
-        }
-    }
-
-    #[test]
-    fn exhausted_decode_budget_does_not_write_partial_thumbnail() {
-        let (root, input) =
-            fixture_from_bytes(include_bytes!("../test-data/clip-thumbnail-long-gop.mp4"));
-        let output = root.path().join("thumbnail.jpg");
-        for (packet_limit, timeout, expected_error) in [
-            (240, std::time::Duration::from_secs(2), "packet budget"),
-            (
-                SEEK_DECODE_PACKET_LIMIT,
-                std::time::Duration::ZERO,
-                "time budget",
-            ),
-        ] {
-            let result =
-                decode_clip_thumbnail_with_budget(&input, 8.5, &output, packet_limit, timeout);
-            assert!(result.unwrap_err().contains(expected_error));
-            assert!(!output.exists());
-        }
-    }
-
-    #[test]
-    fn frames_without_timestamps_preserve_first_frame_fallback() {
-        let mut frame = ffmpeg::frame::Video::empty();
-        assert!(thumbnail_frame_reaches_target(&frame, 100));
-        frame.set_pts(Some(99));
-        assert!(!thumbnail_frame_reaches_target(&frame, 100));
-        frame.set_pts(Some(100));
-        assert!(thumbnail_frame_reaches_target(&frame, 100));
-    }
-}
diff --git a/apps/desktop/src-tauri/src/crash_sentinel.rs b/apps/desktop/src-tauri/src/crash_sentinel.rs
deleted file mode 100644
index 8a49480bcb4..00000000000
--- a/apps/desktop/src-tauri/src/crash_sentinel.rs
+++ /dev/null
@@ -1,377 +0,0 @@
-//! Detects sessions that ended without a clean shutdown.
-//!
-//! A whole class of failures never reaches Sentry's panic hook because the process
-//! is killed without panicking: a macOS WindowServer/GPU wedge that soft-restarts the
-//! login session, an OOM kill, a force-quit, or power loss. We catch those after the
-//! fact: every launch arms a sentinel file with this session's context, and a clean
-//! shutdown disarms it. If a launch finds a sentinel left over from a previous run,
-//! that run died unexpectedly — report it to Sentry with the captured context.
-
-use std::{
-    path::{Path, PathBuf},
-    sync::Mutex,
-};
-
-use serde::{Deserialize, Serialize};
-
-const SENTINEL_FILE: &str = "session-active.json";
-
-#[derive(Serialize, Deserialize, Clone)]
-struct SessionRecord {
-    pid: u32,
-    started_at: String,
-    app_version: String,
-    os: String,
-    arch: String,
-    #[serde(default)]
-    liquid_glass: String,
-    /// True while GPU adapter/device initialisation is in flight. If the process
-    /// dies inside that window, the next launch treats the death as a
-    /// graphics-init crash (the only case that justifies software-rendering
-    /// recovery); a death at any other time says nothing about the GPU.
-    #[serde(default)]
-    gpu_init_phase: bool,
-    /// True when this session was already running in software-graphics recovery
-    /// mode, so a follow-up crash doesn't chain into recovery forever.
-    #[serde(default)]
-    graphics_recovery: bool,
-    /// True while any camera-background-blur processor is alive (ONNX/DirectML
-    /// session + dedicated GPU work), and for a linger period after the last
-    /// one is released — deferred driver/D3D12 faults have been observed
-    /// killing the process tens of seconds after blur teardown. Native crashes
-    /// in that stack never reach a panic handler; if the process dies inside
-    /// this window the next launch attributes the death to blur and disables it.
-    #[serde(default)]
-    blur_active: bool,
-    /// True when this session already ran with blur disabled by crash recovery,
-    /// for diagnostics on the next-launch report.
-    #[serde(default)]
-    blur_recovery: bool,
-}
-
-struct ActiveSession {
-    path: PathBuf,
-    record: SessionRecord,
-    gpu_init_depth: u32,
-    blur_session_depth: u32,
-    /// Bumped on every blur enter/exit so a scheduled linger-disarm can tell
-    /// whether blur activity happened after it was scheduled.
-    blur_generation: u64,
-}
-
-static SESSION: Mutex> = Mutex::new(None);
-
-/// How the previous session died, as reconstructed from its surviving sentinel.
-/// Only the Windows graphics-recovery path consumes the fields today.
-#[derive(Clone, Copy)]
-#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
-pub struct UnexpectedTermination {
-    /// The process died while GPU adapter/device initialisation was in flight.
-    pub during_gpu_init: bool,
-    /// The session was already running in software-graphics recovery mode.
-    pub in_graphics_recovery: bool,
-    /// The process died while a camera-background-blur processor was alive.
-    pub blur_active: bool,
-}
-
-/// Arm the sentinel for this session and, if a previous session's sentinel survived,
-/// report that unexpected termination to Sentry. Call once at startup, after Sentry
-/// is initialised. Returns details of the previous session's unexpected termination,
-/// or `None` if the previous session shut down cleanly.
-pub fn init(logs_dir: Option<&Path>, app_version: &str) -> Option {
-    let os = format!(
-        "{} {}",
-        tauri_plugin_os::platform(),
-        tauri_plugin_os::version()
-    );
-    let arch = tauri_plugin_os::arch().to_string();
-    sentry::configure_scope(|scope| {
-        scope.set_tag("os.full", &os);
-        scope.set_tag("arch", &arch);
-        scope.set_tag("app.version", app_version);
-    });
-
-    let path = logs_dir?.join(SENTINEL_FILE);
-    let mut previous_termination = None;
-
-    if let Ok(contents) = std::fs::read_to_string(&path) {
-        match serde_json::from_str::(&contents) {
-            // A live process still owns this sentinel — almost certainly a
-            // single-instance double launch (this init runs before the
-            // single-instance plugin loads), not a crash. Leave it untouched and
-            // don't arm a competing sentinel for this about-to-exit instance.
-            Ok(prev) if process_is_running(prev.pid) => return None,
-            Ok(prev) => {
-                report_unexpected_termination(&prev);
-                previous_termination = Some(UnexpectedTermination {
-                    during_gpu_init: prev.gpu_init_phase,
-                    in_graphics_recovery: prev.graphics_recovery,
-                    blur_active: prev.blur_active,
-                });
-            }
-            Err(error) => {
-                tracing::warn!(%error, "Found unreadable crash sentinel from previous session")
-            }
-        }
-        let _ = std::fs::remove_file(&path);
-    }
-
-    let record = SessionRecord {
-        pid: std::process::id(),
-        started_at: chrono::Utc::now().to_rfc3339(),
-        app_version: app_version.to_string(),
-        os: os.clone(),
-        arch: arch.clone(),
-        liquid_glass: "unknown".to_string(),
-        gpu_init_phase: false,
-        graphics_recovery: false,
-        blur_active: false,
-        blur_recovery: false,
-    };
-
-    write_record(&path, &record);
-
-    *SESSION.lock().unwrap() = Some(ActiveSession {
-        path,
-        record,
-        gpu_init_depth: 0,
-        blur_session_depth: 0,
-        blur_generation: 0,
-    });
-
-    previous_termination
-}
-
-/// Arm the GPU-init marker while adapter/device initialisation runs. If the process
-/// dies inside this window the next launch sees `during_gpu_init` and can engage
-/// graphics recovery. Nestable; the marker persists until the last exit call.
-pub fn enter_gpu_init_phase() {
-    if let Ok(mut guard) = SESSION.lock()
-        && let Some(session) = guard.as_mut()
-    {
-        session.gpu_init_depth += 1;
-        if !session.record.gpu_init_phase {
-            session.record.gpu_init_phase = true;
-            write_record(&session.path, &session.record);
-        }
-    }
-}
-
-/// Disarm the GPU-init marker once initialisation finished (successfully or not —
-/// a survivable failure is not a crash).
-pub fn exit_gpu_init_phase() {
-    if let Ok(mut guard) = SESSION.lock()
-        && let Some(session) = guard.as_mut()
-    {
-        session.gpu_init_depth = session.gpu_init_depth.saturating_sub(1);
-        if session.gpu_init_depth == 0 && session.record.gpu_init_phase {
-            session.record.gpu_init_phase = false;
-            write_record(&session.path, &session.record);
-        }
-    }
-}
-
-/// How long `blur_active` stays armed after the last blur processor is
-/// released. Deferred D3D12/DML/driver faults have been observed killing the
-/// process up to ~50s after blur teardown finished (the fault surfaces
-/// asynchronously); disarming immediately would miss exactly those deaths and
-/// leave the crash loop unbroken.
-const BLUR_DISARM_LINGER: std::time::Duration = std::time::Duration::from_secs(120);
-
-/// Arm the blur marker while a camera-background-blur processor is alive. If the
-/// process dies inside this window the next launch sees `blur_active` and can
-/// disable blur. Nestable (editor render + camera preview can overlap); the
-/// marker persists until a linger period after the last exit call.
-pub fn enter_blur_session() {
-    if let Ok(mut guard) = SESSION.lock()
-        && let Some(session) = guard.as_mut()
-    {
-        session.blur_session_depth += 1;
-        session.blur_generation = session.blur_generation.wrapping_add(1);
-        if !session.record.blur_active {
-            session.record.blur_active = true;
-            write_record(&session.path, &session.record);
-        }
-    }
-}
-
-/// Schedule the blur marker to disarm once the linger window passes with no new
-/// blur session. The generation check makes a stale disarm from an earlier
-/// exit a no-op if blur was re-armed in the meantime.
-pub fn exit_blur_session() {
-    let scheduled_generation = {
-        let Ok(mut guard) = SESSION.lock() else {
-            return;
-        };
-        let Some(session) = guard.as_mut() else {
-            return;
-        };
-        session.blur_session_depth = session.blur_session_depth.saturating_sub(1);
-        session.blur_generation = session.blur_generation.wrapping_add(1);
-        if session.blur_session_depth != 0 || !session.record.blur_active {
-            return;
-        }
-        session.blur_generation
-    };
-
-    std::thread::spawn(move || {
-        std::thread::sleep(BLUR_DISARM_LINGER);
-        if let Ok(mut guard) = SESSION.lock()
-            && let Some(session) = guard.as_mut()
-            && session.blur_generation == scheduled_generation
-            && session.blur_session_depth == 0
-            && session.record.blur_active
-        {
-            session.record.blur_active = false;
-            write_record(&session.path, &session.record);
-        }
-    });
-}
-
-/// Record that this session is running with camera background blur disabled by
-/// crash recovery, for diagnostics on a follow-up unexpected-termination report.
-pub fn mark_blur_recovery() {
-    if let Ok(mut guard) = SESSION.lock()
-        && let Some(session) = guard.as_mut()
-        && !session.record.blur_recovery
-    {
-        session.record.blur_recovery = true;
-        write_record(&session.path, &session.record);
-    }
-
-    sentry::configure_scope(|scope| {
-        scope.set_tag("camera_blur_recovery", "true");
-    });
-}
-
-/// Record that this session is running in software-graphics recovery mode, so an
-/// unexpected termination of *this* session doesn't chain into recovery again.
-#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
-pub fn mark_graphics_recovery() {
-    if let Ok(mut guard) = SESSION.lock()
-        && let Some(session) = guard.as_mut()
-        && !session.record.graphics_recovery
-    {
-        session.record.graphics_recovery = true;
-        write_record(&session.path, &session.record);
-    }
-
-    sentry::configure_scope(|scope| {
-        scope.set_tag("graphics_recovery", "true");
-    });
-}
-
-/// Record the result of the macOS Liquid Glass material attempt so that, if this
-/// session dies unexpectedly, the next-launch report names which cohort it was in.
-/// `outcome` is one of "applied", "fallback", or "unsupported".
-#[cfg(target_os = "macos")]
-pub fn set_liquid_glass_outcome(outcome: &str) {
-    if let Ok(mut guard) = SESSION.lock()
-        && let Some(session) = guard.as_mut()
-        && session.record.liquid_glass != outcome
-    {
-        session.record.liquid_glass = outcome.to_string();
-        write_record(&session.path, &session.record);
-    }
-
-    sentry::configure_scope(|scope| {
-        scope.set_tag("macos_liquid_glass", outcome);
-    });
-}
-
-/// Disarm the sentinel after a fully graceful shutdown. If this is never reached (the
-/// process was killed, or shutdown hung past the watchdog) the surviving sentinel is
-/// what the next launch reports.
-pub fn mark_clean_exit() {
-    if let Ok(mut guard) = SESSION.lock()
-        && let Some(session) = guard.take()
-    {
-        let _ = std::fs::remove_file(&session.path);
-    }
-}
-
-fn report_unexpected_termination(prev: &SessionRecord) {
-    tracing::error!(
-        prev_pid = prev.pid,
-        prev_started_at = %prev.started_at,
-        prev_os = %prev.os,
-        prev_liquid_glass = %prev.liquid_glass,
-        prev_gpu_init_phase = prev.gpu_init_phase,
-        prev_graphics_recovery = prev.graphics_recovery,
-        prev_blur_active = prev.blur_active,
-        prev_blur_recovery = prev.blur_recovery,
-        "Previous Cap session terminated without a clean shutdown"
-    );
-
-    sentry::with_scope(
-        |scope| {
-            scope.set_tag("unexpected_termination", "true");
-            scope.set_tag("prev.os", &prev.os);
-            scope.set_tag("prev.arch", &prev.arch);
-            scope.set_tag("prev.app_version", &prev.app_version);
-            scope.set_tag("prev.macos_liquid_glass", &prev.liquid_glass);
-            scope.set_tag("prev.gpu_init_phase", prev.gpu_init_phase.to_string());
-            scope.set_tag("prev.graphics_recovery", prev.graphics_recovery.to_string());
-            scope.set_tag("prev.blur_active", prev.blur_active.to_string());
-            scope.set_tag("prev.blur_recovery", prev.blur_recovery.to_string());
-            scope.set_extra("prev.pid", prev.pid.into());
-            scope.set_extra("prev.started_at", prev.started_at.clone().into());
-        },
-        || {
-            sentry::capture_message(
-                "Cap session terminated unexpectedly (no clean shutdown)",
-                sentry::Level::Error,
-            );
-        },
-    );
-}
-
-fn process_is_running(pid: u32) -> bool {
-    let pid = sysinfo::Pid::from_u32(pid);
-    let mut system = sysinfo::System::new();
-    system.refresh_processes(sysinfo::ProcessesToUpdate::Some(&[pid]), true);
-    system.process(pid).is_some()
-}
-
-fn write_record(path: &Path, record: &SessionRecord) {
-    match serde_json::to_string(record) {
-        Ok(json) => {
-            if let Err(error) = std::fs::write(path, json) {
-                tracing::warn!(%error, "Failed to write crash sentinel");
-            }
-        }
-        Err(error) => tracing::warn!(%error, "Failed to serialize crash sentinel"),
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn sentinel_is_disabled_without_a_directory_and_works_when_available() {
-        assert!(init(None, "test").is_none());
-        assert!(SESSION.lock().unwrap().is_none());
-        enter_gpu_init_phase();
-        exit_gpu_init_phase();
-        enter_blur_session();
-        exit_blur_session();
-        mark_clean_exit();
-        assert!(SESSION.lock().unwrap().is_none());
-
-        let directory = tempfile::tempdir().unwrap();
-        let path = directory.path().join(SENTINEL_FILE);
-        assert!(init(Some(directory.path()), "test").is_none());
-        let read_record = || {
-            serde_json::from_str::(&std::fs::read_to_string(&path).unwrap()).unwrap()
-        };
-        assert_eq!(read_record().app_version, "test");
-        enter_gpu_init_phase();
-        assert!(read_record().gpu_init_phase);
-        exit_gpu_init_phase();
-        assert!(!read_record().gpu_init_phase);
-        mark_clean_exit();
-        assert!(!path.exists());
-        assert!(SESSION.lock().unwrap().is_none());
-    }
-}
diff --git a/apps/desktop/src-tauri/src/deeplink_actions.rs b/apps/desktop/src-tauri/src/deeplink_actions.rs
deleted file mode 100644
index 5372d58785f..00000000000
--- a/apps/desktop/src-tauri/src/deeplink_actions.rs
+++ /dev/null
@@ -1,558 +0,0 @@
-use cap_recording::{
-    RecordingMode, feeds::camera::DeviceOrModelID, sources::screen_capture::ScreenCaptureTarget,
-};
-use serde::{Deserialize, Serialize};
-use std::path::{Path, PathBuf};
-use tauri::{AppHandle, Manager, Url};
-use tracing::trace;
-
-use crate::{App, ArcLock, recording::StartRecordingInputs, windows::ShowCapWindow};
-
-#[cfg(debug_assertions)]
-use tauri::Emitter;
-
-#[cfg(debug_assertions)]
-use crate::camera::CameraPreviewState;
-
-#[cfg(debug_assertions)]
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
-pub struct CaptureArea {
-    screen: String,
-    x: f64,
-    y: f64,
-    width: f64,
-    height: f64,
-}
-
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
-#[serde(rename_all = "snake_case")]
-pub enum CaptureMode {
-    Screen(String),
-    Window(String),
-    #[cfg(debug_assertions)]
-    Area(Box),
-    #[cfg(debug_assertions)]
-    CameraOnly,
-}
-
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
-#[serde(rename_all = "snake_case")]
-pub enum DeepLinkAction {
-    StartRecording {
-        capture_mode: CaptureMode,
-        camera: Option,
-        mic_label: Option,
-        capture_system_audio: bool,
-        mode: RecordingMode,
-    },
-    StopRecording,
-    #[cfg(debug_assertions)]
-    PauseRecording,
-    #[cfg(debug_assertions)]
-    ResumeRecording,
-    #[cfg(debug_assertions)]
-    OpenCamera {
-        camera: DeviceOrModelID,
-    },
-    #[cfg(debug_assertions)]
-    SetCameraPreviewState {
-        state: CameraPreviewState,
-    },
-    #[cfg(debug_assertions)]
-    SetRecordingInputs {
-        camera: Option,
-        mic_label: Option,
-    },
-    #[cfg(debug_assertions)]
-    SetEditorPlayback {
-        project_path: PathBuf,
-        playing: bool,
-    },
-    #[cfg(debug_assertions)]
-    CloseEditor {
-        project_path: PathBuf,
-    },
-    OpenEditor {
-        project_path: PathBuf,
-    },
-    OpenSettings {
-        page: Option,
-    },
-}
-
-pub struct DeepLinkActionExecutor {
-    tx: std::sync::mpsc::Sender,
-}
-
-impl DeepLinkActionExecutor {
-    pub fn new(app: &AppHandle) -> Self {
-        let (tx, rx) = std::sync::mpsc::channel::();
-        let app_handle = app.clone();
-        let runtime = tokio::runtime::Handle::current();
-
-        trace!("Starting deep link action executor");
-        let thread = std::thread::Builder::new().name("deep-link-action-executor".to_string());
-        // Debug recording futures overflow the default thread stack; match Tauri's worker stack.
-        #[cfg(debug_assertions)]
-        let thread = thread.stack_size(16 * 1024 * 1024);
-        let thread_result = thread.spawn(move || {
-            trace!("Deep link action executor started");
-            for action in rx {
-                trace!(?action, "Executing deep link action");
-                if let Err(err) = runtime.block_on(action.execute(&app_handle)) {
-                    eprintln!("Failed to handle deep link action: {err}");
-                }
-            }
-        });
-
-        if let Err(err) = thread_result {
-            eprintln!("Failed to start deep link action executor: {err}");
-        }
-
-        Self { tx }
-    }
-
-    fn dispatch(
-        &self,
-        action: DeepLinkAction,
-    ) -> Result<(), std::sync::mpsc::SendError> {
-        self.tx.send(action)
-    }
-}
-
-pub fn handle(app_handle: &AppHandle, urls: Vec) {
-    trace!("Handling deep actions for: {:?}", &urls);
-
-    let actions: Vec<_> = urls
-        .into_iter()
-        .filter(|url| !url.as_str().is_empty())
-        .filter_map(|url| {
-            DeepLinkAction::try_from(&url)
-                .map_err(|e| match e {
-                    ActionParseFromUrlError::ParseFailed(msg) => {
-                        eprintln!("Failed to parse deep link \"{}\": {}", &url, msg)
-                    }
-                    ActionParseFromUrlError::Invalid => {
-                        eprintln!("Invalid deep link format \"{}\"", &url)
-                    }
-                    // Likely login action, not handled here.
-                    ActionParseFromUrlError::NotAction => {}
-                })
-                .ok()
-        })
-        .collect();
-
-    trace!(action_count = actions.len(), "Parsed deep link actions");
-
-    if actions.is_empty() {
-        return;
-    }
-
-    let Some(executor) = app_handle.try_state::() else {
-        eprintln!("Deep link action executor unavailable");
-        return;
-    };
-
-    for action in actions {
-        trace!(?action, "Queueing deep link action");
-        if let Err(err) = executor.dispatch(action) {
-            eprintln!("Failed to queue deep link action: {err}");
-        }
-    }
-}
-
-#[derive(Debug, PartialEq, Eq)]
-pub enum ActionParseFromUrlError {
-    ParseFailed(String),
-    Invalid,
-    NotAction,
-}
-
-impl TryFrom<&Url> for DeepLinkAction {
-    type Error = ActionParseFromUrlError;
-
-    fn try_from(url: &Url) -> Result {
-        #[cfg(target_os = "macos")]
-        if url.scheme() == "file" {
-            return url
-                .to_file_path()
-                .map(|project_path| Self::OpenEditor { project_path })
-                .map_err(|_| ActionParseFromUrlError::Invalid);
-        }
-
-        match url.domain() {
-            Some("action") => {}
-            Some(_) => return Err(ActionParseFromUrlError::NotAction),
-            None => return Err(ActionParseFromUrlError::Invalid),
-        }
-
-        let params = url
-            .query_pairs()
-            .collect::>();
-        let json_value = params
-            .get("value")
-            .ok_or(ActionParseFromUrlError::Invalid)?;
-        let action: Self = serde_json::from_str(json_value)
-            .map_err(|e| ActionParseFromUrlError::ParseFailed(e.to_string()))?;
-        Ok(action)
-    }
-}
-
-impl DeepLinkAction {
-    pub async fn execute(self, app: &AppHandle) -> Result<(), String> {
-        match self {
-            DeepLinkAction::StartRecording {
-                capture_mode,
-                camera,
-                mic_label,
-                capture_system_audio,
-                mode,
-            } => {
-                let state = app.state::>();
-
-                crate::set_camera_input(app.clone(), state.clone(), camera, None).await?;
-                crate::set_mic_input(app.clone(), state.clone(), mic_label).await?;
-
-                let capture_target: ScreenCaptureTarget = match capture_mode {
-                    CaptureMode::Screen(name) => cap_recording::screen_capture::list_displays()
-                        .into_iter()
-                        .find(|(s, _)| s.name == name)
-                        .map(|(s, _)| ScreenCaptureTarget::Display { id: s.id })
-                        .ok_or(format!("No screen with name \"{}\"", &name))?,
-                    CaptureMode::Window(name) => cap_recording::screen_capture::list_windows()
-                        .into_iter()
-                        .find(|(w, _)| w.name == name)
-                        .map(|(w, _)| ScreenCaptureTarget::Window { id: w.id })
-                        .ok_or(format!("No window with name \"{}\"", &name))?,
-                    #[cfg(debug_assertions)]
-                    CaptureMode::Area(area) => {
-                        if area.width <= 0.0 || area.height <= 0.0 {
-                            return Err("Area width and height must be positive".to_string());
-                        }
-                        let screen = cap_recording::screen_capture::list_displays()
-                            .into_iter()
-                            .find(|(display, _)| display.name == area.screen)
-                            .map(|(display, _)| display.id)
-                            .ok_or(format!("No screen with name \"{}\"", &area.screen))?;
-                        ScreenCaptureTarget::Area {
-                            screen,
-                            bounds: scap_targets::bounds::LogicalBounds::new(
-                                scap_targets::bounds::LogicalPosition::new(area.x, area.y),
-                                scap_targets::bounds::LogicalSize::new(area.width, area.height),
-                            ),
-                        }
-                    }
-                    #[cfg(debug_assertions)]
-                    CaptureMode::CameraOnly => ScreenCaptureTarget::CameraOnly,
-                };
-
-                let inputs = StartRecordingInputs {
-                    mode,
-                    capture_target,
-                    capture_system_audio,
-                    organization_id: None,
-                };
-
-                crate::recording::start_recording(app.clone(), state, inputs)
-                    .await
-                    .map(|_| ())
-            }
-            DeepLinkAction::StopRecording => {
-                crate::recording::stop_recording(app.clone(), app.state()).await
-            }
-            #[cfg(debug_assertions)]
-            DeepLinkAction::PauseRecording => {
-                crate::recording::pause_recording(app.clone(), app.state()).await
-            }
-            #[cfg(debug_assertions)]
-            DeepLinkAction::ResumeRecording => {
-                crate::recording::resume_recording(app.clone(), app.state()).await
-            }
-            #[cfg(debug_assertions)]
-            DeepLinkAction::OpenCamera { camera } => {
-                crate::set_camera_input(
-                    app.clone(),
-                    app.state::>(),
-                    Some(camera),
-                    None,
-                )
-                .await?;
-
-                if crate::general_settings::GeneralSettingsStore::native_camera_preview_enabled(app)
-                {
-                    crate::set_native_camera_preview_enabled(
-                        app.clone(),
-                        app.state::>(),
-                        true,
-                    )
-                    .await?;
-                }
-
-                app.emit("instant-mode-harness-camera-opened", ())
-                    .map_err(|err| err.to_string())?;
-                for delay_ms in [250, 750, 1500] {
-                    tokio::time::sleep(std::time::Duration::from_millis(delay_ms)).await;
-                    app.emit("instant-mode-harness-camera-opened", ())
-                        .map_err(|err| err.to_string())?;
-                }
-
-                Ok(())
-            }
-            #[cfg(debug_assertions)]
-            DeepLinkAction::SetCameraPreviewState { state } => {
-                crate::set_camera_preview_state(app.state(), state).await
-            }
-            #[cfg(debug_assertions)]
-            DeepLinkAction::SetRecordingInputs { camera, mic_label } => {
-                crate::set_camera_input(app.clone(), app.state(), camera, None).await?;
-                crate::set_mic_input(app.clone(), app.state(), mic_label).await
-            }
-            #[cfg(debug_assertions)]
-            DeepLinkAction::SetEditorPlayback {
-                project_path,
-                playing,
-            } => {
-                let window = crate::windows::editor_window_for_path(app, &project_path)
-                    .ok_or("Editor window is not open")?;
-                window
-                    .emit_to(
-                        tauri::EventTarget::WebviewWindow {
-                            label: window.label().to_string(),
-                        },
-                        "cap-dev-set-editor-playback",
-                        playing,
-                    )
-                    .map_err(|error| error.to_string())
-            }
-            #[cfg(debug_assertions)]
-            DeepLinkAction::CloseEditor { project_path } => {
-                let window = crate::windows::editor_window_for_path(app, &project_path)
-                    .ok_or("Editor window is not open")?;
-                window.close().map_err(|error| error.to_string())
-            }
-            DeepLinkAction::OpenEditor { project_path } => {
-                crate::open_project_from_path(Path::new(&project_path), app.clone())
-            }
-            DeepLinkAction::OpenSettings { page } => {
-                crate::show_window(app.clone(), ShowCapWindow::Settings { page }).await
-            }
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn parses_stop_recording_action_url() {
-        let url = Url::parse("cap-desktop://action?value=%22stop_recording%22").unwrap();
-
-        assert_eq!(
-            DeepLinkAction::try_from(&url),
-            Ok(DeepLinkAction::StopRecording)
-        );
-    }
-
-    #[cfg(debug_assertions)]
-    #[test]
-    fn parses_open_camera_action_url() {
-        let value = serde_json::json!({
-            "open_camera": {
-                "camera": { "DeviceID": "camera-1" }
-            }
-        })
-        .to_string();
-        let url = Url::parse_with_params("cap-desktop://action", &[("value", value)]).unwrap();
-
-        assert_eq!(
-            DeepLinkAction::try_from(&url),
-            Ok(DeepLinkAction::OpenCamera {
-                camera: DeviceOrModelID::DeviceID("camera-1".to_string())
-            })
-        );
-    }
-
-    #[cfg(debug_assertions)]
-    #[test]
-    fn parses_camera_preview_state_action_url() {
-        let value = serde_json::json!({
-            "set_camera_preview_state": {
-                "state": {
-                    "size": 400.0,
-                    "shape": "full",
-                    "mirrored": true,
-                    "background_blur": "heavy"
-                }
-            }
-        })
-        .to_string();
-        let url = Url::parse_with_params("cap-desktop://action", &[("value", value)]).unwrap();
-
-        assert_eq!(
-            DeepLinkAction::try_from(&url),
-            Ok(DeepLinkAction::SetCameraPreviewState {
-                state: CameraPreviewState {
-                    size: 400.0,
-                    shape: crate::camera::CameraPreviewShape::Full,
-                    mirrored: true,
-                    background_blur: cap_project::BackgroundBlurMode::Heavy,
-                }
-            })
-        );
-    }
-
-    #[cfg(debug_assertions)]
-    #[test]
-    fn parses_pause_and_resume_action_urls() {
-        let pause_url = Url::parse("cap-desktop://action?value=%22pause_recording%22").unwrap();
-        let resume_url = Url::parse("cap-desktop://action?value=%22resume_recording%22").unwrap();
-
-        assert_eq!(
-            DeepLinkAction::try_from(&pause_url),
-            Ok(DeepLinkAction::PauseRecording)
-        );
-        assert_eq!(
-            DeepLinkAction::try_from(&resume_url),
-            Ok(DeepLinkAction::ResumeRecording)
-        );
-    }
-
-    #[cfg(debug_assertions)]
-    #[test]
-    fn parses_area_recording_action_url() {
-        let value = serde_json::json!({
-            "start_recording": {
-                "capture_mode": {
-                    "area": {
-                        "screen": "Built-in Retina Display",
-                        "x": 10.0,
-                        "y": 20.0,
-                        "width": 800.0,
-                        "height": 600.0
-                    }
-                },
-                "camera": { "DeviceID": "camera-1" },
-                "mic_label": "microphone-1",
-                "capture_system_audio": false,
-                "mode": "instant"
-            }
-        })
-        .to_string();
-        let url = Url::parse_with_params("cap-desktop://action", &[("value", value)]).unwrap();
-
-        assert_eq!(
-            DeepLinkAction::try_from(&url),
-            Ok(DeepLinkAction::StartRecording {
-                capture_mode: CaptureMode::Area(Box::new(CaptureArea {
-                    screen: "Built-in Retina Display".to_string(),
-                    x: 10.0,
-                    y: 20.0,
-                    width: 800.0,
-                    height: 600.0,
-                })),
-                camera: Some(DeviceOrModelID::DeviceID("camera-1".to_string())),
-                mic_label: Some("microphone-1".to_string()),
-                capture_system_audio: false,
-                mode: RecordingMode::Instant,
-            })
-        );
-    }
-
-    #[cfg(debug_assertions)]
-    #[test]
-    fn parses_camera_only_recording_action_url() {
-        let value = serde_json::json!({
-            "start_recording": {
-                "capture_mode": "camera_only",
-                "camera": { "DeviceID": "camera-1" },
-                "mic_label": "microphone-1",
-                "capture_system_audio": false,
-                "mode": "studio"
-            }
-        })
-        .to_string();
-        let url = Url::parse_with_params("cap-desktop://action", &[("value", value)]).unwrap();
-
-        assert_eq!(
-            DeepLinkAction::try_from(&url),
-            Ok(DeepLinkAction::StartRecording {
-                capture_mode: CaptureMode::CameraOnly,
-                camera: Some(DeviceOrModelID::DeviceID("camera-1".to_string())),
-                mic_label: Some("microphone-1".to_string()),
-                capture_system_audio: false,
-                mode: RecordingMode::Studio,
-            })
-        );
-    }
-
-    #[test]
-    fn parses_start_recording_action_url() {
-        let url = Url::parse(
-            "cap-desktop://action?value=%7B%22start_recording%22%3A%7B%22capture_mode%22%3A%7B%22screen%22%3A%22Odyssey%20G93SC%22%7D%2C%22camera%22%3Anull%2C%22mic_label%22%3A%22Shure%20MV7%2B%22%2C%22capture_system_audio%22%3Atrue%2C%22mode%22%3A%22studio%22%7D%7D",
-        )
-        .unwrap();
-
-        let Ok(DeepLinkAction::StartRecording {
-            capture_mode,
-            camera,
-            mic_label,
-            capture_system_audio,
-            mode,
-        }) = DeepLinkAction::try_from(&url)
-        else {
-            panic!("expected start recording action");
-        };
-
-        assert_eq!(
-            capture_mode,
-            CaptureMode::Screen("Odyssey G93SC".to_string())
-        );
-        assert_eq!(camera, None);
-        assert_eq!(mic_label.as_deref(), Some("Shure MV7+"));
-        assert!(capture_system_audio);
-        assert_eq!(mode, RecordingMode::Studio);
-    }
-
-    #[test]
-    fn parses_start_recording_action_with_camera_device_id() {
-        let value = serde_json::json!({
-            "start_recording": {
-                "capture_mode": { "screen": "Odyssey G93SC" },
-                "camera": { "DeviceID": "camera-1" },
-                "mic_label": "Shure MV7+",
-                "capture_system_audio": true,
-                "mode": "studio"
-            }
-        })
-        .to_string();
-        let url = Url::parse_with_params("cap-desktop://action", &[("value", value)]).unwrap();
-
-        let Ok(DeepLinkAction::StartRecording {
-            camera,
-            mic_label,
-            capture_system_audio,
-            ..
-        }) = DeepLinkAction::try_from(&url)
-        else {
-            panic!("expected start recording action");
-        };
-
-        assert_eq!(
-            camera,
-            Some(DeviceOrModelID::DeviceID("camera-1".to_string()))
-        );
-        assert_eq!(mic_label.as_deref(), Some("Shure MV7+"));
-        assert!(capture_system_audio);
-    }
-
-    #[test]
-    fn rejects_non_action_host() {
-        let url = Url::parse("cap-desktop://login?value=%22stop_recording%22").unwrap();
-
-        assert_eq!(
-            DeepLinkAction::try_from(&url),
-            Err(ActionParseFromUrlError::NotAction)
-        );
-    }
-}
diff --git a/apps/desktop/src-tauri/src/diagnostics.rs b/apps/desktop/src-tauri/src/diagnostics.rs
deleted file mode 100644
index 102c735e423..00000000000
--- a/apps/desktop/src-tauri/src/diagnostics.rs
+++ /dev/null
@@ -1,787 +0,0 @@
-use crate::{ArcLock, general_settings::GeneralSettingsStore, permissions};
-use serde::{Deserialize, Serialize};
-use specta::Type;
-use std::{
-    path::{Path, PathBuf},
-    sync::atomic::{AtomicBool, Ordering},
-};
-use tauri::{AppHandle, Manager};
-use tauri_specta::Event;
-use tokio::io::AsyncBufReadExt;
-use tracing::{error, info, warn};
-
-/// Reports are written next to the logs so support can ask for them by name.
-const REPORTS_DIR_NAME: &str = "diagnostics";
-const REPORTS_TO_KEEP: usize = 5;
-const SYNC_TEST_STDERR_TAIL_LIMIT: usize = 40;
-/// The full report always lands on disk; only the copy handed back to the
-/// webview is trimmed, so a pathological run can't wedge the settings window.
-const MAX_INLINE_REPORT_BYTES: usize = 2 * 1024 * 1024;
-const MIN_SYNC_TEST_SECS: u32 = 14;
-const MAX_SYNC_TEST_SECS: u32 = 120;
-
-/// Only one diagnostic can run at a time: the sync test takes over the screen
-/// and the audio device, so a second run would measure the first one.
-static DIAGNOSTIC_RUNNING: AtomicBool = AtomicBool::new(false);
-
-#[derive(Debug, Clone, Serialize, Deserialize, Type)]
-#[serde(rename_all = "camelCase")]
-pub struct DiagnosticOptions {
-    pub include_sync_test: bool,
-    /// `studio`, `instant` or `both`.
-    pub mode: String,
-    pub duration_secs: Option,
-    pub include_microphone: bool,
-    pub mic_name: Option,
-    pub skip_export: bool,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, Type)]
-#[serde(rename_all = "camelCase")]
-pub struct DiagnosticRunResult {
-    pub report_path: String,
-    pub verdict: Option,
-    pub summary: Option,
-    pub sync_test_error: Option,
-    pub report_json: String,
-}
-
-/// `phase` is `sync-test`, `collecting` or `done`; `stage`/`mode` are only set
-/// for `sync-test` and carry the CLI's stage names verbatim.
-#[derive(Debug, Clone, Serialize, Type, Event)]
-#[serde(rename_all = "camelCase")]
-pub struct DiagnosticProgress {
-    pub phase: String,
-    pub stage: Option,
-    pub mode: Option,
-}
-
-impl DiagnosticProgress {
-    fn phase(phase: &str) -> Self {
-        Self {
-            phase: phase.to_string(),
-            stage: None,
-            mode: None,
-        }
-    }
-}
-
-/// The subset of `cap selftest av-sync --progress-json` NDJSON we act on.
-/// Lines with an unknown `type` (or no `type` at all) are ignored so the CLI
-/// can add message kinds without breaking older apps.
-#[derive(Debug, Deserialize, PartialEq)]
-#[serde(tag = "type")]
-enum SyncTestMessage {
-    Stage {
-        stage: String,
-        #[serde(default)]
-        mode: Option,
-    },
-    Report {
-        report: serde_json::Value,
-    },
-    Error {
-        error: String,
-    },
-}
-
-fn parse_sync_test_line(line: &str) -> Option {
-    let line = line.trim();
-    if line.is_empty() {
-        return None;
-    }
-    serde_json::from_str(line).ok()
-}
-
-fn normalize_mode(mode: &str) -> Result<&'static str, String> {
-    match mode {
-        "studio" => Ok("studio"),
-        "instant" => Ok("instant"),
-        "both" => Ok("both"),
-        other => Err(format!("Unknown sync test mode '{other}'")),
-    }
-}
-
-struct RunGuard;
-
-impl RunGuard {
-    fn acquire() -> Result {
-        DIAGNOSTIC_RUNNING
-            .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
-            .map(|_| Self)
-            .map_err(|_| "A diagnostic is already running".to_string())
-    }
-}
-
-impl Drop for RunGuard {
-    fn drop(&mut self) {
-        DIAGNOSTIC_RUNNING.store(false, Ordering::Release);
-    }
-}
-
-/// The argv for one sync-test run, without the binary itself.
-///
-/// `--discard-recordings` is not optional here: the app surfaces the report and
-/// never the recording, and the CLI otherwise keeps the recorded project for
-/// every non-pass verdict -- including the common `inconclusive` one -- with
-/// nothing on this side to reveal or delete it.
-fn sync_test_args(options: &DiagnosticOptions, mode: &str) -> Vec {
-    let mut args = vec![
-        "selftest".to_string(),
-        "av-sync".to_string(),
-        "--mode".to_string(),
-        mode.to_string(),
-        "--progress-json".to_string(),
-        "--discard-recordings".to_string(),
-    ];
-
-    if let Some(duration) = options.duration_secs {
-        args.push("--duration".to_string());
-        args.push(
-            duration
-                .clamp(MIN_SYNC_TEST_SECS, MAX_SYNC_TEST_SECS)
-                .to_string(),
-        );
-    }
-
-    if options.include_microphone {
-        args.push("--mic".to_string());
-        if let Some(name) = options.mic_name.as_deref().filter(|n| !n.is_empty()) {
-            args.push("--mic-name".to_string());
-            args.push(name.to_string());
-        }
-    }
-
-    if options.skip_export {
-        args.push("--skip-export".to_string());
-    }
-
-    args
-}
-
-async fn collect_sync_test_stderr_tail(stderr: tokio::process::ChildStderr) -> Vec {
-    let mut lines = tokio::io::BufReader::new(stderr).lines();
-    let mut tail = Vec::new();
-
-    loop {
-        match lines.next_line().await {
-            Ok(Some(line)) => {
-                if cfg!(debug_assertions) {
-                    info!(line = %line, "Sync test stderr");
-                }
-                tail.push(line);
-                if tail.len() > SYNC_TEST_STDERR_TAIL_LIMIT {
-                    tail.remove(0);
-                }
-            }
-            Ok(None) => break,
-            Err(e) => {
-                tail.push(format!("failed reading stderr: {e}"));
-                break;
-            }
-        }
-    }
-
-    tail
-}
-
-/// Drives `cap selftest av-sync` in the exporter sidecar. The verdict lives in
-/// the `Report` message, never in the exit code: the CLI exits non-zero for
-/// fail/inconclusive runs that still produced a full report.
-async fn run_sync_test(
-    app: &AppHandle,
-    options: &DiagnosticOptions,
-) -> Result {
-    let mode = normalize_mode(&options.mode)?;
-    // The sync test lives in the `cap` CLI, shipped as the `cap-exporter`
-    // sidecar; a dev build without the sidecar has no way to run it.
-    let bin_path = crate::export::resolve_exporter_binary()
-        .map_err(|e| format!("Sync test helper unavailable: {e}"))?;
-
-    let mut command = tokio::process::Command::new(&bin_path);
-    command
-        .args(sync_test_args(options, mode))
-        .stdout(std::process::Stdio::piped())
-        .stderr(std::process::Stdio::piped())
-        // Every early return below (a stdout read error, most of all) would
-        // otherwise orphan a process that owns the screen with a fullscreen
-        // flashing window and is midway through a recording.
-        .kill_on_drop(true);
-    crate::export::configure_exporter_command(&mut command);
-
-    let mut child = command
-        .spawn()
-        .map_err(|e| format!("Failed to start sync test '{}': {e}", bin_path.display()))?;
-
-    let stdout = child
-        .stdout
-        .take()
-        .ok_or_else(|| "Sync test stdout was not captured".to_string())?;
-    let stderr = child
-        .stderr
-        .take()
-        .ok_or_else(|| "Sync test stderr was not captured".to_string())?;
-    let stderr_task = tokio::spawn(collect_sync_test_stderr_tail(stderr));
-
-    let mut report = None;
-    let mut reported_error = None;
-    let mut stdout_lines = tokio::io::BufReader::new(stdout).lines();
-
-    while let Some(line) = stdout_lines
-        .next_line()
-        .await
-        .map_err(|e| format!("Failed reading sync test stdout: {e}"))?
-    {
-        match parse_sync_test_line(&line) {
-            Some(SyncTestMessage::Stage { stage, mode }) => {
-                DiagnosticProgress {
-                    phase: "sync-test".to_string(),
-                    stage: Some(stage),
-                    mode,
-                }
-                .emit(app)
-                .ok();
-            }
-            Some(SyncTestMessage::Report { report: value }) => report = Some(value),
-            Some(SyncTestMessage::Error { error }) => reported_error = Some(error),
-            None => {}
-        }
-    }
-
-    let status = child
-        .wait()
-        .await
-        .map_err(|e| format!("Failed waiting for sync test: {e}"))?;
-    let stderr_tail = stderr_task.await.unwrap_or_default();
-
-    if let Some(report) = report {
-        return Ok(report);
-    }
-
-    if let Some(error) = reported_error {
-        return Err(error);
-    }
-
-    let tail = stderr_tail.join("\n");
-    Err(format!(
-        "Sync test exited with status {status} without producing a report.\n{tail}"
-    ))
-}
-
-/// Strip credentials from a configured server URL without hiding the host,
-/// which is the part support needs to know about.
-fn redact_url_credentials(url: &str) -> String {
-    let Some((scheme, rest)) = url.split_once("://") else {
-        return url.to_string();
-    };
-    let authority_end = rest.find('/').unwrap_or(rest.len());
-    let (authority, path) = rest.split_at(authority_end);
-    match authority.rsplit_once('@') {
-        Some((_, host)) => format!("{scheme}://***@{host}{path}"),
-        None => url.to_string(),
-    }
-}
-
-fn settings_snapshot(settings: &GeneralSettingsStore) -> serde_json::Value {
-    use cap_recording::diagnostics::redact_home_paths;
-
-    serde_json::json!({
-        "maxFps": settings.max_fps,
-        "instantModeMaxResolution": settings.instant_mode_max_resolution,
-        "studioRecordingQuality": settings.studio_recording_quality,
-        "customCursorCapture": settings.custom_cursor_capture,
-        "outOfProcessMuxer": settings.out_of_process_muxer,
-        "crashRecoveryRecording": settings.crash_recovery_recording,
-        "enableNativeCameraPreview": settings.enable_native_camera_preview,
-        "recordingsPath": settings
-            .recordings_path
-            .as_deref()
-            .map(redact_home_paths),
-        "previousRecordingsPaths": settings
-            .previous_recordings_paths
-            .iter()
-            .map(|p| redact_home_paths(p))
-            .collect::>(),
-        "updateChannel": settings.update_channel,
-        "serverUrl": redact_url_credentials(&settings.server_url),
-        "instanceId": settings.instance_id,
-        "enableTelemetry": settings.enable_telemetry,
-        "editorPreviewQuality": settings.editor_preview_quality,
-        "captureKeyboardEvents": settings.capture_keyboard_events,
-    })
-}
-
-fn permissions_snapshot() -> serde_json::Value {
-    let check = permissions::do_permissions_check(false);
-    serde_json::json!({
-        "screenRecording": crate::logging::permission_status_str(&check.screen_recording),
-        "camera": crate::logging::permission_status_str(&check.camera),
-        "microphone": crate::logging::permission_status_str(&check.microphone),
-        "accessibility": crate::logging::permission_status_str(&check.accessibility),
-    })
-}
-
-fn reports_dir(app: &AppHandle) -> Result {
-    let dir = app
-        .path()
-        .app_data_dir()
-        .map_err(|e| format!("Failed to get app data dir: {e}"))?
-        .join(REPORTS_DIR_NAME);
-    std::fs::create_dir_all(&dir)
-        .map_err(|e| format!("Failed to create diagnostics folder: {e}"))?;
-    Ok(dir)
-}
-
-/// Keep the newest `keep` reports. Ties on modification time fall back to the
-/// (timestamped) file name so the order is deterministic.
-fn prune_reports(dir: &Path, keep: usize) -> Result<(), String> {
-    let entries =
-        std::fs::read_dir(dir).map_err(|e| format!("Failed to read diagnostics folder: {e}"))?;
-
-    let mut reports: Vec<(std::time::SystemTime, std::ffi::OsString, PathBuf)> = entries
-        .filter_map(|entry| {
-            let entry = entry.ok()?;
-            let path = entry.path();
-            let name = path.file_name()?.to_owned();
-            let name_str = name.to_str()?;
-            if !path.is_file()
-                || !name_str.starts_with("cap-diagnostic-")
-                || !name_str.ends_with(".json")
-            {
-                return None;
-            }
-            let modified = std::fs::metadata(&path).ok()?.modified().ok()?;
-            Some((modified, name, path))
-        })
-        .collect();
-
-    reports.sort_by(|a, b| b.0.cmp(&a.0).then_with(|| b.1.cmp(&a.1)));
-
-    for (_, _, path) in reports.into_iter().skip(keep) {
-        if let Err(e) = std::fs::remove_file(&path) {
-            warn!(path = %path.display(), error = %e, "Failed to prune old diagnostic report");
-        }
-    }
-
-    Ok(())
-}
-
-/// The webview only ever renders a preview, so the two unbounded arrays are the
-/// first thing to go when a report is huge.
-fn truncate_for_ui(report: &serde_json::Value) -> serde_json::Value {
-    let mut trimmed = report.clone();
-
-    if let Some(obj) = trimmed.as_object_mut() {
-        obj.insert(
-            "recentRecordings".to_string(),
-            serde_json::Value::Array(Vec::new()),
-        );
-
-        if let Some(sync_test) = obj.get_mut("syncTest").and_then(|v| v.as_object_mut()) {
-            for key in ["recording", "microphone", "export", "instant"] {
-                if let Some(measurement) = sync_test.get_mut(key).and_then(|v| v.as_object_mut()) {
-                    measurement.insert("events".to_string(), serde_json::Value::Array(Vec::new()));
-                }
-            }
-        }
-
-        obj.insert(
-            "truncatedForPreview".to_string(),
-            serde_json::Value::Bool(true),
-        );
-    }
-
-    trimmed
-}
-
-fn resolve_within(dir: &Path, candidate: &Path) -> Result {
-    let dir = dir
-        .canonicalize()
-        .map_err(|e| format!("Diagnostics folder unavailable: {e}"))?;
-    let candidate = candidate
-        .canonicalize()
-        .map_err(|e| format!("Diagnostic report not found: {e}"))?;
-
-    if !candidate.starts_with(&dir) {
-        return Err("Diagnostic report is outside the diagnostics folder".to_string());
-    }
-
-    Ok(candidate)
-}
-
-fn validate_report_path(app: &AppHandle, report_path: &str) -> Result {
-    resolve_within(&reports_dir(app)?, Path::new(report_path))
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn run_diagnostic(
-    app: AppHandle,
-    options: DiagnosticOptions,
-) -> Result {
-    if options.include_sync_test {
-        // Validate before taking the guard so a bad mode is a plain error.
-        normalize_mode(&options.mode)?;
-    }
-
-    let _guard = RunGuard::acquire()?;
-
-    {
-        let app_lock = app.state::>();
-        let state = app_lock.read().await;
-        if matches!(
-            state.recording_state,
-            crate::RecordingState::Active(_) | crate::RecordingState::Pending { .. }
-        ) {
-            return Err("Stop the current recording before running a diagnostic".to_string());
-        }
-    }
-
-    let mut sync_test = None;
-    let mut sync_test_error = None;
-
-    if options.include_sync_test {
-        match run_sync_test(&app, &options).await {
-            Ok(report) => sync_test = Some(report),
-            Err(e) => {
-                // An unrunnable sync test still leaves a useful environment
-                // report, so the run continues with the reason recorded.
-                error!(error = %e, "Sync test failed; continuing with environment report");
-                sync_test_error = Some(e);
-            }
-        }
-    }
-
-    DiagnosticProgress::phase("collecting").emit(&app).ok();
-
-    let settings = GeneralSettingsStore::get(&app)
-        .map_err(|e| warn!("Failed to read general settings for diagnostic: {e}"))
-        .ok()
-        .flatten();
-    let recordings_dir = GeneralSettingsStore::recordings_dir(&app);
-    let configured_max_fps = settings.as_ref().map(|s| s.max_fps);
-    let fragmented_recording = settings
-        .as_ref()
-        .map(|s| s.crash_recovery_recording)
-        .unwrap_or(cap_recording::DEFAULT_CRASH_RECOVERY_RECORDING);
-    let settings_json = settings.as_ref().map(settings_snapshot);
-    let app_version = env!("CARGO_PKG_VERSION").to_string();
-    let sync_test_error_for_report = sync_test_error.clone();
-
-    // `collect_report` probes displays and disk mounts; both can block for tens
-    // of seconds, so it never runs on the async runtime's cooperative threads.
-    let report = tokio::task::spawn_blocking(move || {
-        cap_recording::diagnostics::collect_report(
-            cap_recording::diagnostics::DiagnosticReportArgs {
-                flavor: "tauri",
-                app_version: &app_version,
-                settings: settings_json,
-                permissions: Some(permissions_snapshot()),
-                recordings_dir: Some(recordings_dir.as_path()),
-                configured_max_fps,
-                fragmented_recording,
-                sync_test,
-                sync_test_error: sync_test_error_for_report,
-            },
-        )
-    })
-    .await
-    .map_err(|e| format!("Failed to collect diagnostic report: {e}"))?;
-
-    let verdict = report
-        .sync_test
-        .as_ref()
-        .and_then(|v| v.get("verdict"))
-        .and_then(|v| v.as_str())
-        .map(str::to_string);
-    let summary = report
-        .sync_test
-        .as_ref()
-        .and_then(|v| v.get("summary"))
-        .and_then(|v| v.as_str())
-        .map(str::to_string);
-
-    let report_value = serde_json::to_value(&report)
-        .map_err(|e| format!("Failed to serialize diagnostic report: {e}"))?;
-    let report_json = serde_json::to_string_pretty(&report_value)
-        .map_err(|e| format!("Failed to serialize diagnostic report: {e}"))?;
-
-    let dir = reports_dir(&app)?;
-    let report_path = dir.join(format!(
-        "cap-diagnostic-{}.json",
-        chrono::Local::now().format("%Y%m%d-%H%M%S")
-    ));
-    std::fs::write(&report_path, &report_json)
-        .map_err(|e| format!("Failed to write diagnostic report: {e}"))?;
-    prune_reports(&dir, REPORTS_TO_KEEP).ok();
-
-    let report_json = if report_json.len() > MAX_INLINE_REPORT_BYTES {
-        serde_json::to_string_pretty(&truncate_for_ui(&report_value)).unwrap_or(report_json)
-    } else {
-        report_json
-    };
-
-    DiagnosticProgress::phase("done").emit(&app).ok();
-
-    Ok(DiagnosticRunResult {
-        report_path: report_path.display().to_string(),
-        verdict,
-        summary,
-        sync_test_error,
-        report_json,
-    })
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn upload_diagnostic_report(app: AppHandle, report_path: String) -> Result<(), String> {
-    let path = validate_report_path(&app, &report_path)?;
-    let report = std::fs::read_to_string(&path)
-        .map_err(|e| format!("Failed to read diagnostic report: {e}"))?;
-
-    crate::logging::upload_log_file_inner(&app, Some(report)).await
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn reveal_diagnostic_report(app: AppHandle, report_path: String) -> Result<(), String> {
-    let path = validate_report_path(&app, &report_path)?;
-
-    crate::reveal_in_dir(app, path)
-        .await
-        .map_err(|e| format!("Failed to reveal diagnostic report: {e}"))
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    fn temp_dir() -> PathBuf {
-        let dir = std::env::temp_dir().join(format!("cap-diagnostics-{}", uuid::Uuid::new_v4()));
-        std::fs::create_dir_all(&dir).unwrap();
-        dir
-    }
-
-    #[test]
-    fn parses_stage_lines() {
-        assert_eq!(
-            parse_sync_test_line(r#"{"type":"Stage","stage":"recording","mode":"studio"}"#),
-            Some(SyncTestMessage::Stage {
-                stage: "recording".to_string(),
-                mode: Some("studio".to_string()),
-            })
-        );
-        assert_eq!(
-            parse_sync_test_line(r#"{"type":"Stage","stage":"done","mode":null}"#),
-            Some(SyncTestMessage::Stage {
-                stage: "done".to_string(),
-                mode: None,
-            })
-        );
-    }
-
-    #[test]
-    fn parses_report_and_error_lines() {
-        let report = parse_sync_test_line(r#"{"type":"Report","report":{"verdict":"pass"}}"#);
-        let Some(SyncTestMessage::Report { report }) = report else {
-            panic!("expected a report message");
-        };
-        assert_eq!(report["verdict"], "pass");
-
-        assert_eq!(
-            parse_sync_test_line(r#"{"type":"Error","error":"no display"}"#),
-            Some(SyncTestMessage::Error {
-                error: "no display".to_string()
-            })
-        );
-    }
-
-    #[test]
-    fn ignores_unknown_and_malformed_lines() {
-        assert_eq!(parse_sync_test_line(r#"{"type":"Heartbeat","at":1}"#), None);
-        assert_eq!(parse_sync_test_line("not json at all"), None);
-        assert_eq!(parse_sync_test_line("{}"), None);
-        assert_eq!(parse_sync_test_line("   "), None);
-        // A stage message missing its required field is dropped, not fatal.
-        assert_eq!(parse_sync_test_line(r#"{"type":"Stage"}"#), None);
-    }
-
-    fn options(mode: &str) -> DiagnosticOptions {
-        DiagnosticOptions {
-            include_sync_test: true,
-            mode: mode.to_string(),
-            duration_secs: None,
-            include_microphone: false,
-            mic_name: None,
-            skip_export: false,
-        }
-    }
-
-    /// The app never surfaces the recorded project, so it always asks the CLI
-    /// to discard it -- otherwise every non-pass verdict leaves a full screen
-    /// recording in temp that nothing here ever cleans up.
-    #[test]
-    fn the_sync_test_always_discards_recordings() {
-        assert_eq!(
-            sync_test_args(&options("both"), "both"),
-            [
-                "selftest",
-                "av-sync",
-                "--mode",
-                "both",
-                "--progress-json",
-                "--discard-recordings",
-            ]
-        );
-
-        let full = DiagnosticOptions {
-            duration_secs: Some(500),
-            include_microphone: true,
-            mic_name: Some("Studio Mic".to_string()),
-            skip_export: true,
-            ..options("studio")
-        };
-        assert_eq!(
-            sync_test_args(&full, "studio"),
-            [
-                "selftest",
-                "av-sync",
-                "--mode",
-                "studio",
-                "--progress-json",
-                "--discard-recordings",
-                // Out-of-range durations are clamped, as they always were.
-                "--duration",
-                "120",
-                "--mic",
-                "--mic-name",
-                "Studio Mic",
-                "--skip-export",
-            ]
-        );
-
-        // An empty mic name is not passed as a flag value.
-        let empty_name = DiagnosticOptions {
-            include_microphone: true,
-            mic_name: Some(String::new()),
-            ..options("instant")
-        };
-        assert!(
-            !sync_test_args(&empty_name, "instant")
-                .iter()
-                .any(|arg| arg == "--mic-name")
-        );
-    }
-
-    #[test]
-    fn normalizes_known_modes_only() {
-        assert_eq!(normalize_mode("both"), Ok("both"));
-        assert_eq!(normalize_mode("studio"), Ok("studio"));
-        assert_eq!(normalize_mode("instant"), Ok("instant"));
-        assert!(normalize_mode("Studio").is_err());
-        assert!(normalize_mode("").is_err());
-    }
-
-    #[test]
-    fn resolve_within_accepts_files_in_the_dir() {
-        let root = temp_dir();
-        let dir = root.join("diagnostics");
-        std::fs::create_dir_all(&dir).unwrap();
-        let file = dir.join("cap-diagnostic-1.json");
-        std::fs::write(&file, "{}").unwrap();
-
-        let resolved = resolve_within(&dir, &file).unwrap();
-        assert_eq!(resolved, file.canonicalize().unwrap());
-
-        std::fs::remove_dir_all(&root).ok();
-    }
-
-    #[test]
-    fn resolve_within_rejects_escapes() {
-        let root = temp_dir();
-        let dir = root.join("diagnostics");
-        std::fs::create_dir_all(&dir).unwrap();
-        let outside = root.join("secret.json");
-        std::fs::write(&outside, "{}").unwrap();
-
-        // Traversal out of the diagnostics folder.
-        assert!(resolve_within(&dir, &dir.join("../secret.json")).is_err());
-        // An absolute path elsewhere on disk.
-        assert!(resolve_within(&dir, &outside).is_err());
-        // A file that does not exist at all.
-        assert!(resolve_within(&dir, &dir.join("missing.json")).is_err());
-
-        std::fs::remove_dir_all(&root).ok();
-    }
-
-    #[test]
-    fn prunes_to_the_newest_reports() {
-        let dir = temp_dir();
-        for i in 0..8 {
-            std::fs::write(
-                dir.join(format!("cap-diagnostic-2026010{i}-120000.json")),
-                "{}",
-            )
-            .unwrap();
-        }
-        // Unrelated files are never touched.
-        std::fs::write(dir.join("notes.txt"), "keep me").unwrap();
-        std::fs::write(dir.join("cap-diagnostic-partial.txt"), "keep me").unwrap();
-
-        prune_reports(&dir, 5).unwrap();
-
-        let mut remaining: Vec = std::fs::read_dir(&dir)
-            .unwrap()
-            .map(|e| e.unwrap().file_name().to_string_lossy().into_owned())
-            .filter(|n| n.starts_with("cap-diagnostic-") && n.ends_with(".json"))
-            .collect();
-        remaining.sort();
-
-        assert_eq!(remaining.len(), 5);
-        assert!(remaining.contains(&"cap-diagnostic-20260107-120000.json".to_string()));
-        assert!(!remaining.contains(&"cap-diagnostic-20260100-120000.json".to_string()));
-        assert!(dir.join("notes.txt").exists());
-        assert!(dir.join("cap-diagnostic-partial.txt").exists());
-
-        std::fs::remove_dir_all(&dir).ok();
-    }
-
-    #[test]
-    fn redacts_only_url_credentials() {
-        assert_eq!(
-            redact_url_credentials("https://cap.so"),
-            "https://cap.so".to_string()
-        );
-        assert_eq!(
-            redact_url_credentials("https://user:pass@self.hosted/cap"),
-            "https://***@self.hosted/cap".to_string()
-        );
-        assert_eq!(redact_url_credentials("not a url"), "not a url".to_string());
-    }
-
-    #[test]
-    fn truncate_for_ui_drops_unbounded_arrays() {
-        let report = serde_json::json!({
-            "recentRecordings": [{ "id": "a" }],
-            "syncTest": {
-                "verdict": "pass",
-                "recording": { "medianOffsetMs": 1.0, "events": [1, 2, 3] },
-                "studioError": null,
-            },
-        });
-
-        let trimmed = truncate_for_ui(&report);
-
-        assert_eq!(trimmed["recentRecordings"].as_array().unwrap().len(), 0);
-        assert_eq!(
-            trimmed["syncTest"]["recording"]["events"]
-                .as_array()
-                .unwrap()
-                .len(),
-            0
-        );
-        assert_eq!(trimmed["syncTest"]["verdict"], "pass");
-        assert_eq!(trimmed["syncTest"]["recording"]["medianOffsetMs"], 1.0);
-        assert_eq!(trimmed["truncatedForPreview"], true);
-    }
-}
diff --git a/apps/desktop/src-tauri/src/editor_preparing.rs b/apps/desktop/src-tauri/src/editor_preparing.rs
deleted file mode 100644
index 74a236e1348..00000000000
--- a/apps/desktop/src-tauri/src/editor_preparing.rs
+++ /dev/null
@@ -1,1398 +0,0 @@
-use std::{
-    collections::HashMap,
-    io::{self, BufReader, Read},
-    panic::AssertUnwindSafe,
-    path::{Path, PathBuf},
-    str::FromStr,
-    sync::{
-        Arc, Mutex,
-        atomic::{AtomicBool, Ordering},
-    },
-    time::Duration,
-};
-
-use cap_editor::{
-    EditorFrameFormat, PreparingEditorProgress, PreparingPlaybackController, PreparingPlaybackExit,
-    PreparingPlaybackOptions, PreparingPlaybackSession, PreparingPlaybackSnapshot,
-    PreparingPlaybackState, PreparingPlaybackStopHandle, PreparingPreviewInput,
-    PreparingPreviewOptions, PreparingPreviewSegment,
-};
-use cap_project::{CursorEvents, ProjectConfiguration};
-use cap_recording::recovery::{
-    PreparingSidecarKind, PreparingStudioSources, PreparingStudioState, PreparingVideoTrack,
-};
-use cap_rendering::{FrozenRecordedCursorAssets, ManagedSegmentVideoInput, ManagedVideoTrackInput};
-use futures::{
-    FutureExt,
-    future::{BoxFuture, Shared},
-};
-use serde::Serialize;
-use specta::Type;
-use tauri::{AppHandle, Manager, Window};
-use tauri_specta::Event;
-use tokio::sync::{oneshot, watch};
-
-use crate::frame_ws::{OwnedWatchFrameWs, WSFrame};
-use crate::{
-    FinalizationProject, FinalizingRecordings,
-    preparing_finalization::FinalizationPreparing,
-    windows::{CapWindowId, EditorWindowIds},
-};
-
-mod audio;
-
-const MAX_CURSOR_BYTES: u64 = 256 * 1024 * 1024;
-
-#[derive(Clone, Debug, Serialize, Type)]
-#[serde(rename_all = "camelCase")]
-pub(crate) struct PreparingEditorSeed {
-    title: String,
-    tracks: Vec,
-}
-
-#[derive(Clone, Debug, Serialize, Type, tauri_specta::Event)]
-#[serde(rename_all = "camelCase")]
-pub(crate) struct PreparingEditorChanged {
-    request_epoch: u32,
-    job_id: String,
-    sequence: u32,
-    fps: u32,
-    progress: PreparingEditorProgress,
-    playback: PreparingPlaybackState,
-    seed: PreparingEditorSeed,
-}
-
-#[derive(Default)]
-struct PlaybackBinding {
-    latest: Option,
-    controller: Option,
-    audio_output: Option>,
-    exit: Option,
-    handoff: Option,
-}
-
-#[derive(Clone)]
-struct RetainedJoin(Shared>>);
-
-impl RetainedJoin {
-    fn new(task: tokio::task::JoinHandle>) -> Self {
-        let completion = async move {
-            task.await
-                .map_err(|error| format!("Preparing cleanup task failed: {error}"))?
-        }
-        .boxed()
-        .shared();
-        let retained = completion.clone();
-        drop(tokio::spawn(async move {
-            let _ = retained.await;
-        }));
-        Self(completion)
-    }
-
-    async fn wait(&self) -> Result<(), String> {
-        self.0.clone().await
-    }
-    fn succeeded(&self) -> bool {
-        self.0.peek().is_some_and(Result::is_ok)
-    }
-}
-
-struct ConsumerControl {
-    window_ids: EditorWindowIds,
-    window_id: u32,
-    request_epoch: u32,
-    path: PathBuf,
-    finalization: FinalizationPreparing,
-    cancelled: watch::Sender,
-    accepts_frames: AtomicBool,
-    playback: Mutex,
-    publish: Option>,
-}
-
-impl ConsumerControl {
-    fn cancel(&self) {
-        if let Some(handoff) = &self.playback.lock().unwrap().handoff {
-            handoff.cancel();
-        }
-        self.accepts_frames.store(false, Ordering::Release);
-        self.cancelled.send_replace(true);
-    }
-
-    fn is_active(&self) -> bool {
-        !*self.cancelled.borrow()
-            && self
-                .window_ids
-                .ids
-                .lock()
-                .unwrap()
-                .iter()
-                .any(|(path, id)| *id == self.window_id && path == &self.path)
-            && (self.finalization.is_pending() || self.finalization.allows_preparing_continuation())
-    }
-
-    fn publish_snapshot(&self, snapshot: &PreparingPlaybackSnapshot) {
-        let update = {
-            let mut binding = self.playback.lock().unwrap();
-            let Some(latest) = binding.latest.as_mut() else {
-                return;
-            };
-            latest.sequence = latest.sequence.saturating_add(1);
-            latest.progress = snapshot.progress.clone();
-            latest.playback = snapshot.playback;
-            latest.clone()
-        };
-        if let Some(publish) = &self.publish {
-            publish(update);
-        }
-    }
-
-    fn accepts(&self) -> bool {
-        self.accepts_frames.load(Ordering::Acquire) && self.is_active()
-    }
-
-    fn retire_playback(&self) {
-        let output = {
-            let mut binding = self.playback.lock().unwrap();
-            binding.controller = None;
-            binding.exit = None;
-            if let Some(handoff) = binding.handoff.take() {
-                handoff.cancel();
-            }
-            binding.audio_output.take()
-        };
-        if let Some(output) = output {
-            output.shutdown();
-        }
-    }
-}
-
-struct Entry {
-    control: Arc,
-    joined: RetainedJoin,
-}
-
-#[derive(Default)]
-struct ProjectConsumers {
-    ordinary_loading: bool,
-    entries: Vec,
-}
-
-#[derive(Default)]
-struct Registry {
-    projects: HashMap,
-    epochs: HashMap,
-}
-
-#[derive(Clone, Default)]
-pub(crate) struct PreparingConsumers(Arc>);
-
-impl PreparingConsumers {
-    pub(crate) async fn dispose_all(&self) -> Result<(), String> {
-        let paths = {
-            let registry = self.0.lock().unwrap();
-            for project in registry.projects.values() {
-                for entry in &project.entries {
-                    entry.control.cancel();
-                }
-            }
-            registry.projects.keys().cloned().collect::>()
-        };
-        let mut failure = None;
-        for path in paths {
-            if let Err(error) = self.before_ordinary_loading(&path).await {
-                failure.get_or_insert(error);
-            }
-        }
-        for project in self.0.lock().unwrap().projects.values() {
-            for entry in &project.entries {
-                entry.control.retire_playback();
-            }
-        }
-        failure.map_or(Ok(()), Err)
-    }
-
-    pub(crate) fn cancel_window(&self, window_id: u32, epoch: Option) {
-        let registry = self.0.lock().unwrap();
-        let mut closed = Vec::new();
-        for project in registry.projects.values() {
-            for entry in &project.entries {
-                if entry.control.window_id == window_id
-                    && epoch.is_none_or(|epoch| entry.control.request_epoch == epoch)
-                {
-                    let adopted = epoch.is_some()
-                        && entry
-                            .control
-                            .playback
-                            .lock()
-                            .unwrap()
-                            .handoff
-                            .as_ref()
-                            .is_some_and(|handoff| handoff.committed());
-                    if adopted {
-                        entry.control.accepts_frames.store(false, Ordering::Release);
-                        entry.control.cancelled.send_replace(true);
-                    } else {
-                        entry.control.cancel();
-                    }
-                    if epoch.is_none() {
-                        closed.push((entry.control.clone(), entry.joined.clone()));
-                    }
-                }
-            }
-        }
-        drop(registry);
-        if !closed.is_empty() {
-            let registry = self.clone();
-            drop(tokio::spawn(async move {
-                for (control, joined) in closed {
-                    let _ = joined.wait().await;
-                    control.retire_playback();
-                }
-                for project in registry.0.lock().unwrap().projects.values_mut() {
-                    project.entries.retain(|entry| {
-                        entry.control.window_id != window_id || !entry.joined.succeeded()
-                    });
-                }
-            }));
-        }
-    }
-
-    fn control_for_window(
-        &self,
-        window_id: u32,
-        epoch: Option,
-    ) -> Option> {
-        self.0
-            .lock()
-            .unwrap()
-            .projects
-            .values()
-            .flat_map(|project| &project.entries)
-            .filter(|entry| {
-                entry.control.window_id == window_id
-                    && epoch.is_none_or(|epoch| entry.control.request_epoch == epoch)
-            })
-            .max_by_key(|entry| entry.control.request_epoch)
-            .map(|entry| entry.control.clone())
-    }
-
-    pub(crate) fn snapshot_for_window(&self, window_id: u32) -> Option {
-        self.control_for_window(window_id, None)?
-            .playback
-            .lock()
-            .unwrap()
-            .latest
-            .clone()
-    }
-
-    pub(crate) async fn take_startup(
-        &self,
-        path: &Path,
-    ) -> Result<
-        (
-            Arc,
-            cap_editor::EditorStartupInputs,
-            Option,
-        ),
-        String,
-    > {
-        let latest = {
-            let registry = self.0.lock().unwrap();
-            registry.projects.get(path).and_then(|project| {
-                project
-                    .entries
-                    .iter()
-                    .filter(|entry| {
-                        entry.joined.succeeded()
-                            || (entry.control.is_active()
-                                && entry.control.finalization.allows_preparing_continuation())
-                    })
-                    .max_by_key(|entry| entry.control.request_epoch)
-                    .map(|entry| (entry.control.clone(), entry.joined.clone()))
-            })
-        };
-        if let Some((control, joined)) = latest {
-            let handoff = control.playback.lock().unwrap().handoff.clone();
-            let mut completed_audio = None;
-            let mut continuing = None;
-            if let Some(handoff) = handoff {
-                match handoff.take_completed_audio().await {
-                    Ok(audio) => {
-                        completed_audio = Some(audio);
-                        continuing = Some(handoff);
-                    }
-                    Err(_) => {
-                        control.cancel();
-                        joined.wait().await?;
-                    }
-                }
-            }
-            let mut binding = control.playback.lock().unwrap();
-            if completed_audio.is_none() {
-                completed_audio = binding
-                    .exit
-                    .take()
-                    .and_then(|exit| exit.take_completed_audio());
-            }
-            let output = binding
-                .audio_output
-                .take()
-                .unwrap_or_else(|| Arc::new(cap_editor::AudioOutput::new()));
-            return Ok((
-                output,
-                cap_editor::EditorStartupInputs {
-                    recordings: None,
-                    completed_audio,
-                },
-                continuing,
-            ));
-        }
-        Ok((
-            Arc::new(cap_editor::AudioOutput::new()),
-            cap_editor::EditorStartupInputs::default(),
-            None,
-        ))
-    }
-
-    pub(crate) async fn before_ordinary_loading(&self, path: &Path) -> Result<(), String> {
-        let pending = {
-            let mut registry = self.0.lock().unwrap();
-            let project = registry.projects.entry(path.to_path_buf()).or_default();
-            project.ordinary_loading = true;
-            project
-                .entries
-                .iter()
-                .filter_map(|entry| {
-                    if entry.control.is_active()
-                        && entry.control.finalization.allows_preparing_continuation()
-                        && entry.control.playback.lock().unwrap().handoff.is_some()
-                    {
-                        return None;
-                    }
-                    entry.control.cancel();
-                    Some(entry.joined.clone())
-                })
-                .collect::>()
-        };
-        let mut failure = None;
-        for joined in pending {
-            if let Err(error) = joined.wait().await {
-                failure.get_or_insert(error);
-            }
-        }
-        failure.map_or(Ok(()), Err)
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-pub(crate) async fn create_preparing_editor_frame(
-    window: Window,
-    request_epoch: u32,
-) -> Result, String> {
-    let CapWindowId::Editor { id } =
-        CapWindowId::from_str(window.label()).map_err(|error| error.to_string())?
-    else {
-        return Err("Invalid editor window".into());
-    };
-    let app = window.app_handle();
-    let window_ids = EditorWindowIds::get(app);
-    let path = window_ids
-        .ids
-        .lock()
-        .unwrap()
-        .iter()
-        .find(|(_, current)| *current == id)
-        .map(|(path, _)| path.clone())
-        .ok_or("Editor window is closed")?;
-    let project = FinalizationProject::observe(path.clone()).await?;
-    if path != project.work_path() {
-        return Ok(None);
-    }
-    let Some(finalization) = app
-        .state::()
-        .preparing_for_project(&project)
-    else {
-        return Ok(None);
-    };
-    let registry = app.state::().inner().clone();
-    let (response, result) = oneshot::channel();
-    {
-        let ids = window_ids.ids.lock().unwrap();
-        if !ids
-            .iter()
-            .any(|(registered, current)| *current == id && registered == &path)
-        {
-            return Ok(None);
-        }
-        let mut registry = registry.0.lock().unwrap();
-        if request_epoch == 0
-            || registry
-                .epochs
-                .get(&id)
-                .is_some_and(|epoch| *epoch >= request_epoch)
-        {
-            return Ok(None);
-        }
-        registry.epochs.insert(id, request_epoch);
-        let project = registry.projects.entry(path.clone()).or_default();
-        if project.ordinary_loading || !finalization.is_pending() {
-            return Ok(None);
-        }
-        project.entries.retain(|entry| !entry.joined.succeeded());
-        let previous = project
-            .entries
-            .iter()
-            .map(|entry| {
-                entry.control.cancel();
-                (entry.joined.clone(), entry.control.clone())
-            })
-            .collect();
-        let control = Arc::new(ConsumerControl {
-            window_ids: window_ids.clone(),
-            window_id: id,
-            request_epoch,
-            path,
-            finalization,
-            cancelled: watch::channel(false).0,
-            accepts_frames: AtomicBool::new(false),
-            playback: Mutex::default(),
-            publish: Some(Box::new({
-                let window = window.clone();
-                move |snapshot| {
-                    let _ = snapshot.emit_to(&window, window.label());
-                }
-            })),
-        });
-        let runner = Runner {
-            control: control.clone(),
-            previous,
-            response: Some(response),
-            transport: None,
-            stop: None,
-            frames: watch::channel(None).0,
-        };
-        let joined = RetainedJoin::new(tokio::spawn(runner.run()));
-        project.entries.push(Entry { control, joined });
-    }
-    result
-        .await
-        .map_err(|error| format!("Preparing frame admission failed: {error}"))
-}
-
-#[tauri::command]
-#[specta::specta]
-pub(crate) async fn stop_preparing_editor_frame(
-    window: Window,
-    request_epoch: u32,
-) -> Result<(), String> {
-    let CapWindowId::Editor { id } =
-        CapWindowId::from_str(window.label()).map_err(|error| error.to_string())?
-    else {
-        return Err("Invalid editor window".into());
-    };
-    window
-        .app_handle()
-        .state::()
-        .cancel_window(id, Some(request_epoch));
-    Ok(())
-}
-
-fn editor_window_id(window: &Window) -> Result {
-    match CapWindowId::from_str(window.label()).map_err(|error| error.to_string())? {
-        CapWindowId::Editor { id } => Ok(id),
-        _ => Err("Invalid editor window".into()),
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-pub(crate) fn get_preparing_editor_state(
-    window: Window,
-    request_epoch: u32,
-) -> Result, String> {
-    let id = editor_window_id(&window)?;
-    let state = window.state::();
-    Ok(state
-        .control_for_window(id, Some(request_epoch))
-        .and_then(|control| control.playback.lock().unwrap().latest.clone()))
-}
-
-fn playback_controller(
-    window: &Window,
-    request_epoch: u32,
-    job_id: &str,
-) -> Result {
-    let id = editor_window_id(window)?;
-    let control = window
-        .state::()
-        .control_for_window(id, Some(request_epoch))
-        .ok_or("Preparing editor is closed")?;
-    {
-        let binding = control.playback.lock().unwrap();
-        if binding
-            .latest
-            .as_ref()
-            .is_none_or(|latest| latest.job_id != job_id)
-        {
-            return Err("Preparing editor identity changed".into());
-        }
-        if binding
-            .handoff
-            .as_ref()
-            .is_some_and(|handoff| handoff.committed())
-        {
-            return Err("Preparing playback has been adopted".into());
-        }
-    }
-    if !control.is_active() {
-        return Err("Preparing editor has ended".into());
-    }
-    let binding = control.playback.lock().unwrap();
-    binding
-        .controller
-        .clone()
-        .ok_or_else(|| "Preparing playback is not available".into())
-}
-
-#[tauri::command]
-#[specta::specta]
-pub(crate) async fn seek_preparing_editor(
-    window: Window,
-    request_epoch: u32,
-    job_id: String,
-    seconds: f64,
-) -> Result<(), String> {
-    playback_controller(&window, request_epoch, &job_id)?
-        .seek(seconds)
-        .await
-}
-
-#[tauri::command]
-#[specta::specta]
-pub(crate) async fn set_preparing_editor_playing(
-    window: Window,
-    request_epoch: u32,
-    job_id: String,
-    playing: bool,
-) -> Result<(), String> {
-    playback_controller(&window, request_epoch, &job_id)?
-        .set_playing(playing)
-        .await
-}
-
-pub(crate) async fn join_before_ordinary(app: &AppHandle, path: &Path) -> Result<(), String> {
-    app.state::()
-        .inner()
-        .clone()
-        .before_ordinary_loading(path)
-        .await
-}
-
-struct Runner {
-    control: Arc,
-    previous: Vec<(RetainedJoin, Arc)>,
-    response: Option>>,
-    transport: Option,
-    stop: Option,
-    frames: watch::Sender>>,
-}
-
-impl Runner {
-    async fn run(mut self) -> Result<(), String> {
-        let result = AssertUnwindSafe(self.run_inner()).catch_unwind().await;
-        let adopted = matches!(&result, Ok(Ok(())))
-            && self
-                .control
-                .playback
-                .lock()
-                .unwrap()
-                .handoff
-                .as_ref()
-                .is_some_and(|handoff| handoff.committed());
-        if adopted {
-            self.control.accepts_frames.store(false, Ordering::Release);
-            self.control.cancelled.send_replace(true);
-            self.stop = None;
-        } else {
-            self.control.cancel();
-        }
-        self.frames.send_replace(None);
-        if let Some(response) = self.response.take() {
-            let _ = response.send(None);
-        }
-        let mut failure = match result {
-            Ok(Ok(())) => None,
-            Ok(Err(error)) => {
-                tracing::debug!(%error, "Tauri preparing preview declined");
-                None
-            }
-            Err(_) => {
-                tracing::warn!("Tauri preparing adapter panicked");
-                None
-            }
-        };
-        if let Some(stop) = &self.stop {
-            stop.cancel();
-        }
-        if let Some(transport) = self.transport.take()
-            && let Err(error) = transport.stop_and_wait().await
-        {
-            failure.get_or_insert(error);
-        }
-        if let Some(stop) = self.stop.take() {
-            let exit = stop.stop_and_wait().await;
-            self.control.publish_snapshot(&exit.snapshot);
-            if exit.cleanup_failed {
-                failure.get_or_insert_with(|| {
-                    exit.error
-                        .clone()
-                        .unwrap_or_else(|| "Preparing media cleanup failed".into())
-                });
-            }
-            let mut binding = self.control.playback.lock().unwrap();
-            binding.controller = None;
-            binding.exit = Some(exit);
-        }
-        failure.map_or(Ok(()), Err)
-    }
-
-    async fn run_inner(&mut self) -> Result<(), String> {
-        for (previous, control) in &self.previous {
-            let result = previous.wait().await;
-            control.retire_playback();
-            result?;
-        }
-        if !self.control.is_active() {
-            return Ok(());
-        }
-        let control = self.control.clone();
-        let transport = crate::frame_ws::create_owned_watch_frame_ws(
-            self.frames.subscribe(),
-            Arc::new(move || control.accepts()),
-        )
-        .await?;
-        let url = transport.url.clone();
-        self.transport = Some(transport);
-        if let Some(response) = self.response.take()
-            && response.send(Some(url)).is_err()
-        {
-            return Ok(());
-        }
-        let mut cancel = self.control.cancelled.subscribe();
-        if *cancel.borrow() {
-            return Ok(());
-        }
-        let observer = tokio::select! {
-            biased;
-            _ = cancel.changed() => return Ok(()),
-            observer = self.control.finalization.wait_for_preparing() => observer,
-        };
-        let Some(mut observer) = observer else {
-            return Ok(());
-        };
-        let presentation = tokio::select! {
-            biased;
-            _ = cancel.changed() => return Ok(()),
-            presentation = self.control.finalization.wait_for_presentation() => presentation,
-        };
-        let Some(presentation) = presentation else {
-            return Ok(());
-        };
-        let sources = loop {
-            match observer.latest() {
-                PreparingStudioState::Available(sources) => break sources,
-                PreparingStudioState::Unavailable(error) => return Err(error),
-                PreparingStudioState::Ended => return Ok(()),
-                PreparingStudioState::Waiting => {}
-            }
-            tokio::select! {
-                biased;
-                _ = cancel.changed() => return Ok(()),
-                _ = observer.changed() => {},
-            }
-        };
-        let control = self.control.clone();
-        let job_id = sources.identity().job_id().to_string();
-        let (input, audio) =
-            tokio::task::spawn_blocking(move || adapt(sources, &control, &presentation))
-                .await
-                .map_err(|error| format!("Preparing adapter join failed: {error}"))??;
-        if !self.control.is_active()
-            || !matches!(observer.latest(), PreparingStudioState::Available(_))
-        {
-            return Ok(());
-        }
-        let control = self.control.clone();
-        let frame_observer = observer.clone();
-        let frames = self.frames.clone();
-        let mut tracks = vec!["display".to_string()];
-        if let Some(cap_project::StudioRecordingMeta::MultipleSegments { inner }) =
-            input.recording_meta.studio_meta()
-        {
-            if inner
-                .segments
-                .iter()
-                .any(|segment| segment.camera.is_some())
-            {
-                tracks.push("camera".into());
-            }
-            if inner.segments.iter().any(|segment| segment.mic.is_some()) {
-                tracks.push("microphone".into());
-            }
-            if inner
-                .segments
-                .iter()
-                .any(|segment| segment.system_audio.is_some())
-            {
-                tracks.push("systemAudio".into());
-            }
-        }
-        let audio_output = Arc::new(cap_editor::AudioOutput::new());
-        {
-            let mut binding = self.control.playback.lock().unwrap();
-            binding.audio_output = Some(audio_output.clone());
-            binding.latest = Some(PreparingEditorChanged {
-                request_epoch: self.control.request_epoch,
-                job_id,
-                sequence: 0,
-                fps: crate::EDITOR_PREVIEW_FPS,
-                progress: PreparingEditorProgress::default(),
-                playback: PreparingPlaybackState::default(),
-                seed: PreparingEditorSeed {
-                    title: input.recording_meta.pretty_name.clone(),
-                    tracks,
-                },
-            });
-        }
-        self.control.accepts_frames.store(true, Ordering::Release);
-        let session = PreparingPlaybackSession::spawn_with_expected_metadata(
-            input,
-            audio.tracks,
-            PreparingPlaybackOptions {
-                preview: PreparingPreviewOptions {
-                    use_hardware_decoding: !cfg!(target_os = "windows"),
-                    frame_format: EditorFrameFormat::Rgba,
-                    shared_device: None,
-                },
-                fps: crate::EDITOR_PREVIEW_FPS,
-                resolution: crate::default_editor_preview_resolution(),
-            },
-            audio_output,
-            Box::new(move |_, output, _| {
-                if control.accepts()
-                    && (matches!(frame_observer.latest(), PreparingStudioState::Available(_))
-                        || control.finalization.allows_preparing_continuation())
-                    && let Some(frame) = crate::editor_window::frame_for_websocket(output)
-                {
-                    #[cfg(debug_assertions)]
-                    crate::stop_editor_benchmark::capture_ws_frame(
-                        crate::stop_editor_benchmark::CaptureKind::Preparing,
-                        &control.path,
-                        &frame,
-                    );
-                    frames.send_replace(Some(Arc::new(frame)));
-                }
-            }),
-            audio.expected_metadata,
-        )?;
-        self.stop = Some(session.stop_handle());
-        let handoff = session.handoff_handle();
-        {
-            let mut binding = self.control.playback.lock().unwrap();
-            binding.controller = Some(session.controller());
-            binding.handoff = Some(handoff.clone());
-        }
-        let mut updates = session.updates();
-        self.control
-            .publish_snapshot(&updates.borrow_and_update().clone());
-        let mut health = tokio::time::interval(Duration::from_millis(50));
-        let mut observing = true;
-        loop {
-            tokio::select! {
-                biased;
-                _ = cancel.changed() => return Ok(()),
-                _ = handoff.wait_committed() => return Ok(()),
-                state = observer.changed(), if observing => {
-                    if !matches!(state, PreparingStudioState::Available(_)) {
-                        if !self.control.finalization.allows_preparing_continuation() { return Ok(()); }
-                        observing = false;
-                    }
-                },
-                changed = updates.changed() => {
-                    if changed.is_err() { return Ok(()); }
-                    let snapshot = updates.borrow_and_update().clone();
-                    self.control.publish_snapshot(&snapshot);
-                    if snapshot.progress.phase != cap_editor::PreparingEditorPhase::Preparing {
-                        return Ok(());
-                    }
-                },
-                _ = health.tick() => {
-                    if !self.control.is_active() { return Ok(()); }
-                    if self.transport.as_ref().is_some_and(OwnedWatchFrameWs::is_finished) {
-                        return Ok(());
-                    }
-
-                },
-            }
-        }
-    }
-}
-
-fn ensure_preparing_stopped_layout(
-    timeline: &cap_project::TimelineConfiguration,
-    studio: &cap_project::StudioRecordingMeta,
-) -> Result<(), String> {
-    if timeline.segments.len() != 1 || studio.display_notch().is_some() {
-        Err("Tauri preparing requires one screen segment without a recorded notch".into())
-    } else {
-        Ok(())
-    }
-}
-
-pub(crate) fn project_from_preparing_presentation(
-    presentation: &ProjectConfiguration,
-    stopped_timeline: &cap_project::TimelineConfiguration,
-) -> ProjectConfiguration {
-    let mut project = presentation.clone();
-    project.timeline = Some(crate::recording::recording_timeline(
-        stopped_timeline.segments.clone(),
-        Vec::new(),
-    ));
-    project
-}
-
-fn ensure_preparing_track_presentation<'a>(
-    tracks: impl IntoIterator, Option<&'a Path>)>,
-) -> Result<(), String> {
-    if tracks
-        .into_iter()
-        .any(|(camera, keyboard)| camera.is_some() || keyboard.is_some())
-    {
-        Err("Camera and keyboard presentation require ordinary editor loading".into())
-    } else {
-        Ok(())
-    }
-}
-
-fn ensure_preparing_cursor_presentation(cursor: &CursorEvents) -> Result<(), String> {
-    if cursor.clicks.is_empty() {
-        Ok(())
-    } else {
-        Err("Recorded clicks require late ordinary auto-zoom settings".into())
-    }
-}
-
-fn adapt(
-    sources: Arc,
-    control: &Arc,
-    presentation: &ProjectConfiguration,
-) -> Result<(PreparingPreviewInput, audio::AudioAdaptation), String> {
-    let ended = || "Preparing sources ended".to_string();
-    let live = sources.live().ok_or_else(ended)?;
-    let recording_meta = live.metadata().ok_or_else(ended)?.clone();
-    let studio = recording_meta.studio_meta().ok_or_else(ended)?;
-
-    let timeline = live
-        .configuration()
-        .ok_or_else(ended)?
-        .timeline
-        .as_ref()
-        .ok_or("Missing stopped timeline")?;
-    ensure_preparing_stopped_layout(timeline, studio)?;
-    let mut project = project_from_preparing_presentation(presentation, timeline);
-    if project.clips.is_empty() {
-        project.clips =
-            cap_editor::initial_clip_configuration(&recording_meta.project_path, studio);
-    }
-    let descriptors = live.segments().ok_or_else(ended)?;
-    ensure_preparing_track_presentation(descriptors.iter().map(|segment| {
-        (
-            segment
-                .camera()
-                .map(cap_recording::recovery::PreparingVideoInput::metadata),
-            segment.keyboard_path(),
-        )
-    }))?;
-    let pointer_ids = studio.pointer_cursor_ids();
-    let mut segments = Vec::with_capacity(descriptors.len());
-    let mut cursor_budget = MAX_CURSOR_BYTES;
-    for descriptor in descriptors {
-        if *control.cancelled.borrow() || sources.live().is_none() {
-            return Err(ended());
-        }
-        let display = live
-            .video(descriptor.index(), PreparingVideoTrack::Display)
-            .ok_or_else(ended)?;
-        let (source, paths) = display.input().ok_or_else(ended)?;
-        let display = ManagedVideoTrackInput::new(source.clone(), paths.to_vec())
-            .map_err(|error| error.to_string())?;
-        let camera = if descriptor.camera().is_some() {
-            let camera = live
-                .video(descriptor.index(), PreparingVideoTrack::Camera)
-                .ok_or_else(ended)?;
-            let (source, paths) = camera.input().ok_or_else(ended)?;
-            Some(
-                ManagedVideoTrackInput::new(source.clone(), paths.to_vec())
-                    .map_err(|error| error.to_string())?,
-            )
-        } else {
-            None
-        };
-        let mut cursor = if descriptor.cursor_path().is_some() {
-            let cursor = live
-                .sidecar(descriptor.index(), PreparingSidecarKind::Cursor)
-                .ok_or_else(ended)?;
-            let (source, path) = cursor.input().ok_or_else(ended)?;
-            let reader = source.reader(path).map_err(|error| error.to_string())?;
-            let mut reader = BufReader::new(CheckedCursorReader {
-                reader,
-                is_live: || !*control.cancelled.borrow() && sources.live().is_some(),
-                remaining: cursor_budget,
-            });
-            let cursor = CursorEvents::load_from_reader(&mut reader)?;
-            cursor_budget = reader.get_ref().remaining;
-            cursor
-        } else {
-            CursorEvents::default()
-        };
-        ensure_preparing_cursor_presentation(&cursor)?;
-        cursor.stabilize_short_lived_cursor_shapes(
-            (!pointer_ids.is_empty()).then_some(&pointer_ids),
-            cap_project::cursor::SHORT_CURSOR_SHAPE_DEBOUNCE_MS,
-        );
-        segments.push(PreparingPreviewSegment {
-            video: ManagedSegmentVideoInput::new(
-                descriptor.index() as usize,
-                studio,
-                display,
-                camera,
-            )
-            .map_err(|error| error.to_string())?,
-            cursor: Arc::new(cursor),
-        });
-    }
-    let images = descriptors
-        .first()
-        .ok_or_else(ended)?
-        .cursor_images()
-        .iter()
-        .map(|asset| {
-            (
-                asset.id().to_string(),
-                asset.metadata().clone(),
-                Arc::<[u8]>::from(asset.bytes()),
-            )
-        });
-    let cursor_assets =
-        FrozenRecordedCursorAssets::new(images).map_err(|error| error.to_string())?;
-    if *control.cancelled.borrow() || sources.live().is_none() {
-        return Err(ended());
-    }
-    let audio = audio::adapt_audio(&sources, &recording_meta, control)?;
-    Ok((
-        PreparingPreviewInput {
-            recording_meta,
-            project,
-            segments,
-            cursor_assets,
-        },
-        audio,
-    ))
-}
-
-struct CheckedCursorReader {
-    reader: R,
-    is_live: F,
-    remaining: u64,
-}
-
-impl bool> Read for CheckedCursorReader {
-    fn read(&mut self, output: &mut [u8]) -> io::Result {
-        if output.is_empty() {
-            return Ok(0);
-        }
-        if !(self.is_live)() {
-            return Err(io::Error::other("Preparing sources ended"));
-        }
-        if self.remaining == 0 {
-            let mut next = [0];
-            return if self.reader.read(&mut next)? == 0 {
-                Ok(0)
-            } else {
-                Err(io::Error::new(
-                    io::ErrorKind::InvalidData,
-                    "Cursor sidecar exceeds preparing limit",
-                ))
-            };
-        }
-        let length = output.len().min(self.remaining as usize);
-        let count = self.reader.read(&mut output[..length])?;
-        self.remaining -= count as u64;
-        Ok(count)
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use crate::FinalizationAccess;
-
-    fn control(
-        path: &Path,
-        window_id: u32,
-        epoch: u32,
-    ) -> (crate::FinalizationToken, Arc) {
-        let project =
-            FinalizationProject::capture(path.to_path_buf(), FinalizationAccess::Write).unwrap();
-        let finalizations = FinalizingRecordings::default();
-        let token = finalizations.start_finalizing(project).unwrap();
-        let window_ids = EditorWindowIds::default();
-        window_ids
-            .ids
-            .lock()
-            .unwrap()
-            .push((path.to_path_buf(), window_id));
-        let control = Arc::new(ConsumerControl {
-            window_ids,
-            window_id,
-            request_epoch: epoch,
-            path: path.to_path_buf(),
-            finalization: token.preparing(),
-            cancelled: watch::channel(false).0,
-            accepts_frames: AtomicBool::new(true),
-            playback: Mutex::default(),
-            publish: None,
-        });
-        (token, control)
-    }
-
-    #[tokio::test]
-    async fn abandoned_admission_joins_transport_without_waiting_for_finalization() {
-        let directory = tempfile::tempdir().unwrap();
-        let path = directory.path().canonicalize().unwrap();
-        let (token, control) = control(&path, 1, 1);
-        let (response, receiver) = oneshot::channel();
-        drop(receiver);
-        let runner = Runner {
-            control: control.clone(),
-            previous: Vec::new(),
-            response: Some(response),
-            transport: None,
-            stop: None,
-            frames: watch::channel(None).0,
-        };
-        tokio::time::timeout(Duration::from_secs(2), runner.run())
-            .await
-            .expect("Abandoned admission waited for recording finalization")
-            .unwrap();
-        assert!(!control.is_active());
-        assert!(control.finalization.is_pending());
-        token.finish(Ok(()));
-    }
-
-    #[tokio::test]
-    async fn loading_barrier_cancels_and_joins_even_when_the_first_waiter_is_dropped() {
-        let directory = tempfile::tempdir().unwrap();
-        let path = directory.path().canonicalize().unwrap();
-        let (_token, control) = control(&path, 1, 1);
-        let (release, receiver) = oneshot::channel();
-        let (completed, mut completion) = watch::channel(false);
-        let joined = RetainedJoin::new(tokio::spawn(async move {
-            receiver.await.unwrap();
-            completed.send_replace(true);
-            Ok(())
-        }));
-        let registry = PreparingConsumers::default();
-        registry
-            .0
-            .lock()
-            .unwrap()
-            .projects
-            .entry(path.clone())
-            .or_default()
-            .entries
-            .push(Entry {
-                control: control.clone(),
-                joined: joined.clone(),
-            });
-        let waiter = {
-            let registry = registry.clone();
-            let path = path.clone();
-            tokio::spawn(async move { registry.before_ordinary_loading(&path).await })
-        };
-        while !*control.cancelled.borrow() {
-            tokio::task::yield_now().await;
-        }
-        assert!(!waiter.is_finished());
-        assert!(registry.0.lock().unwrap().projects[&path].ordinary_loading);
-        waiter.abort();
-        assert!(waiter.await.unwrap_err().is_cancelled());
-        release.send(()).unwrap();
-        completion.wait_for(|done| *done).await.unwrap();
-        joined.wait().await.unwrap();
-        registry.before_ordinary_loading(&path).await.unwrap();
-    }
-
-    #[tokio::test]
-    async fn replacement_admission_retires_previous_audio_after_join() {
-        let directory = tempfile::tempdir().unwrap();
-        let path = directory.path().canonicalize().unwrap();
-        let (_previous_token, previous) = control(&path, 1, 1);
-        let (_next_token, next) = control(&path, 1, 2);
-        let output = Arc::new(cap_editor::AudioOutput::new());
-        let retained = Arc::downgrade(&output);
-        previous.playback.lock().unwrap().audio_output = Some(output);
-        let (release, receiver) = oneshot::channel();
-        let joined = RetainedJoin::new(tokio::spawn(async move {
-            receiver.await.unwrap();
-            Ok(())
-        }));
-        let (response, receiver) = oneshot::channel();
-        drop(receiver);
-        let runner = Runner {
-            control: next,
-            previous: vec![(joined, previous)],
-            response: Some(response),
-            transport: None,
-            stop: None,
-            frames: watch::channel(None).0,
-        };
-        let task = tokio::spawn(runner.run());
-        tokio::task::yield_now().await;
-        assert!(retained.upgrade().is_some());
-        assert!(!task.is_finished());
-        release.send(()).unwrap();
-        tokio::time::timeout(Duration::from_secs(2), task)
-            .await
-            .unwrap()
-            .unwrap()
-            .unwrap();
-        assert!(retained.upgrade().is_none());
-    }
-
-    #[tokio::test]
-    async fn failed_cleanup_remains_a_barrier_on_reopen_and_retry() {
-        let directory = tempfile::tempdir().unwrap();
-        let path = directory.path().canonicalize().unwrap();
-        let (_token, control) = control(&path, 1, 1);
-        let joined = RetainedJoin::new(tokio::spawn(async {
-            panic!("injected owned cleanup failure");
-        }));
-        let registry = PreparingConsumers::default();
-        registry
-            .0
-            .lock()
-            .unwrap()
-            .projects
-            .entry(path.clone())
-            .or_default()
-            .entries
-            .push(Entry { control, joined });
-        let first = registry.before_ordinary_loading(&path).await.unwrap_err();
-        let next = registry.before_ordinary_loading(&path).await.unwrap_err();
-        assert_eq!(first, next);
-        assert_eq!(registry.0.lock().unwrap().projects[&path].entries.len(), 1);
-    }
-
-    #[tokio::test]
-    async fn closed_window_retires_audio_only_after_owned_cleanup_finishes() {
-        let directory = tempfile::tempdir().unwrap();
-        let path = directory.path().canonicalize().unwrap();
-        let (_token, control) = control(&path, 3, 1);
-        let output = Arc::new(cap_editor::AudioOutput::new());
-        let retained = Arc::downgrade(&output);
-        control.playback.lock().unwrap().audio_output = Some(output);
-        let (release, receiver) = oneshot::channel();
-        let joined = RetainedJoin::new(tokio::spawn(async move {
-            receiver.await.unwrap();
-            Ok(())
-        }));
-        let registry = PreparingConsumers::default();
-        registry
-            .0
-            .lock()
-            .unwrap()
-            .projects
-            .entry(path.clone())
-            .or_default()
-            .entries
-            .push(Entry {
-                control: control.clone(),
-                joined,
-            });
-        registry.cancel_window(3, None);
-        tokio::task::yield_now().await;
-        assert!(retained.upgrade().is_some());
-        assert!(!control.is_active());
-        release.send(()).unwrap();
-        tokio::time::timeout(Duration::from_secs(2), async {
-            loop {
-                if registry.0.lock().unwrap().projects[&path]
-                    .entries
-                    .is_empty()
-                {
-                    break;
-                }
-                tokio::task::yield_now().await;
-            }
-        })
-        .await
-        .unwrap();
-        assert!(retained.upgrade().is_none());
-    }
-
-    #[tokio::test]
-    async fn old_frontend_stop_does_not_cancel_a_new_window_request() {
-        let directory = tempfile::tempdir().unwrap();
-        let path = directory.path().canonicalize().unwrap();
-        let (_token, control) = control(&path, 8, 2);
-        let registry = PreparingConsumers::default();
-        let joined = RetainedJoin::new(tokio::spawn(async { Ok(()) }));
-        registry
-            .0
-            .lock()
-            .unwrap()
-            .projects
-            .entry(path)
-            .or_default()
-            .entries
-            .push(Entry {
-                control: control.clone(),
-                joined,
-            });
-        registry.cancel_window(8, Some(1));
-        registry.cancel_window(7, None);
-        assert!(control.accepts());
-        registry.cancel_window(8, Some(2));
-        assert!(!control.accepts());
-    }
-
-    #[test]
-    fn native_registration_and_finalization_both_guard_frame_delivery() {
-        let directory = tempfile::tempdir().unwrap();
-        let path = directory.path().canonicalize().unwrap();
-        let (token, control) = control(&path, 1, 1);
-        assert!(control.accepts());
-        control.window_ids.ids.lock().unwrap().clear();
-        assert!(!control.accepts());
-        control.window_ids.ids.lock().unwrap().push((path, 2));
-        assert!(!control.accepts());
-        token.finish(Ok(()));
-        assert!(!control.is_active());
-    }
-
-    #[test]
-    fn cancelled_cursor_parse_terminates_without_retrying_interrupted_reads() {
-        let mut reader = CheckedCursorReader {
-            reader: std::io::Cursor::new([1, 2]),
-            is_live: || false,
-            remaining: 2,
-        };
-        let error = reader.read(&mut [0; 1]).unwrap_err();
-        assert_ne!(error.kind(), std::io::ErrorKind::Interrupted);
-        assert_eq!(reader.reader.position(), 0);
-    }
-}
-
-#[cfg(test)]
-mod presentation_guard_tests {
-    use super::*;
-
-    fn camera() -> cap_project::VideoMeta {
-        serde_json::from_value(serde_json::json!({
-            "path": "camera", "fps": 24, "start_time": 0.125
-        }))
-        .unwrap()
-    }
-
-    #[test]
-    fn screen_only_descriptors_pass_but_any_recorded_camera_is_declined() {
-        let camera = camera();
-        ensure_preparing_track_presentation([(None, None)]).unwrap();
-        for tracks in [
-            vec![(Some(&camera), None)],
-            vec![(None, None), (Some(&camera), None)],
-        ] {
-            assert_eq!(
-                ensure_preparing_track_presentation(tracks).unwrap_err(),
-                "Camera and keyboard presentation require ordinary editor loading"
-            );
-        }
-    }
-
-    #[test]
-    fn keyboard_sidecars_decline_even_without_a_camera_or_visible_overlay() {
-        for path in [Path::new("keyboard.json"), Path::new("keyboard.msgpack")] {
-            assert_eq!(
-                ensure_preparing_track_presentation([(None, Some(path))]).unwrap_err(),
-                "Camera and keyboard presentation require ordinary editor loading"
-            );
-        }
-    }
-
-    #[test]
-    fn click_up_and_click_down_both_decline_but_pointer_movement_alone_passes() {
-        let mut cursor = CursorEvents::default();
-        cursor.moves.push(cap_project::CursorMoveEvent {
-            active_modifiers: Vec::new(),
-            cursor_id: "arrow".into(),
-            time_ms: 0.0,
-            x: 0.2,
-            y: 0.8,
-        });
-        ensure_preparing_cursor_presentation(&cursor).unwrap();
-        for down in [false, true] {
-            cursor.clicks = vec![cap_project::CursorClickEvent {
-                active_modifiers: Vec::new(),
-                cursor_num: 0,
-                cursor_id: "arrow".into(),
-                time_ms: 0.0,
-                down,
-            }];
-            assert_eq!(
-                ensure_preparing_cursor_presentation(&cursor).unwrap_err(),
-                "Recorded clicks require late ordinary auto-zoom settings"
-            );
-        }
-    }
-    #[test]
-    fn stopped_layout_rejects_multiple_or_missing_segments_and_recorded_notches() {
-        let segment = cap_project::TimelineSegment {
-            recording_clip: 0,
-            start: 0.0,
-            end: 6.0,
-            timescale: 1.0,
-            name: None,
-            speed_audio_mode: None,
-            hide_cursor: None,
-            volume: None,
-        };
-        for notch in [
-            None,
-            Some(cap_project::DisplayNotch {
-                x: 0.4,
-                width: 0.2,
-                height: 0.03,
-            }),
-        ] {
-            let metadata: cap_project::RecordingMeta = serde_json::from_value(serde_json::json!({
-                "pretty_name": "Tauri presentation metadata", "sharing": null,
-                "segments": [{"display": {"path": "display", "fps": 30, "start_time": 0.0}, "display_notch": notch}]
-            })).unwrap();
-            for count in [0, 1, 2] {
-                let timeline =
-                    crate::recording::recording_timeline(vec![segment.clone(); count], Vec::new());
-                let result =
-                    ensure_preparing_stopped_layout(&timeline, metadata.studio_meta().unwrap());
-                assert_eq!(result.is_ok(), count == 1 && notch.is_none());
-                if let Err(error) = result {
-                    assert_eq!(
-                        error,
-                        "Tauri preparing requires one screen segment without a recorded notch"
-                    );
-                }
-            }
-        }
-    }
-}
diff --git a/apps/desktop/src-tauri/src/editor_preparing/audio.rs b/apps/desktop/src-tauri/src/editor_preparing/audio.rs
deleted file mode 100644
index a7e106ada93..00000000000
--- a/apps/desktop/src-tauri/src/editor_preparing/audio.rs
+++ /dev/null
@@ -1,227 +0,0 @@
-use super::*;
-use cap_editor::PreparingAudioSegmentInput;
-use cap_project::{AudioMeta, RecordingMeta, StudioRecordingMeta};
-use cap_recording::recovery::PreparingAudioTrack;
-
-const MAX_AUDIO_TIMING_LOG_BYTES: u64 = 4 * 1024 * 1024;
-
-pub(super) struct AudioAdaptation {
-    pub(super) tracks: Vec,
-    pub(super) expected_metadata: RecordingMeta,
-}
-
-pub(super) fn adapt_audio(
-    sources: &Arc,
-    metadata: &RecordingMeta,
-    control: &Arc,
-) -> Result {
-    let mut expected_metadata = metadata.clone();
-    let cap_project::RecordingMetaInner::Studio(studio) = &mut expected_metadata.inner else {
-        return Err("Preparing audio requires Studio metadata".into());
-    };
-    let StudioRecordingMeta::MultipleSegments { inner } = studio.as_mut() else {
-        return Err("Preparing audio requires stopped segments".into());
-    };
-    for segment in &mut inner.segments {
-        for audio in [&mut segment.mic, &mut segment.system_audio]
-            .into_iter()
-            .flatten()
-        {
-            audio.gap_summary = None;
-        }
-    }
-    let expected_meta = expected_metadata
-        .studio_meta()
-        .ok_or("Preparing Studio metadata ended")?;
-    // Clean Stop joins the synchronous writers of timing-repair lines; finalization can still append unrelated log events.
-    let timing_log = read_timing_log(
-        &metadata.project_path.join("recording-logs.log"),
-        MAX_AUDIO_TIMING_LOG_BYTES,
-    );
-    let timing_eligible = timing_log.is_ok();
-    if let Err(error) = &timing_log {
-        tracing::debug!(%error, "Preparing audio timing requires ordinary loading");
-    }
-    let timing_log = timing_log.ok().flatten();
-    let repairs = cap_editor::segment_audio_timing_repairs(expected_meta, timing_log.as_deref());
-    let live = sources.live().ok_or("Preparing audio sources ended")?;
-    let descriptors = live.segments().ok_or("Preparing audio sources ended")?;
-    let mut tracks = Vec::with_capacity(descriptors.len());
-    for (index, descriptor) in descriptors.iter().enumerate() {
-        let repair = *repairs
-            .get(index)
-            .ok_or("Preparing audio timing layout changed")?;
-        let track = |kind, stem| {
-            if !timing_eligible {
-                return None;
-            }
-            let lease = live.audio(descriptor.index(), kind)?;
-            let metadata = lease.metadata()?;
-            let (source, path) = lease.input()?;
-            if !preserved_audio_path(metadata, path, stem) {
-                return None;
-            }
-            if path.extension().is_some_and(|extension| extension == "m4a") {
-                let control = control.clone();
-                let sources = sources.clone();
-                let input = cap_enc_ffmpeg::SegmentedInput::open_relocatable_interruptible(
-                    source,
-                    [path],
-                    Arc::new(move || *control.cancelled.borrow() || sources.live().is_none()),
-                )
-                .ok()?;
-                if input
-                    .input()
-                    .streams()
-                    .best(ffmpeg::media::Type::Video)
-                    .is_some()
-                    || !input
-                        .input()
-                        .streams()
-                        .best(ffmpeg::media::Type::Audio)
-                        .is_some_and(|stream| stream.parameters().id() == ffmpeg::codec::Id::AAC)
-                {
-                    return None;
-                }
-            }
-            cap_audio::ManagedAudioInput::new(source.clone(), path.to_path_buf()).ok()
-        };
-        tracks.push(PreparingAudioSegmentInput {
-            mic: track(PreparingAudioTrack::Mic, "audio-input"),
-            system_audio: track(PreparingAudioTrack::SystemAudio, "system_audio"),
-            timing_repair: repair,
-        });
-        if *control.cancelled.borrow() || sources.live().is_none() {
-            return Err("Preparing audio sources ended".into());
-        }
-    }
-    Ok(AudioAdaptation {
-        tracks,
-        expected_metadata,
-    })
-}
-
-fn read_timing_log(path: &Path, limit: u64) -> Result, String> {
-    let initial = match std::fs::symlink_metadata(path) {
-        Ok(metadata) => metadata,
-        Err(error) if error.kind() == io::ErrorKind::NotFound => return Ok(None),
-        Err(error) => return Err(format!("Preparing audio timing log metadata: {error}")),
-    };
-    if !initial.is_file() || initial.len() > limit {
-        return Err("Preparing audio timing log is not a bounded regular file".into());
-    }
-    let file = std::fs::File::open(path)
-        .map_err(|error| format!("Preparing audio timing log open: {error}"))?;
-    let opened = file.metadata().map_err(|error| error.to_string())?;
-    if !opened.is_file()
-        || opened.len() != initial.len()
-        || opened.modified().ok() != initial.modified().ok()
-    {
-        return Err("Preparing audio timing log changed before reading".into());
-    }
-    let mut bytes = String::with_capacity(opened.len() as usize);
-    let mut bounded = file.take(limit.saturating_add(1));
-    bounded
-        .read_to_string(&mut bytes)
-        .map_err(|error| format!("Preparing audio timing log read: {error}"))?;
-    let finished = bounded
-        .get_ref()
-        .metadata()
-        .map_err(|error| error.to_string())?;
-    if bytes.len() as u64 != opened.len()
-        || finished.len() != opened.len()
-        || finished.modified().ok() != opened.modified().ok()
-    {
-        return Err("Preparing audio timing log changed while reading".into());
-    }
-    Ok(Some(bytes))
-}
-
-fn preserved_audio_path(metadata: &AudioMeta, relative: &Path, stem: &str) -> bool {
-    let expected = Path::new("content/segments").join(relative);
-    if Path::new(metadata.path.as_str()) != expected {
-        return false;
-    }
-    ["m4a", "ogg"].into_iter().any(|extension| {
-        relative
-            .file_name()
-            .is_some_and(|name| name == format!("{stem}.{extension}").as_str())
-    })
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn timing_snapshot_preserves_utf8_and_distinguishes_absence_from_ineligible() {
-        let root = tempfile::tempdir().unwrap();
-        let path = root.path().join("recording-logs.log");
-        assert_eq!(read_timing_log(&path, 100).unwrap(), None);
-        let text = "微phone segment{index=0}:mic-out: Dropping overlapping audio frame frame_count=1 overlap_ms=100\n";
-        std::fs::write(&path, text).unwrap();
-        assert_eq!(
-            read_timing_log(&path, text.len() as u64)
-                .unwrap()
-                .as_deref(),
-            Some(text)
-        );
-        assert!(read_timing_log(&path, text.len() as u64 - 1).is_err());
-        std::fs::write(&path, [0xff, 0xfe]).unwrap();
-        assert!(read_timing_log(&path, 100).is_err());
-        assert!(read_timing_log(root.path(), 100).is_err());
-    }
-
-    #[test]
-    fn oversized_timing_log_is_declined_without_reading_its_payload() {
-        let root = tempfile::tempdir().unwrap();
-        let path = root.path().join("recording-logs.log");
-        let file = std::fs::File::create(&path).unwrap();
-        file.set_len(MAX_AUDIO_TIMING_LOG_BYTES + 1).unwrap();
-        assert!(read_timing_log(&path, MAX_AUDIO_TIMING_LOG_BYTES).is_err());
-    }
-
-    #[cfg(unix)]
-    #[test]
-    fn timing_log_symlink_is_ineligible() {
-        let root = tempfile::tempdir().unwrap();
-        let target = root.path().join("target.log");
-        let path = root.path().join("recording-logs.log");
-        std::fs::write(&target, "retained").unwrap();
-        std::os::unix::fs::symlink(&target, &path).unwrap();
-        assert!(read_timing_log(&path, 100).is_err());
-    }
-
-    #[test]
-    fn audio_admission_requires_the_unchanged_final_path_and_container_name() {
-        let metadata = |path: &str| AudioMeta {
-            path: path.into(),
-            start_time: Some(0.0),
-            device_id: None,
-            gap_summary: None,
-            digital_silence_ms: None,
-        };
-        for extension in ["m4a", "ogg"] {
-            let relative = PathBuf::from(format!("segment-0/audio-input.{extension}"));
-            let meta = metadata(&format!("content/segments/{}", relative.display()));
-            assert!(preserved_audio_path(&meta, &relative, "audio-input"));
-            assert!(!preserved_audio_path(&meta, &relative, "system_audio"));
-        }
-        for path in [
-            "segment-0/audio-input.mp3",
-            "segment-0/audio-input/audio.m4a",
-            "segment-0/audio-input.M4A",
-        ] {
-            assert!(!preserved_audio_path(
-                &metadata(&format!("content/segments/{path}")),
-                Path::new(path),
-                "audio-input"
-            ));
-        }
-        assert!(!preserved_audio_path(
-            &metadata("content/segments/other/audio-input.m4a"),
-            Path::new("segment-0/audio-input.m4a"),
-            "audio-input"
-        ));
-    }
-}
diff --git a/apps/desktop/src-tauri/src/editor_recording.rs b/apps/desktop/src-tauri/src/editor_recording.rs
deleted file mode 100644
index 8300cbb16ac..00000000000
--- a/apps/desktop/src-tauri/src/editor_recording.rs
+++ /dev/null
@@ -1,206 +0,0 @@
-use std::path::{Path, PathBuf};
-use std::sync::Mutex;
-
-use cap_project::RecordingMeta;
-use cap_recording::RecordingMode;
-use tauri::{AppHandle, Manager};
-use tauri_specta::Event;
-
-use crate::recording_settings::RecordingSettingsStore;
-use crate::windows::{EditorRecordingTarget, ShowCapWindow, editor_window_for_path};
-use crate::{App, ArcLock, tray};
-
-#[derive(serde::Serialize, serde::Deserialize, specta::Type, Debug, Clone, PartialEq, Eq)]
-#[serde(rename_all = "camelCase")]
-pub struct EditorRecordingFlowInfo {
-    pub project_path: PathBuf,
-    pub project_name: String,
-}
-
-#[derive(serde::Serialize, serde::Deserialize, specta::Type, tauri_specta::Event, Debug, Clone)]
-pub struct EditorRecordingFlowChanged {
-    pub target: Option,
-}
-
-/// The recording mode the user had selected before "Record a new clip" forced
-/// Studio, so the preference survives the flow no matter which path ends it.
-#[derive(Default)]
-pub struct EditorRecordingFlowState {
-    previous_mode: Mutex>,
-}
-
-fn project_name(project_path: &Path) -> String {
-    RecordingMeta::load_for_project(project_path)
-        .map(|meta| meta.pretty_name)
-        .ok()
-        .filter(|name| !name.trim().is_empty())
-        .or_else(|| {
-            project_path
-                .file_stem()
-                .map(|stem| stem.to_string_lossy().into_owned())
-        })
-        .unwrap_or_else(|| "this project".into())
-}
-
-pub fn current(app: &AppHandle) -> Option {
-    let project_path = EditorRecordingTarget::current(app)?;
-    Some(EditorRecordingFlowInfo {
-        project_name: project_name(&project_path),
-        project_path,
-    })
-}
-
-fn emit_changed(app: &AppHandle) {
-    let _ = EditorRecordingFlowChanged {
-        target: current(app),
-    }
-    .emit(app);
-}
-
-fn begin(app: &AppHandle, project_path: PathBuf) -> Result<(), String> {
-    let current_mode = RecordingSettingsStore::get(app)?
-        .and_then(|settings| settings.mode)
-        .unwrap_or_default();
-    if current_mode != RecordingMode::Studio {
-        RecordingSettingsStore::set_mode(app, RecordingMode::Studio)?;
-        tray::update_tray_icon_for_mode(app, RecordingMode::Studio);
-    }
-    if let Some(state) = app.try_state::() {
-        *state.previous_mode.lock().unwrap() = Some(current_mode);
-    }
-    EditorRecordingTarget::set(app, Some(project_path));
-    emit_changed(app);
-    Ok(())
-}
-
-/// Runs after every path that takes the editor recording target -- clean stop,
-/// failed or cancelled recording, failed restart, and an explicit cancel -- so
-/// the forced Studio mode is put back and every window learns the flow ended.
-pub fn finish(app: &AppHandle) {
-    let previous_mode = app
-        .try_state::()
-        .and_then(|state| state.previous_mode.lock().unwrap().take());
-    if let Some(previous_mode) = previous_mode
-        && previous_mode != RecordingMode::Studio
-    {
-        let still_studio = RecordingSettingsStore::get(app)
-            .ok()
-            .flatten()
-            .and_then(|settings| settings.mode)
-            .is_none_or(|mode| mode == RecordingMode::Studio);
-        if still_studio {
-            if let Err(error) = RecordingSettingsStore::set_mode(app, previous_mode) {
-                tracing::warn!(%error, "failed to restore the recording mode after the clip flow");
-            } else {
-                tray::update_tray_icon_for_mode(app, previous_mode);
-            }
-        }
-    }
-    emit_changed(app);
-}
-
-/// Takes the target without touching any window. Callers must already know
-/// no recording is live or pending, since a live recording owns the target.
-pub fn abort(app: &AppHandle) -> Option {
-    let project_path = EditorRecordingTarget::take(app)?;
-    finish(app);
-    tracing::info!(path = %project_path.display(), "editor recording flow aborted");
-    Some(project_path)
-}
-
-pub fn reveal_editor(app: &AppHandle, project_path: &Path) -> bool {
-    let Some(editor_window) = editor_window_for_path(app, project_path) else {
-        return false;
-    };
-    let _ = editor_window.unminimize();
-    let _ = editor_window.show();
-    let _ = editor_window.set_focus();
-    true
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn open_editor_recording_main(
-    app: AppHandle,
-    state: tauri::State<'_, ArcLock>,
-    project_path: PathBuf,
-) -> Result<(), String> {
-    if state.read().await.is_recording_active_or_pending() {
-        return Err("A recording is already in progress".into());
-    }
-    let editor_window = editor_window_for_path(&app, &project_path)
-        .ok_or_else(|| "The editor window is no longer open".to_string())?;
-
-    if let Some(previous) = abort(&app)
-        && previous != project_path
-    {
-        reveal_editor(&app, &previous);
-    }
-    begin(&app, project_path.clone())?;
-
-    if let Err(error) = (ShowCapWindow::Main {
-        init_target_mode: None,
-    })
-    .show(&app)
-    .await
-    {
-        abort(&app);
-        return Err(format!("Could not open the recorder: {error}"));
-    }
-
-    let _ = editor_window.hide();
-    tracing::info!(path = %project_path.display(), "editor recording flow started");
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn cancel_editor_recording_flow(
-    app: AppHandle,
-    state: tauri::State<'_, ArcLock>,
-) -> Result<(), String> {
-    if state.read().await.is_recording_active_or_pending() {
-        return Err("Stop the recording before leaving the recorder".into());
-    }
-    let Some(project_path) = EditorRecordingTarget::current(&app) else {
-        return Ok(());
-    };
-    if editor_window_for_path(&app, &project_path).is_none() {
-        abort(&app);
-        return Ok(());
-    }
-    crate::dismiss_main_window(&app);
-    Ok(())
-}
-
-/// The editor that armed the flow went away (deleted from the recordings list,
-/// say) while nothing was recording: drop the flow so the main window returns
-/// to its normal state instead of advertising a clip nobody can receive.
-pub fn abort_if_editor_gone(app: &AppHandle) {
-    let Some(project_path) = EditorRecordingTarget::current(app) else {
-        return;
-    };
-    if editor_window_for_path(app, &project_path).is_some() {
-        return;
-    }
-    let idle = app
-        .try_state::>()
-        .and_then(|state| {
-            state
-                .try_read()
-                .ok()
-                .map(|state| !state.is_recording_active_or_pending())
-        })
-        .unwrap_or(false);
-    if idle {
-        abort(app);
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn get_editor_recording_target(
-    app: AppHandle,
-) -> Result, String> {
-    Ok(current(&app))
-}
diff --git a/apps/desktop/src-tauri/src/editor_window.rs b/apps/desktop/src-tauri/src/editor_window.rs
deleted file mode 100644
index dc6b2a111ab..00000000000
--- a/apps/desktop/src-tauri/src/editor_window.rs
+++ /dev/null
@@ -1,776 +0,0 @@
-use std::{
-    collections::HashMap,
-    ops::Deref,
-    path::PathBuf,
-    str::FromStr,
-    sync::{
-        Arc,
-        atomic::{AtomicU8, Ordering},
-    },
-    time::Instant,
-};
-use tauri::{AppHandle, Emitter, Listener, Manager, Runtime, Window, ipc::CommandArg};
-use tokio::sync::{RwLock, watch};
-use tokio_util::sync::CancellationToken;
-
-use cap_rendering::GpuOutputFormat;
-use tauri_specta::Event;
-
-use crate::{
-    FrameLayoutEvent, create_editor_instance_impl,
-    frame_ws::{WSFrame, WSFrameFormat, create_watch_frame_ws},
-    windows::{CapWindowId, EditorWindowIds},
-};
-
-/// Forwards rendered frames to the preview websocket and mirrors each frame's
-/// display/camera placement to the webview so overlay hit-boxes always match
-/// what was actually rendered.
-fn make_frame_callback(
-    app: AppHandle,
-    frame_tx: watch::Sender>>,
-) -> cap_editor::EditorFrameCallback {
-    Box::new(move |output, layout| {
-        let Some(ws_frame) = frame_for_websocket(output) else {
-            return;
-        };
-        let _ = frame_tx.send(Some(std::sync::Arc::new(ws_frame)));
-
-        // Emitted unconditionally: a prewarmed instance renders before the
-        // webview attaches its listener, so deduping here would leave a
-        // fresh window without layout data until the next config change.
-        let _ = FrameLayoutEvent::from(layout).emit(&app);
-    })
-}
-
-pub(crate) fn frame_for_websocket(output: cap_editor::EditorFrameOutput) -> Option {
-    let frame = match output {
-        cap_editor::EditorFrameOutput::Nv12(frame) => {
-            let ws_format = match frame.format {
-                GpuOutputFormat::Nv12 => WSFrameFormat::Nv12 { full_range: false },
-                GpuOutputFormat::Rgba => WSFrameFormat::Rgba,
-            };
-            WSFrame {
-                data: Arc::new(frame.data.into_vec()).into(),
-                width: frame.width,
-                height: frame.height,
-                stride: frame.y_stride,
-                frame_number: frame.frame_number,
-                target_time_ns: frame.target_time_ns,
-                format: ws_format,
-                created_at: Instant::now(),
-            }
-        }
-        cap_editor::EditorFrameOutput::Rgba(frame) => WSFrame {
-            data: frame.data.into(),
-            width: frame.width,
-            height: frame.height,
-            stride: frame.padded_bytes_per_row,
-            frame_number: frame.frame_number,
-            target_time_ns: frame.target_time_ns,
-            format: WSFrameFormat::Rgba,
-            created_at: Instant::now(),
-        },
-        // The Tauri editor transports frames over a websocket, so it never
-        // requests the gpui-only zero-copy surface format.
-        #[cfg(target_os = "macos")]
-        cap_editor::EditorFrameOutput::Surface(_) => return None,
-    };
-    Some(frame.into_packed())
-}
-
-pub struct EditorInstance {
-    inner: Arc,
-    pub instance_id: uuid::Uuid,
-    handoff_playback: tokio::sync::Mutex>,
-    disposed: std::sync::atomic::AtomicBool,
-    pub ws_port: u16,
-    pub ws_shutdown_token: CancellationToken,
-    app_handle: AppHandle,
-    render_frame_event_id: tauri::EventId,
-}
-
-type PendingResult = Result, String>;
-type PendingReceiver = tokio::sync::watch::Receiver>;
-
-pub(crate) struct EditorInstanceDelivery {
-    instance: Arc,
-    cleanup_runtime: tokio::runtime::Handle,
-    state: AtomicU8,
-}
-
-impl EditorInstanceDelivery {
-    const PENDING: u8 = 0;
-    const ADOPTED: u8 = 1;
-    const RETIRED: u8 = 2;
-
-    fn new(instance: Arc, cleanup_runtime: tokio::runtime::Handle) -> Arc {
-        Arc::new(Self {
-            instance,
-            cleanup_runtime,
-            state: AtomicU8::new(Self::PENDING),
-        })
-    }
-
-    fn adopt_into(
-        &self,
-        instances: &mut HashMap>,
-        window_label: &str,
-    ) -> Result, String> {
-        self.state
-            .compare_exchange(
-                Self::PENDING,
-                Self::ADOPTED,
-                Ordering::AcqRel,
-                Ordering::Acquire,
-            )
-            .map_err(|_| "Editor instance delivery is no longer pending".to_string())?;
-        let instance = self.instance.clone();
-        let _ = instances.insert(window_label.to_string(), instance.clone());
-        Ok(instance)
-    }
-
-    fn retire(&self) -> Option> {
-        self.state
-            .compare_exchange(
-                Self::PENDING,
-                Self::RETIRED,
-                Ordering::AcqRel,
-                Ordering::Acquire,
-            )
-            .ok()?;
-        let instance = self.instance.clone();
-        Some(self.cleanup_runtime.spawn(async move {
-            instance.dispose().await;
-        }))
-    }
-
-    async fn dispose(&self) {
-        if let Some(cleanup) = self.retire() {
-            let _ = cleanup.await;
-        }
-    }
-}
-
-impl Drop for EditorInstanceDelivery {
-    fn drop(&mut self) {
-        drop(self.retire());
-    }
-}
-
-#[derive(Clone, Default)]
-pub struct PendingEditorInstances(Arc>>);
-
-async fn do_prewarm(app: AppHandle, path: PathBuf) -> Result, String> {
-    let (frame_tx, frame_rx) = watch::channel(None);
-
-    let (ws_port, ws_shutdown_token) = create_watch_frame_ws(frame_rx, Default::default()).await;
-    let ws_guard = ws_shutdown_token.clone().drop_guard();
-    let (inner, render_frame_event_id) =
-        create_editor_instance_impl(&app, path, make_frame_callback(app.clone(), frame_tx)).await?;
-
-    let instance = Arc::new(EditorInstance {
-        inner,
-        instance_id: uuid::Uuid::new_v4(),
-        handoff_playback: Default::default(),
-        disposed: Default::default(),
-        ws_port,
-        ws_shutdown_token,
-        app_handle: app,
-        render_frame_event_id,
-    });
-    ws_guard.disarm();
-    Ok(instance)
-}
-
-async fn recreate_preparing_instance(
-    app: AppHandle,
-    previous: &Arc,
-) -> Result, String> {
-    let (frame_tx, frame_rx) = watch::channel(None);
-    let (ws_port, ws_shutdown_token) = create_watch_frame_ws(frame_rx, Default::default()).await;
-    let ws_guard = ws_shutdown_token.clone().drop_guard();
-    let state_app = app.clone();
-    let inner = previous
-        .inner
-        .recreate_preparing_candidate(
-            move |state| {
-                let _ = crate::EditorStateChanged::new(state).emit(&state_app);
-            },
-            make_frame_callback(app.clone(), frame_tx),
-            cap_editor::EditorFrameFormat::Rgba,
-        )
-        .await?;
-    let render_frame_event_id = crate::RenderFrameEvent::listen_checked(&app, {
-        let preview_tx = inner.preview_tx.clone();
-        move |event| {
-            preview_tx.send_modify(|request| {
-                *request = Some((event.frame_number, event.fps, event.resolution_base))
-            });
-        }
-    });
-    let instance = Arc::new(EditorInstance {
-        inner,
-        instance_id: uuid::Uuid::new_v4(),
-        handoff_playback: Default::default(),
-        disposed: Default::default(),
-        ws_port,
-        ws_shutdown_token,
-        app_handle: app,
-        render_frame_event_id,
-    });
-    let fps = crate::EDITOR_PREVIEW_FPS;
-    let resolution = crate::default_editor_preview_resolution();
-    let started = match instance
-        .inner
-        .start_preparing_handoff(fps, resolution)
-        .await
-    {
-        Ok(started) => started,
-        Err(error) => {
-            instance.dispose().await;
-            return Err(format!("Preparing handoff start failed: {error:?}"));
-        }
-    };
-    if !started {
-        let frame = instance
-            .inner
-            .preparing_adoption()
-            .and_then(|adoption| adoption.frame_number(fps))
-            .unwrap_or(0);
-        instance
-            .inner
-            .preview_tx
-            .send_modify(|request| *request = Some((frame, fps, resolution)));
-    }
-    ws_guard.disarm();
-    Ok(instance)
-}
-
-fn with_registered_editor(
-    window_ids: &EditorWindowIds,
-    id: u32,
-    action: impl FnOnce() -> T,
-) -> Result {
-    let ids = window_ids.ids.lock().map_err(|error| error.to_string())?;
-    if !ids.iter().any(|(_, registered_id)| *registered_id == id) {
-        return Err("Editor window is no longer registered".to_string());
-    }
-    Ok(action())
-}
-
-impl PendingEditorInstances {
-    pub fn get(app: &AppHandle) -> Self {
-        match app.try_state::() {
-            Some(s) => (*s).clone(),
-            None => {
-                let pending = Self::default();
-                app.manage(pending);
-                (*app.state::()).clone()
-            }
-        }
-    }
-
-    pub async fn start_prewarm(app: &AppHandle, window_label: String, path: PathBuf) {
-        let Ok(CapWindowId::Editor { id }) = CapWindowId::from_str(&window_label) else {
-            return;
-        };
-        let window_ids = EditorWindowIds::get(app);
-        let pending = Self::get(app);
-        let app = app.clone();
-        let tx = {
-            let mut instances = pending.0.write().await;
-            let admitted = with_registered_editor(&window_ids, id, || {
-                use std::collections::hash_map::Entry;
-                match instances.entry(window_label) {
-                    Entry::Vacant(entry) => {
-                        let (tx, rx) = watch::channel(None);
-                        entry.insert(rx);
-                        Some(tx)
-                    }
-                    Entry::Occupied(_) => None,
-                }
-            });
-            match admitted {
-                Ok(Some(tx)) => tx,
-                Ok(None) => return,
-                Err(error) => {
-                    tracing::debug!(%error, "Skipping prewarm for a retired editor");
-                    return;
-                }
-            }
-        };
-
-        let cleanup_runtime = tokio::runtime::Handle::current();
-        tokio::spawn(async move {
-            let result = do_prewarm(app, path)
-                .await
-                .map(|instance| EditorInstanceDelivery::new(instance, cleanup_runtime));
-            tx.send(Some(result)).ok();
-        });
-    }
-
-    pub async fn take_prewarmed(&self, window_label: &str) -> Option {
-        let mut instances = self.0.write().await;
-        instances.remove(window_label)
-    }
-
-    pub async fn cancel_prewarm(&self, window_label: &str) {
-        let mut instances = self.0.write().await;
-        if let Some(mut rx) = instances.remove(window_label) {
-            tokio::spawn(async move {
-                let timeout = tokio::time::timeout(std::time::Duration::from_secs(10), async {
-                    loop {
-                        let instance_to_dispose = {
-                            let borrowed = rx.borrow_and_update().clone();
-                            match borrowed {
-                                Some(Ok(instance)) => Some(instance),
-                                Some(Err(_)) => break,
-                                None => None,
-                            }
-                        };
-
-                        if let Some(instance) = instance_to_dispose {
-                            instance.dispose().await;
-                            break;
-                        }
-
-                        if rx.changed().await.is_err() {
-                            break;
-                        }
-                    }
-                });
-                if timeout.await.is_err() {
-                    tracing::warn!(
-                        "Timed out waiting for prewarmed editor instance to complete for cleanup"
-                    );
-                }
-            });
-        }
-    }
-
-    pub async fn dispose_all(app: &AppHandle) {
-        let Some(pending) = app.try_state::() else {
-            return;
-        };
-
-        let pending = {
-            let mut instances = pending.0.write().await;
-            std::mem::take(&mut *instances)
-        };
-
-        let count = pending.len();
-        for (_, mut rx) in pending {
-            let result = tokio::time::timeout(std::time::Duration::from_millis(500), async {
-                loop {
-                    let instance_to_dispose = {
-                        let borrowed = rx.borrow_and_update().clone();
-                        match borrowed {
-                            Some(Ok(instance)) => Some(instance),
-                            Some(Err(_)) => break,
-                            None => None,
-                        }
-                    };
-
-                    if let Some(instance) = instance_to_dispose {
-                        instance.dispose().await;
-                        break;
-                    }
-
-                    if rx.changed().await.is_err() {
-                        break;
-                    }
-                }
-            })
-            .await;
-
-            if result.is_err() {
-                tracing::warn!("Timed out disposing pending editor instance during app exit");
-            }
-        }
-
-        if count > 0 {
-            tracing::info!(count, "Disposed pending editor instances during app exit");
-        }
-    }
-}
-
-impl EditorInstance {
-    pub async fn dispose(&self) {
-        self.dispose_inner(false).await;
-    }
-
-    async fn dispose_inner(&self, refresh_thumbnail: bool) {
-        self.disposed.store(true, Ordering::Release);
-        let mut handoff = self.handoff_playback.lock().await;
-        if let Some((_, playback)) = handoff.take() {
-            playback.stop();
-        }
-        if refresh_thumbnail {
-            if self.inner.dispose_with_thumbnail().await {
-                let _ = self
-                    .app_handle
-                    .emit("recording-thumbnail-changed", &self.project_path);
-            }
-        } else {
-            self.inner.dispose().await;
-        }
-
-        self.ws_shutdown_token.cancel();
-        self.app_handle.unlisten(self.render_frame_event_id);
-    }
-
-    fn validate_handoff(&self, expected: &str) -> Result<(), String> {
-        if expected != self.instance_id.to_string() || self.disposed.load(Ordering::Acquire) {
-            Err("The handoff editor instance has ended".into())
-        } else {
-            Ok(())
-        }
-    }
-
-    pub(crate) fn commit_preparing_frame(
-        &self,
-        expected: &str,
-        frame: u32,
-        fps: u32,
-    ) -> Result {
-        self.validate_handoff(expected)?;
-        if self
-            .inner
-            .preparing_adoption()
-            .is_some_and(|adoption| adoption.is_owner())
-        {
-            return Ok(true);
-        }
-        if self
-            .inner
-            .preparing_adoption()
-            .is_some_and(|adoption| adoption.invalidated())
-        {
-            return Err("Preparing handoff candidate was superseded".into());
-        }
-        Ok(self
-            .inner
-            .preparing_adoption()
-            .is_none_or(|adoption| adoption.try_commit(frame, fps)))
-    }
-
-    pub(crate) async fn start_handoff_playback(
-        &self,
-        expected: &str,
-        frame_number: u32,
-        fps: u32,
-        resolution: cap_project::XY,
-    ) -> Result {
-        let mut handoff = self.handoff_playback.lock().await;
-        self.validate_handoff(expected)?;
-        if self
-            .inner
-            .preparing_adoption()
-            .is_some_and(|adoption| adoption.is_owner())
-            && let Some(playback) = self.inner.state.lock().await.playback_task.clone()
-        {
-            let playback_id = uuid::Uuid::new_v4();
-            *handoff = Some((playback_id, playback));
-            return Ok(playback_id.to_string());
-        }
-        self.inner
-            .modify_and_emit_state(|state| state.playhead_position = frame_number)
-            .await;
-        let playback = self
-            .inner
-            .start_playback_with_handle(fps, resolution, Some(frame_number))
-            .await
-            .map_err(|error| format!("The handoff playback could not start: {error:?}"))?;
-        if let Err(error) = self.validate_handoff(expected) {
-            playback.stop();
-            return Err(error);
-        }
-        let playback_id = uuid::Uuid::new_v4();
-        *handoff = Some((playback_id, playback));
-        Ok(playback_id.to_string())
-    }
-
-    pub(crate) async fn stop_handoff_playback(
-        &self,
-        expected: &str,
-        playback_id: &str,
-    ) -> Result<(), String> {
-        let mut handoff = self.handoff_playback.lock().await;
-        self.validate_handoff(expected)?;
-        if handoff
-            .as_ref()
-            .is_some_and(|(id, _)| id.to_string() == playback_id)
-            && let Some((_, playback)) = handoff.take()
-        {
-            playback.stop();
-        }
-        Ok(())
-    }
-}
-
-impl Drop for EditorInstance {
-    fn drop(&mut self) {
-        self.ws_shutdown_token.cancel();
-        self.app_handle.unlisten(self.render_frame_event_id);
-    }
-}
-
-impl Deref for EditorInstance {
-    type Target = Arc;
-
-    fn deref(&self) -> &Self::Target {
-        &self.inner
-    }
-}
-
-#[derive(Clone)]
-pub struct EditorInstances(Arc>>>);
-
-pub struct WindowEditorInstance(pub Arc);
-
-impl specta::function::FunctionArg for WindowEditorInstance {
-    fn to_datatype(_: &mut specta::TypeMap) -> Option {
-        None
-    }
-}
-
-impl Deref for WindowEditorInstance {
-    type Target = Arc;
-
-    fn deref(&self) -> &Self::Target {
-        &self.0
-    }
-}
-
-impl AsRef for WindowEditorInstance {
-    fn as_ref(&self) -> &EditorInstance {
-        &self.0
-    }
-}
-
-impl<'de, R: Runtime> CommandArg<'de, R> for WindowEditorInstance {
-    fn from_command(
-        command: tauri::ipc::CommandItem<'de, R>,
-    ) -> Result {
-        let window = Window::from_command(command)?;
-
-        let Some(instances) = window.try_state::() else {
-            return Err("editor instance registry unavailable".into());
-        };
-
-        // Avoid `futures::executor::block_on` on a tokio RwLock here. That can deadlock or
-        // panic when the IPC handler runs from inside the tokio runtime (release builds hit
-        // this path much more aggressively than dev builds and silently terminate the process).
-        // `try_read` is sync and never blocks; if the lock is contended we surface a transient
-        // error and let the frontend retry.
-        let Ok(instance_guard) = instances.0.try_read() else {
-            return Err("editor instance registry busy".into());
-        };
-
-        let Some(instance) = instance_guard.get(window.label()).cloned() else {
-            return Err("editor instance unavailable".into());
-        };
-
-        Ok(Self(instance))
-    }
-}
-
-pub struct OptionalWindowEditorInstance(pub Option>);
-
-impl specta::function::FunctionArg for OptionalWindowEditorInstance {
-    fn to_datatype(_: &mut specta::TypeMap) -> Option {
-        None
-    }
-}
-
-impl Deref for OptionalWindowEditorInstance {
-    type Target = Option>;
-
-    fn deref(&self) -> &Self::Target {
-        &self.0
-    }
-}
-
-impl<'de, R: Runtime> CommandArg<'de, R> for OptionalWindowEditorInstance {
-    fn from_command(
-        command: tauri::ipc::CommandItem<'de, R>,
-    ) -> Result {
-        let Ok(window) = Window::from_command(command) else {
-            return Ok(Self(None));
-        };
-
-        let Some(instances) = window.try_state::() else {
-            return Ok(Self(None));
-        };
-
-        match instances.0.try_read() {
-            Ok(instance_guard) => Ok(Self(instance_guard.get(window.label()).cloned())),
-            Err(_) => Ok(Self(None)),
-        }
-    }
-}
-
-impl EditorInstances {
-    pub async fn get_or_create(
-        window: &Window,
-        path: PathBuf,
-    ) -> Result, String> {
-        let CapWindowId::Editor { id } =
-            CapWindowId::from_str(window.label()).map_err(|error| error.to_string())?
-        else {
-            return Err("Invalid editor window".to_string());
-        };
-        let window_ids = EditorWindowIds::get(window.app_handle());
-        with_registered_editor(&window_ids, id, || ())?;
-        let instances = match window.try_state::() {
-            Some(s) => (*s).clone(),
-            None => {
-                window.manage(Self(Arc::new(RwLock::new(HashMap::new()))));
-                (*window.state::()).clone()
-            }
-        };
-        let mut instances = instances.0.write().await;
-        if let Some(instance) =
-            with_registered_editor(&window_ids, id, || instances.get(window.label()).cloned())?
-        {
-            if !instance
-                .inner
-                .preparing_adoption()
-                .is_some_and(|adoption| adoption.invalidated())
-            {
-                return Ok(instance);
-            }
-            let replacement =
-                recreate_preparing_instance(window.app_handle().clone(), &instance).await?;
-            if let Err(error) = with_registered_editor(&window_ids, id, || ()) {
-                replacement.dispose().await;
-                return Err(error);
-            }
-            let _ = instances.insert(window.label().to_string(), replacement.clone());
-            instance.dispose().await;
-            return Ok(replacement);
-        }
-
-        let requested_at = Instant::now();
-        let pending = PendingEditorInstances::get(window.app_handle());
-        let mut prewarmed = None;
-        if let Some(mut prewarmed_rx) = pending.take_prewarmed(window.label()).await {
-            loop {
-                let result = prewarmed_rx.borrow_and_update().clone();
-                if let Some(result) = result {
-                    prewarmed = Some(result?);
-                    break;
-                }
-                if prewarmed_rx.changed().await.is_err() {
-                    break;
-                }
-            }
-            if prewarmed.is_none() {
-                tracing::warn!(
-                    "Editor open: prewarm channel closed without a result, building on demand"
-                );
-            }
-        }
-        let was_prewarmed = prewarmed.is_some();
-        let instance = match prewarmed {
-            Some(instance) => instance,
-            None => {
-                with_registered_editor(&window_ids, id, || ())?;
-                let cleanup_runtime = tokio::runtime::Handle::current();
-                let (frame_tx, frame_rx) = watch::channel(None);
-                let (ws_port, ws_shutdown_token) =
-                    create_watch_frame_ws(frame_rx, Default::default()).await;
-                let ws_guard = ws_shutdown_token.clone().drop_guard();
-                let app_handle = window.app_handle().clone();
-                let (inner, render_frame_event_id) = create_editor_instance_impl(
-                    window.app_handle(),
-                    path.clone(),
-                    make_frame_callback(app_handle.clone(), frame_tx),
-                )
-                .await?;
-                let instance = Arc::new(EditorInstance {
-                    inner,
-                    instance_id: uuid::Uuid::new_v4(),
-                    handoff_playback: Default::default(),
-                    disposed: Default::default(),
-                    ws_port,
-                    ws_shutdown_token,
-                    app_handle,
-                    render_frame_event_id,
-                });
-                ws_guard.disarm();
-                EditorInstanceDelivery::new(instance, cleanup_runtime)
-            }
-        };
-
-        let published = with_registered_editor(&window_ids, id, || {
-            instance.adopt_into(&mut instances, window.label())
-        });
-        drop(instances);
-        let instance = match published {
-            Ok(Ok(instance)) => instance,
-            Ok(Err(error)) | Err(error) => {
-                instance.dispose().await;
-                return Err(error);
-            }
-        };
-        if was_prewarmed {
-            tracing::info!(
-                wait_ms = requested_at.elapsed().as_millis() as u64,
-                "Editor open: instance served from prewarm"
-            );
-        } else {
-            tracing::info!(
-                build_ms = requested_at.elapsed().as_millis() as u64,
-                "Editor open: instance built on demand (no prewarm hit)"
-            );
-        }
-        Ok(instance)
-    }
-
-    /// Project paths of every currently open editor. Used to avoid touching
-    /// projects that are in use (e.g. when migrating recordings between
-    /// storage folders).
-    pub async fn open_project_paths(app: &AppHandle) -> Vec {
-        let Some(instances) = app.try_state::() else {
-            return Vec::new();
-        };
-
-        let instances = instances.0.read().await;
-        instances
-            .values()
-            .map(|instance| instance.project_path.clone())
-            .collect()
-    }
-
-    pub async fn remove(window: Window) {
-        let Some(instances) = window.try_state::() else {
-            return;
-        };
-
-        let instance = instances.0.write().await.remove(window.label());
-        if let Some(instance) = instance {
-            instance.dispose_inner(true).await;
-        }
-    }
-
-    pub async fn dispose_all(app: &AppHandle) {
-        let Some(instances) = app.try_state::() else {
-            return;
-        };
-
-        let instances = {
-            let mut instances = instances.0.write().await;
-            std::mem::take(&mut *instances)
-        };
-
-        let count = instances.len();
-        for (_, instance) in instances {
-            instance.dispose().await;
-        }
-
-        if count > 0 {
-            tracing::info!(count, "Disposed editor instances during app exit");
-        }
-    }
-}
diff --git a/apps/desktop/src-tauri/src/exit_shutdown.rs b/apps/desktop/src-tauri/src/exit_shutdown.rs
deleted file mode 100644
index 9c9e8b13804..00000000000
--- a/apps/desktop/src-tauri/src/exit_shutdown.rs
+++ /dev/null
@@ -1,278 +0,0 @@
-use std::sync::atomic::{AtomicU8, Ordering};
-use tokio::task::JoinHandle;
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub(crate) enum ExitBlocked {
-    StateUnavailable,
-    RecordingActive,
-    FinalizationActive,
-    ExportActive,
-    UploadActive,
-    UpdateInstalling,
-    AlreadyExiting,
-}
-
-impl ExitBlocked {
-    pub(crate) fn message(self) -> &'static str {
-        match self {
-            Self::StateUnavailable => {
-                "Cap could not confirm that recording has finished. Wait for any recording to finish, then try again."
-            }
-            Self::RecordingActive => {
-                "Finish or cancel your recording before quitting or restarting Cap. If you already pressed Stop, wait for it to finish."
-            }
-            Self::FinalizationActive => {
-                "Cap is still saving your recording. Wait for it to finish before quitting or restarting."
-            }
-            Self::ExportActive => {
-                "Wait for your export to finish before quitting or restarting Cap."
-            }
-            Self::UploadActive => {
-                "Cap is still uploading your recording. Wait for it to finish before quitting or restarting."
-            }
-            Self::UpdateInstalling => "Cap is installing an update. Wait for it to finish.",
-            Self::AlreadyExiting => "Cap is already shutting down.",
-        }
-    }
-}
-
-pub(crate) fn with_idle_recording_state(
-    state: &tokio::sync::RwLock,
-    verify_idle: impl FnOnce(&T) -> Result<(), ExitBlocked>,
-    begin: impl FnOnce() -> R,
-) -> Result {
-    let state = state
-        .try_read()
-        .map_err(|_| ExitBlocked::StateUnavailable)?;
-    verify_idle(&state)?;
-    Ok(begin())
-}
-
-pub(crate) fn recording_start_allowed(
-    is_exiting: bool,
-    update_blocks_recording: bool,
-) -> Result<(), &'static str> {
-    if is_exiting {
-        Err("Cap is shutting down. Recording has not started.")
-    } else if update_blocks_recording {
-        Err("Cap is installing an update. Finish updating or restart Cap before recording.")
-    } else {
-        Ok(())
-    }
-}
-
-pub(crate) fn prepare_then_begin_exit(
-    prepare: impl FnOnce() -> Result<(), String>,
-    begin: impl FnOnce() -> bool,
-) -> Result<(), String> {
-    prepare()?;
-    if begin() {
-        Ok(())
-    } else {
-        Err(ExitBlocked::AlreadyExiting.message().into())
-    }
-}
-
-#[derive(Default)]
-pub(crate) struct UpdateInstallState(AtomicU8);
-
-impl UpdateInstallState {
-    pub(crate) fn is_installing(&self) -> bool {
-        self.0.load(Ordering::Acquire) == 1
-    }
-
-    pub(crate) fn blocks_recording(&self) -> bool {
-        self.0.load(Ordering::Acquire) != 0
-    }
-
-    pub(crate) fn begin(&self) -> Option> {
-        self.0
-            .compare_exchange(0, 1, Ordering::AcqRel, Ordering::Acquire)
-            .ok()
-            .map(|_| UpdateInstallGuard {
-                state: self,
-                completed: false,
-            })
-    }
-}
-
-pub(crate) struct UpdateInstallGuard<'a> {
-    state: &'a UpdateInstallState,
-    completed: bool,
-}
-
-impl UpdateInstallGuard<'_> {
-    pub(crate) fn complete(mut self, can_exit_later: bool) {
-        self.state
-            .0
-            .store(if can_exit_later { 2 } else { 0 }, Ordering::Release);
-        self.completed = true;
-    }
-}
-
-impl Drop for UpdateInstallGuard<'_> {
-    fn drop(&mut self) {
-        if !self.completed {
-            let _ = self
-                .state
-                .0
-                .compare_exchange(1, 0, Ordering::AcqRel, Ordering::Acquire);
-        }
-    }
-}
-
-pub(crate) fn run_while_active(is_exiting: FExit, operation: F) -> Option
-where
-    FExit: Fn() -> bool,
-    F: FnOnce() -> T,
-{
-    if is_exiting() {
-        None
-    } else {
-        Some(operation())
-    }
-}
-
-pub(crate) fn collect_device_inventory(
-    is_exiting: FExit,
-    camera_permitted: bool,
-    microphone_permitted: bool,
-    list_cameras: FCamera,
-    list_microphones: FMicrophone,
-) -> Option<(Vec, Vec)>
-where
-    FExit: Fn() -> bool,
-    FCamera: FnOnce() -> Vec,
-    FMicrophone: FnOnce() -> Vec,
-{
-    if is_exiting() {
-        return None;
-    }
-
-    let cameras = if camera_permitted {
-        if is_exiting() {
-            return None;
-        }
-
-        list_cameras()
-    } else {
-        Vec::new()
-    };
-
-    if is_exiting() {
-        return None;
-    }
-
-    let microphones = if microphone_permitted {
-        if is_exiting() {
-            return None;
-        }
-
-        list_microphones()
-    } else {
-        Vec::new()
-    };
-
-    if is_exiting() {
-        return None;
-    }
-
-    Some((cameras, microphones))
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub(crate) enum AppExitAction {
-    #[cfg(target_os = "macos")]
-    Process(i32),
-    #[cfg(not(target_os = "macos"))]
-    Runtime(i32),
-}
-
-pub(crate) fn app_exit_action(exit_code: i32) -> AppExitAction {
-    #[cfg(target_os = "macos")]
-    {
-        AppExitAction::Process(exit_code)
-    }
-
-    #[cfg(not(target_os = "macos"))]
-    {
-        AppExitAction::Runtime(exit_code)
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub(crate) enum ExitRequestDecision {
-    StartCleanup,
-    AlreadyExiting,
-    ExportActive,
-    AllowRuntimeExit,
-    AllowRuntimeRestart,
-}
-
-pub(crate) fn handle_exit_requested(
-    is_exiting: bool,
-    export_active: bool,
-    runtime_exit_requested: bool,
-    runtime_restart_requested: bool,
-    prevent_exit: FPrevent,
-) -> ExitRequestDecision
-where
-    FPrevent: FnOnce(),
-{
-    if runtime_restart_requested {
-        ExitRequestDecision::AllowRuntimeRestart
-    } else if is_exiting && runtime_exit_requested {
-        ExitRequestDecision::AllowRuntimeExit
-    } else if export_active {
-        prevent_exit();
-        ExitRequestDecision::ExportActive
-    } else if is_exiting {
-        prevent_exit();
-        ExitRequestDecision::AlreadyExiting
-    } else {
-        prevent_exit();
-        ExitRequestDecision::StartCleanup
-    }
-}
-
-pub(crate) fn read_target_under_cursor(
-    is_exiting: FExit,
-    display: FDisplay,
-    window: FWindow,
-) -> Option<(Option, Option)>
-where
-    FExit: Fn() -> bool,
-    FDisplay: FnOnce() -> Option,
-    FWindow: FnOnce() -> Option,
-{
-    if is_exiting() {
-        return None;
-    }
-
-    let display = display();
-
-    if is_exiting() {
-        return None;
-    }
-
-    let window = window();
-
-    if is_exiting() {
-        return None;
-    }
-
-    Some((display, window))
-}
-
-pub(crate) fn abort_join_handles(
-    tasks: impl IntoIterator>,
-    task: Option>,
-) {
-    for task in tasks {
-        task.abort();
-    }
-
-    if let Some(task) = task {
-        task.abort();
-    }
-}
diff --git a/apps/desktop/src-tauri/src/export.rs b/apps/desktop/src-tauri/src/export.rs
deleted file mode 100644
index 662fe679128..00000000000
--- a/apps/desktop/src-tauri/src/export.rs
+++ /dev/null
@@ -1,2747 +0,0 @@
-mod estimate_request;
-
-use crate::editor_window::{OptionalWindowEditorInstance, WindowEditorInstance};
-use crate::{FramesRendered, get_video_metadata};
-use cap_export::{ExporterBase, make_cursor_only_project};
-use cap_project::{RecordingMeta, TimelineFrameMapping, XY};
-use cap_rendering::{
-    FrameRenderer, ProjectRecordingsMeta, ProjectUniforms, RenderSegment, RenderVideoConstants,
-    RendererLayers, TransitionRenderInput, ZoomTransformTimeline,
-};
-use cap_utils::export_resources::{DiskBudget, ExportResources, estimated_working_bytes};
-use futures::FutureExt;
-use image::codecs::jpeg::JpegEncoder;
-use serde::{Deserialize, Serialize};
-use specta::Type;
-use std::any::Any;
-use std::future::Future;
-use std::panic::AssertUnwindSafe;
-use std::{
-    collections::HashMap,
-    path::{Path, PathBuf},
-    process::Stdio,
-    sync::{
-        Arc, LazyLock, Mutex, MutexGuard,
-        atomic::{AtomicBool, AtomicUsize, Ordering},
-    },
-};
-use tauri::Manager;
-use tauri_plugin_dialog::{DialogExt, MessageDialogButtons, MessageDialogKind};
-use tokio::io::AsyncBufReadExt;
-use tokio_util::sync::CancellationToken;
-use tracing::{error, info, instrument, warn};
-
-fn panic_message(panic: Box) -> String {
-    if let Some(msg) = panic.downcast_ref::<&str>() {
-        msg.to_string()
-    } else if let Some(msg) = panic.downcast_ref::() {
-        msg.clone()
-    } else {
-        "unknown panic".to_string()
-    }
-}
-
-fn export_panic_error(panic: Box) -> String {
-    let panic_msg = panic_message(panic);
-    error!(
-        target: "cap_desktop_export",
-        panic = %panic_msg,
-        "export command panicked"
-    );
-    sentry::capture_message(
-        &format!("Export command panicked: {panic_msg}"),
-        sentry::Level::Error,
-    );
-    "Export failed unexpectedly".to_string()
-}
-
-#[cfg(all(windows, not(debug_assertions)))]
-async fn run_export_command(make_future: F) -> Result
-where
-    T: Send + 'static,
-    F: FnOnce() -> Fut + Send + 'static,
-    Fut: Future> + 'static,
-{
-    let (tx, rx) = tokio::sync::oneshot::channel();
-
-    // Windows release builds can stack-overflow in Tauri's IPC command entry before the save
-    // dialog or exporter sidecar starts. Keep the export future off that command-entry stack.
-    std::thread::Builder::new()
-        .name("cap-export-command".to_string())
-        .stack_size(EXPORT_COMMAND_THREAD_STACK_SIZE)
-        .spawn(move || {
-            let result = match tokio::runtime::Builder::new_current_thread()
-                .enable_all()
-                .build()
-            {
-                Ok(runtime) => runtime.block_on(async move {
-                    match AssertUnwindSafe(make_future()).catch_unwind().await {
-                        Ok(result) => result,
-                        Err(panic) => Err(export_panic_error(panic)),
-                    }
-                }),
-                Err(err) => Err(format!("Failed to build export command runtime: {err}")),
-            };
-
-            let _ = tx.send(result);
-        })
-        .map_err(|err| format!("Failed to spawn export command thread: {err}"))?;
-
-    rx.await
-        .map_err(|err| format!("Export command thread stopped: {err}"))?
-}
-
-#[cfg(not(all(windows, not(debug_assertions))))]
-async fn run_export_command(make_future: F) -> Result
-where
-    F: FnOnce() -> Fut,
-    Fut: Future>,
-{
-    match AssertUnwindSafe(make_future()).catch_unwind().await {
-        Ok(result) => result,
-        Err(panic) => Err(export_panic_error(panic)),
-    }
-}
-
-async fn run_protected_export(
-    project_path: &Path,
-    settings: &ExportSettings,
-    progress: ExportProgress,
-    force_ffmpeg: bool,
-    cancel_token: CancellationToken,
-) -> Result {
-    match AssertUnwindSafe(do_export(
-        project_path,
-        settings,
-        progress,
-        force_ffmpeg,
-        cancel_token,
-    ))
-    .catch_unwind()
-    .await
-    {
-        Ok(result) => result,
-        Err(panic) => {
-            let panic_msg = panic_message(panic);
-            error!(
-                target: "cap_desktop_export",
-                panic = %panic_msg,
-                "export task panicked"
-            );
-            sentry::capture_message(
-                &format!("Export task panicked: {panic_msg}"),
-                sentry::Level::Error,
-            );
-            Err("Export failed unexpectedly".to_string())
-        }
-    }
-}
-
-const EXPORTER_STDERR_TAIL_LIMIT: usize = 80;
-const EXPORT_PROGRESS_FORWARD_INTERVAL: std::time::Duration = std::time::Duration::from_millis(100);
-#[cfg(all(windows, not(debug_assertions)))]
-const EXPORT_COMMAND_THREAD_STACK_SIZE: usize = 16 * 1024 * 1024;
-static ACTIVE_EXPORT_SESSIONS: AtomicUsize = AtomicUsize::new(0);
-static ACTIVE_EXPORT_CANCELLATIONS: LazyLock>> =
-    LazyLock::new(|| Mutex::new(HashMap::new()));
-static ACTIVE_EXPORT_WINDOW_SESSIONS: LazyLock>> =
-    LazyLock::new(|| Mutex::new(HashMap::new()));
-static NEXT_EXPORT_COMMAND_ID: AtomicUsize = AtomicUsize::new(1);
-
-#[cfg(windows)]
-const CREATE_NO_WINDOW: u32 = 0x0800_0000;
-
-#[derive(Deserialize)]
-#[serde(tag = "type")]
-enum ExportSidecarMessage {
-    Progress {
-        rendered_count: u32,
-        total_frames: u32,
-    },
-    Completed {
-        path: PathBuf,
-    },
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-enum ExportWorkerMode {
-    HardwareOptimized,
-    SoftwareSafe,
-}
-
-impl ExportWorkerMode {
-    fn force_ffmpeg_decoder(self, requested: bool) -> bool {
-        requested || matches!(self, Self::SoftwareSafe)
-    }
-
-    fn is_software_safe(self) -> bool {
-        matches!(self, Self::SoftwareSafe)
-    }
-}
-
-#[derive(Clone)]
-struct ExportProgress(tauri::ipc::Channel);
-
-#[derive(Debug, PartialEq, Eq)]
-enum ExportSaveDestination {
-    Selected(PathBuf),
-    #[cfg(any(target_os = "macos", test))]
-    Default,
-}
-
-#[cfg(any(target_os = "macos", test))]
-fn resolve_macos_export_destination(
-    result: Result, String>,
-) -> Option {
-    match result {
-        Ok(path) => path.map(ExportSaveDestination::Selected),
-        Err(error) => {
-            warn!(
-                error,
-                "Save dialog unavailable; keeping the export in its project output folder"
-            );
-            Some(ExportSaveDestination::Default)
-        }
-    }
-}
-
-struct ExportSaveDialogRequest {
-    #[cfg(not(target_os = "linux"))]
-    app: tauri::AppHandle,
-    #[cfg(target_os = "linux")]
-    parent: tauri::Window,
-    #[cfg(target_os = "linux")]
-    cancel_token: CancellationToken,
-    file_name: String,
-    file_type: String,
-}
-
-impl ExportProgress {
-    fn send(&self, progress: FramesRendered) -> bool {
-        self.0.send(progress).is_ok()
-    }
-}
-
-struct ExportProgressForwarder {
-    progress: ExportProgress,
-    last_emit_at: Option,
-}
-
-impl ExportProgressForwarder {
-    fn new(progress: ExportProgress) -> Self {
-        Self {
-            progress,
-            last_emit_at: None,
-        }
-    }
-
-    fn send(&mut self, rendered_count: u32, total_frames: u32) -> bool {
-        let now = std::time::Instant::now();
-        let should_emit = rendered_count == 0
-            || rendered_count >= total_frames
-            || self
-                .last_emit_at
-                .is_none_or(|last| now.duration_since(last) >= EXPORT_PROGRESS_FORWARD_INTERVAL);
-
-        if !should_emit {
-            return true;
-        }
-
-        self.last_emit_at = Some(now);
-        self.progress.send(FramesRendered {
-            rendered_count,
-            total_frames,
-        })
-    }
-}
-
-struct ActiveExportCancellation {
-    token: CancellationToken,
-    window_label: Option,
-}
-
-struct ExportCancellationGuard {
-    export_id: String,
-    token: CancellationToken,
-}
-
-impl ExportCancellationGuard {
-    fn new(export_id: String, window_label: Option) -> Self {
-        let token = CancellationToken::new();
-        active_export_cancellations().insert(
-            export_id.clone(),
-            ActiveExportCancellation {
-                token: token.clone(),
-                window_label,
-            },
-        );
-
-        Self { export_id, token }
-    }
-
-    fn token(&self) -> CancellationToken {
-        self.token.clone()
-    }
-}
-
-impl Drop for ExportCancellationGuard {
-    fn drop(&mut self) {
-        active_export_cancellations().remove(&self.export_id);
-    }
-}
-
-fn active_export_cancellations() -> MutexGuard<'static, HashMap> {
-    match ACTIVE_EXPORT_CANCELLATIONS.lock() {
-        Ok(guard) => guard,
-        Err(err) => err.into_inner(),
-    }
-}
-
-fn active_export_window_sessions() -> MutexGuard<'static, HashMap> {
-    match ACTIVE_EXPORT_WINDOW_SESSIONS.lock() {
-        Ok(guard) => guard,
-        Err(err) => err.into_inner(),
-    }
-}
-
-fn next_export_command_id(prefix: &str) -> String {
-    let id = NEXT_EXPORT_COMMAND_ID.fetch_add(1, Ordering::AcqRel);
-    format!("{prefix}-{id}")
-}
-
-fn cancel_export_by_id(export_id: &str) -> bool {
-    let cancellations = active_export_cancellations();
-    if let Some(active_export) = cancellations.get(export_id) {
-        active_export.token.cancel();
-        return true;
-    }
-
-    false
-}
-
-pub fn cancel_exports_for_window(window_label: &str) {
-    let tokens = {
-        let cancellations = active_export_cancellations();
-        cancellations
-            .values()
-            .filter(|active_export| active_export.window_label.as_deref() == Some(window_label))
-            .map(|active_export| active_export.token.clone())
-            .collect::>()
-    };
-
-    for token in &tokens {
-        token.cancel();
-    }
-
-    let released_sessions = release_export_sessions_for_window(window_label);
-
-    if !tokens.is_empty() || released_sessions > 0 {
-        info!(
-            window = window_label,
-            cancelled_count = tokens.len(),
-            released_sessions,
-            "Cancelled window exports"
-        );
-    }
-}
-
-pub fn cancel_all_exports() {
-    let tokens = {
-        let cancellations = active_export_cancellations();
-        cancellations
-            .values()
-            .map(|active_export| active_export.token.clone())
-            .collect::>()
-    };
-
-    for token in &tokens {
-        token.cancel();
-    }
-
-    let released_sessions = release_all_window_export_sessions();
-
-    if !tokens.is_empty() || released_sessions > 0 {
-        info!(
-            cancelled_count = tokens.len(),
-            released_sessions, "Cancelled active exports"
-        );
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument]
-pub fn cancel_export(export_id: String) -> bool {
-    cancel_export_by_id(&export_id)
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(window))]
-pub fn cancel_current_window_exports(window: tauri::Window) {
-    cancel_exports_for_window(window.label());
-}
-
-fn retain_export_session() {
-    let active_exports = ACTIVE_EXPORT_SESSIONS.fetch_add(1, Ordering::AcqRel) + 1;
-    info!(active_exports, "Export session guard started");
-}
-
-fn release_export_session() {
-    let mut current = ACTIVE_EXPORT_SESSIONS.load(Ordering::Acquire);
-    loop {
-        if current == 0 {
-            tracing::warn!("Export session guard release requested with no active exports");
-            return;
-        }
-
-        match ACTIVE_EXPORT_SESSIONS.compare_exchange(
-            current,
-            current - 1,
-            Ordering::AcqRel,
-            Ordering::Acquire,
-        ) {
-            Ok(_) => {
-                info!(
-                    active_exports = current - 1,
-                    "Export session guard released"
-                );
-                return;
-            }
-            Err(next) => current = next,
-        }
-    }
-}
-
-pub fn export_session_active() -> bool {
-    ACTIVE_EXPORT_SESSIONS.load(Ordering::Acquire) > 0
-}
-
-fn retain_export_session_for_window(window_label: &str) {
-    retain_export_session();
-    let mut sessions = active_export_window_sessions();
-    *sessions.entry(window_label.to_string()).or_insert(0) += 1;
-}
-
-fn release_export_session_for_window(window_label: &str) {
-    let should_release = {
-        let mut sessions = active_export_window_sessions();
-        if let Some(count) = sessions.get_mut(window_label) {
-            *count -= 1;
-            if *count == 0 {
-                sessions.remove(window_label);
-            }
-            true
-        } else {
-            false
-        }
-    };
-
-    if should_release {
-        release_export_session();
-    } else {
-        tracing::warn!(
-            window = window_label,
-            "Export session guard release requested with no active window export"
-        );
-    }
-}
-
-fn release_export_sessions_for_window(window_label: &str) -> usize {
-    let count = active_export_window_sessions()
-        .remove(window_label)
-        .unwrap_or(0);
-
-    for _ in 0..count {
-        release_export_session();
-    }
-
-    count
-}
-
-fn release_all_window_export_sessions() -> usize {
-    let count = active_export_window_sessions()
-        .drain()
-        .map(|(_, count)| count)
-        .sum::();
-
-    for _ in 0..count {
-        release_export_session();
-    }
-
-    count
-}
-
-#[tauri::command]
-#[specta::specta]
-pub fn begin_export_session(window: tauri::Window) {
-    retain_export_session_for_window(window.label());
-}
-
-#[tauri::command]
-#[specta::specta]
-pub fn end_export_session(window: tauri::Window) {
-    release_export_session_for_window(window.label());
-}
-
-struct ExportSessionGuard;
-
-impl ExportSessionGuard {
-    fn new() -> Self {
-        retain_export_session();
-        Self
-    }
-}
-
-impl Drop for ExportSessionGuard {
-    fn drop(&mut self) {
-        release_export_session();
-    }
-}
-
-#[cfg(windows)]
-pub(crate) fn configure_exporter_command(command: &mut tokio::process::Command) {
-    command.creation_flags(CREATE_NO_WINDOW);
-}
-
-#[cfg(not(windows))]
-pub(crate) fn configure_exporter_command(_command: &mut tokio::process::Command) {}
-
-async fn run_out_of_process_export(
-    project_path: &Path,
-    settings: &ExportSettings,
-    progress: ExportProgress,
-    force_ffmpeg: bool,
-    cancel_token: CancellationToken,
-) -> Result {
-    let mode = initial_export_worker_mode();
-    match run_out_of_process_export_attempt(
-        project_path,
-        settings,
-        progress.clone(),
-        force_ffmpeg,
-        mode,
-        cancel_token.clone(),
-    )
-    .await
-    {
-        Ok(path) => Ok(path),
-        Err(e) if e != "Export cancelled" && !mode.is_software_safe() => {
-            error!(
-                error = %e,
-                "Export worker failed, retrying with software rendering and encoding"
-            );
-            run_out_of_process_export_attempt(
-                project_path,
-                settings,
-                progress,
-                force_ffmpeg,
-                ExportWorkerMode::SoftwareSafe,
-                cancel_token,
-            )
-            .await
-        }
-        Err(e) => Err(e),
-    }
-}
-
-fn initial_export_worker_mode() -> ExportWorkerMode {
-    if should_start_export_worker_in_software_safe_mode() {
-        ExportWorkerMode::SoftwareSafe
-    } else {
-        ExportWorkerMode::HardwareOptimized
-    }
-}
-
-async fn run_out_of_process_export_attempt(
-    project_path: &Path,
-    settings: &ExportSettings,
-    progress: ExportProgress,
-    force_ffmpeg: bool,
-    mode: ExportWorkerMode,
-    cancel_token: CancellationToken,
-) -> Result {
-    use cap_utils::operation_diagnostics::{Field, Operation};
-    let mut diagnostic = Operation::start(
-        "export_worker",
-        &[
-            Field::identifier(
-                "resource",
-                cap_utils::operation_diagnostics::resource_id(project_path),
-            ),
-            Field::number("requested_fps", settings.fps() as u64),
-            Field::flag("software_safe", mode.is_software_safe()),
-            Field::flag(
-                "force_ffmpeg_decoder",
-                mode.force_ffmpeg_decoder(force_ffmpeg),
-            ),
-        ],
-    );
-    let result = run_out_of_process_export_attempt_inner(
-        project_path,
-        settings,
-        progress,
-        force_ffmpeg,
-        mode,
-        cancel_token,
-        &mut diagnostic,
-    )
-    .await;
-    diagnostic.finish(result.is_ok());
-    result
-}
-
-async fn run_out_of_process_export_attempt_inner(
-    project_path: &Path,
-    settings: &ExportSettings,
-    progress: ExportProgress,
-    force_ffmpeg: bool,
-    mode: ExportWorkerMode,
-    cancel_token: CancellationToken,
-    diagnostic: &mut cap_utils::operation_diagnostics::Operation,
-) -> Result {
-    use cap_utils::operation_diagnostics::Field;
-    if cancel_token.is_cancelled() {
-        return Err("Export cancelled".to_string());
-    }
-
-    diagnostic.stage("resolving_worker");
-    let bin_path = resolve_exporter_binary()?;
-    let settings_json = serde_json::to_string(settings)
-        .map_err(|e| format!("Failed to serialize settings: {e}"))?;
-    let force_ffmpeg_decoder = mode.force_ffmpeg_decoder(force_ffmpeg);
-    let mut progress_forwarder = ExportProgressForwarder::new(progress);
-
-    info!(
-        path = %bin_path.display(),
-        project_path = %project_path.display(),
-        force_ffmpeg = force_ffmpeg_decoder,
-        mode = ?mode,
-        "Starting export worker process"
-    );
-
-    let mut command = tokio::process::Command::new(&bin_path);
-    command
-        .arg("export")
-        .arg(project_path)
-        .arg("--settings-json")
-        .arg(settings_json)
-        .stdin(Stdio::null());
-
-    if let Ok(parent) = serde_json::to_string(&diagnostic.id()) {
-        command.env("CAP_DIAGNOSTIC_PARENT", parent);
-    }
-    command.arg("--progress-json");
-
-    if force_ffmpeg_decoder {
-        command.arg("--force-ffmpeg-decoder");
-    }
-
-    if mode.is_software_safe() {
-        command.env("CAP_EXPORT_FORCE_SOFTWARE_ENCODER", "1");
-        if cfg!(windows) {
-            command.env("CAP_RENDER_FORCE_SOFTWARE_ADAPTER", "1");
-        }
-    }
-    configure_exporter_command(&mut command);
-
-    let mut child = cap_utils::process::spawn_with_piped_output(command).map_err(|e| {
-        format!(
-            "Failed to start export worker '{}': {e}",
-            bin_path.display()
-        )
-    })?;
-
-    if let Some(process_id) = child.id() {
-        diagnostic.field(Field::number("worker_process", process_id as u64));
-    }
-    diagnostic.stage("waiting_for_progress");
-    let stdout = child
-        .stdout
-        .take()
-        .ok_or_else(|| "Export worker stdout was not captured".to_string())?;
-    let stderr = child
-        .stderr
-        .take()
-        .ok_or_else(|| "Export worker stderr was not captured".to_string())?;
-    let stderr_task = tokio::spawn(collect_exporter_stderr_tail(stderr));
-
-    let mut completed_path = None;
-    let mut next_diagnostic_frame = 0;
-    let mut stdout_lines = tokio::io::BufReader::new(stdout).lines();
-
-    while let Some(line) = tokio::select! {
-        line = stdout_lines.next_line() => {
-            line.map_err(|e| format!("Failed reading export worker stdout: {e}"))?
-        }
-        _ = cancel_token.cancelled() => {
-            let _ = child.kill().await;
-            let _ = child.wait().await;
-            let _ = stderr_task.await;
-            diagnostic.stage("cancelled");
-            return Err("Export cancelled".to_string());
-        }
-    } {
-        match serde_json::from_str::(&line) {
-            Ok(ExportSidecarMessage::Progress {
-                rendered_count,
-                total_frames,
-            }) => {
-                if rendered_count >= next_diagnostic_frame {
-                    diagnostic.field(Field::number("rendered_frames", rendered_count as u64));
-                    diagnostic.field(Field::number("expected_frames", total_frames as u64));
-                    diagnostic.stage("rendering");
-                    next_diagnostic_frame =
-                        rendered_count.saturating_add((total_frames / 10).max(1));
-                }
-                if !progress_forwarder.send(rendered_count, total_frames) {
-                    let _ = child.kill().await;
-                    diagnostic.stage("cancelled");
-                    return Err("Export cancelled".to_string());
-                }
-            }
-            Ok(ExportSidecarMessage::Completed { path }) => {
-                diagnostic.field(Field::flag("worker_reported_completion", true));
-                diagnostic.stage("waiting_for_worker_exit");
-                completed_path = Some(path);
-            }
-            Err(e) => {
-                error!(
-                    line = %line,
-                    error = %e,
-                    "Ignoring invalid export worker stdout line"
-                );
-            }
-        }
-    }
-
-    let status = tokio::select! {
-        status = child.wait() => {
-            status.map_err(|e| format!("Failed waiting for export worker: {e}"))?
-        }
-        _ = cancel_token.cancelled() => {
-            let _ = child.kill().await;
-            let _ = child.wait().await;
-            let _ = stderr_task.await;
-            diagnostic.stage("cancelled");
-            return Err("Export cancelled".to_string());
-        }
-    };
-    diagnostic.field(Field::flag("worker_exit_success", status.success()));
-    if let Some(code) = status.code() {
-        diagnostic.field(Field::number(
-            "worker_exit_code_bits",
-            u64::from(code as u32),
-        ));
-    }
-    #[cfg(unix)]
-    {
-        use std::os::unix::process::ExitStatusExt;
-        if let Some(signal) = status.signal() {
-            diagnostic.field(Field::number("worker_signal", signal as u64));
-        }
-    }
-    diagnostic.stage("worker_exited");
-    let stderr_tail = stderr_task.await.unwrap_or_default();
-
-    if !status.success() {
-        if let Some(path) = completed_path {
-            // A worker can report completion and then abort during Windows GPU/codec teardown.
-            // Treat the completed output as authoritative so a post-export sidecar crash does
-            // not become a failed export for the user.
-            error!(
-                status = %status,
-                path = %path.display(),
-                "Export worker exited unsuccessfully after reporting completion"
-            );
-            return Ok(path);
-        }
-
-        let stderr_tail = stderr_tail.join("\n");
-        return Err(format!(
-            "Export worker exited with status {status}. Stderr tail:\n{stderr_tail}"
-        ));
-    }
-
-    completed_path
-        .ok_or_else(|| "Export worker finished without reporting an output path".to_string())
-}
-
-async fn collect_exporter_stderr_tail(stderr: tokio::process::ChildStderr) -> Vec {
-    let mut lines = tokio::io::BufReader::new(stderr).lines();
-    let mut tail = Vec::new();
-
-    loop {
-        match lines.next_line().await {
-            Ok(Some(line)) => {
-                if cap_utils::operation_diagnostics::relay_worker_record(&line) {
-                    continue;
-                }
-                if cfg!(debug_assertions) {
-                    info!(line = %line, "Export worker stderr");
-                }
-                tail.push(line);
-                if tail.len() > EXPORTER_STDERR_TAIL_LIMIT {
-                    tail.remove(0);
-                }
-            }
-            Ok(None) => break,
-            Err(e) => {
-                tail.push(format!("failed reading stderr: {e}"));
-                break;
-            }
-        }
-    }
-
-    tail
-}
-
-pub(crate) fn resolve_exporter_binary() -> Result {
-    let exe = std::env::current_exe().map_err(|e| format!("current_exe: {e}"))?;
-    if let Some(dir) = exe.parent() {
-        for candidate in adjacent_exporter_binary_candidates(dir) {
-            if candidate.exists() {
-                warn_if_exporter_stale(&exe, &candidate);
-                return Ok(candidate);
-            }
-        }
-    }
-
-    if let Ok(cwd) = std::env::current_dir() {
-        for root in std::iter::once(cwd.as_path()).chain(cwd.ancestors()) {
-            for candidate in exporter_binary_candidates(root) {
-                if candidate.exists() {
-                    warn_if_exporter_stale(&exe, &candidate);
-                    return Ok(candidate);
-                }
-            }
-        }
-    }
-
-    Err(format!(
-        "Export worker binary not found; place {} next to the app executable or build the Tauri sidecar bundle",
-        exporter_bin_name()
-    ))
-}
-
-/// Dev-loop trap: `tauri dev` rebuilds the app but not the exporter sidecar,
-/// so exports can silently run renderer code from days earlier and disagree
-/// with the preview. Debug builds log loudly when that is happening.
-fn warn_if_exporter_stale(app_exe: &Path, exporter: &Path) {
-    if !cfg!(debug_assertions) {
-        return;
-    }
-    let mtime = |p: &Path| std::fs::metadata(p).and_then(|m| m.modified()).ok();
-    if let (Some(app_time), Some(exporter_time)) = (mtime(app_exe), mtime(exporter))
-        && let Ok(lag) = app_time.duration_since(exporter_time)
-        && lag.as_secs() > 60
-    {
-        tracing::warn!(
-            exporter = %exporter.display(),
-            lag_secs = lag.as_secs(),
-            "Export worker binary is older than the app; exports may not match \
-             the preview. Rebuild it (cargo build -p cap) and copy it over \
-             target/debug/cap-exporter."
-        );
-    }
-}
-
-fn exporter_binary_candidates(root: &Path) -> Vec {
-    let mut candidates = Vec::new();
-
-    if cfg!(debug_assertions) {
-        candidates.extend(debug_exporter_binary_candidates(root));
-    }
-
-    candidates.push(
-        root.join("apps")
-            .join("desktop")
-            .join("src-tauri")
-            .join("binaries")
-            .join(exporter_bin_name()),
-    );
-
-    if let Some(target_triple) = current_target_triple() {
-        candidates.push(
-            root.join("apps")
-                .join("desktop")
-                .join("src-tauri")
-                .join("binaries")
-                .join(format!(
-                    "cap-exporter-{target_triple}{}",
-                    std::env::consts::EXE_SUFFIX
-                )),
-        );
-    }
-
-    candidates
-}
-
-fn debug_exporter_binary_candidates(root: &Path) -> Vec {
-    let mut candidates = vec![
-        root.join("target").join("debug").join(exporter_bin_name()),
-        root.join("target")
-            .join("debug")
-            .join(format!("cap{}", std::env::consts::EXE_SUFFIX)),
-    ];
-
-    if let Some(target_triple) = current_target_triple() {
-        candidates.push(
-            root.join("target")
-                .join(target_triple)
-                .join("debug")
-                .join(exporter_bin_name()),
-        );
-        candidates.push(
-            root.join("target")
-                .join(target_triple)
-                .join("debug")
-                .join(format!("cap{}", std::env::consts::EXE_SUFFIX)),
-        );
-        candidates.push(root.join("target").join("debug").join(format!(
-            "cap-exporter-{target_triple}{}",
-            std::env::consts::EXE_SUFFIX
-        )));
-    }
-
-    candidates
-}
-
-fn adjacent_exporter_binary_candidates(dir: &Path) -> Vec {
-    let mut candidates = Vec::new();
-
-    candidates.push(dir.join(exporter_bin_name()));
-
-    if let Some(target_triple) = current_target_triple() {
-        candidates.push(dir.join(format!(
-            "cap-exporter-{target_triple}{}",
-            std::env::consts::EXE_SUFFIX
-        )));
-    }
-
-    for subdir in ["../MacOS", "../Resources"] {
-        candidates.push(dir.join(subdir).join(exporter_bin_name()));
-        if let Some(target_triple) = current_target_triple() {
-            candidates.push(dir.join(subdir).join(format!(
-                "cap-exporter-{target_triple}{}",
-                std::env::consts::EXE_SUFFIX
-            )));
-        }
-    }
-
-    candidates
-}
-
-fn current_target_triple() -> Option<&'static str> {
-    if cfg!(all(
-        target_os = "windows",
-        target_arch = "x86_64",
-        target_env = "msvc"
-    )) {
-        Some("x86_64-pc-windows-msvc")
-    } else if cfg!(all(
-        target_os = "windows",
-        target_arch = "aarch64",
-        target_env = "msvc"
-    )) {
-        Some("aarch64-pc-windows-msvc")
-    } else if cfg!(all(target_os = "macos", target_arch = "aarch64")) {
-        Some("aarch64-apple-darwin")
-    } else if cfg!(all(target_os = "macos", target_arch = "x86_64")) {
-        Some("x86_64-apple-darwin")
-    } else {
-        None
-    }
-}
-
-fn exporter_bin_name() -> &'static str {
-    if cfg!(windows) {
-        "cap-exporter.exe"
-    } else {
-        "cap-exporter"
-    }
-}
-
-struct ExportActiveGuard<'a>(&'a AtomicBool);
-
-impl Drop for ExportActiveGuard<'_> {
-    fn drop(&mut self) {
-        self.0.store(false, Ordering::Release);
-        tracing::info!("Resuming editor preview after export");
-    }
-}
-
-struct ExportPreviewActiveGuard<'a>(&'a AtomicBool);
-
-impl<'a> ExportPreviewActiveGuard<'a> {
-    fn try_new(flag: &'a AtomicBool) -> Result {
-        flag.compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
-            .map(|_| Self(flag))
-            .map_err(|_| "Export preview generation is already in progress".to_string())
-    }
-}
-
-impl Drop for ExportPreviewActiveGuard<'_> {
-    fn drop(&mut self) {
-        self.0.store(false, Ordering::Release);
-    }
-}
-
-async fn wait_for_export_preview_idle_or_cancel(
-    flag: &AtomicBool,
-    cancel_token: &CancellationToken,
-) -> Result<(), String> {
-    while flag.load(Ordering::Acquire) {
-        tokio::select! {
-            _ = tokio::time::sleep(std::time::Duration::from_millis(20)) => {}
-            _ = cancel_token.cancelled() => return Err("Export cancelled".to_string()),
-        }
-    }
-
-    Ok(())
-}
-
-#[derive(Serialize, Deserialize, Clone, Copy, Debug, Type)]
-#[serde(tag = "format")]
-pub enum ExportSettings {
-    Mp4(cap_export::mp4::Mp4ExportSettings),
-    Gif(cap_export::gif::GifExportSettings),
-    Mov(cap_export::mov::MovExportSettings),
-}
-
-impl ExportSettings {
-    fn fps(&self) -> u32 {
-        match self {
-            ExportSettings::Mp4(settings) => settings.fps,
-            ExportSettings::Gif(settings) => settings.fps,
-            ExportSettings::Mov(settings) => settings.fps,
-        }
-    }
-
-    fn force_ffmpeg_decoder(&self) -> bool {
-        match self {
-            ExportSettings::Mp4(settings) => settings.force_ffmpeg_decoder,
-            ExportSettings::Gif(_) | ExportSettings::Mov(_) => false,
-        }
-    }
-
-    fn cursor_only(&self) -> bool {
-        match self {
-            ExportSettings::Mov(settings) => settings.cursor_only,
-            _ => false,
-        }
-    }
-}
-
-fn export_project_config(
-    project_config: cap_project::ProjectConfiguration,
-    cursor_only: bool,
-) -> cap_project::ProjectConfiguration {
-    if cursor_only {
-        make_cursor_only_project(project_config)
-    } else {
-        project_config
-    }
-}
-
-async fn do_export(
-    project_path: &Path,
-    settings: &ExportSettings,
-    progress: ExportProgress,
-    force_ffmpeg: bool,
-    cancel_token: CancellationToken,
-) -> Result {
-    if cancel_token.is_cancelled() {
-        return Err("Export cancelled".to_string());
-    }
-
-    let mut exporter_builder =
-        ExporterBase::builder(project_path.to_path_buf()).with_force_ffmpeg_decoder(force_ffmpeg);
-
-    if settings.cursor_only() {
-        let meta = RecordingMeta::load_for_project(project_path).map_err(|e| e.to_string())?;
-        exporter_builder =
-            exporter_builder.with_config(export_project_config(meta.project_config(), true));
-    }
-
-    let exporter_base = exporter_builder.build().await.map_err(|e| e.to_string())?;
-
-    let total_frames = exporter_base.total_frames(settings.fps());
-
-    if !progress.send(FramesRendered {
-        rendered_count: 0,
-        total_frames,
-    }) {
-        return Err("Export cancelled".to_string());
-    }
-
-    match settings {
-        ExportSettings::Mp4(mp4_settings) => {
-            let progress = progress.clone();
-            let cancel_token = cancel_token.clone();
-            mp4_settings
-                .export(exporter_base, move |frame_index| {
-                    if cancel_token.is_cancelled() {
-                        return false;
-                    }
-
-                    progress.send(FramesRendered {
-                        rendered_count: (frame_index + 1).min(total_frames),
-                        total_frames,
-                    })
-                })
-                .await
-        }
-        ExportSettings::Gif(gif_settings) => {
-            let progress = progress.clone();
-            let cancel_token = cancel_token.clone();
-            gif_settings
-                .export(exporter_base, move |frame_index| {
-                    if cancel_token.is_cancelled() {
-                        return false;
-                    }
-
-                    progress.send(FramesRendered {
-                        rendered_count: (frame_index + 1).min(total_frames),
-                        total_frames,
-                    })
-                })
-                .await
-        }
-        ExportSettings::Mov(mov_settings) => {
-            let progress = progress.clone();
-            let cancel_token = cancel_token.clone();
-            mov_settings
-                .export(exporter_base, move |frame_index| {
-                    if cancel_token.is_cancelled() {
-                        return false;
-                    }
-
-                    progress.send(FramesRendered {
-                        rendered_count: (frame_index + 1).min(total_frames),
-                        total_frames,
-                    })
-                })
-                .await
-        }
-    }
-}
-
-fn is_frame_decode_error(error: &str) -> bool {
-    error.contains("Failed to decode video frames")
-        || error.contains("Too many consecutive frame failures")
-        || error.contains("waiting for frame 0")
-}
-
-fn should_force_ffmpeg_export(_project_path: &Path, settings: &ExportSettings) -> bool {
-    settings.force_ffmpeg_decoder()
-}
-
-fn should_force_ffmpeg_preview() -> bool {
-    false
-}
-
-fn should_start_export_worker_in_software_safe_mode() -> bool {
-    false
-}
-
-fn should_use_out_of_process_export() -> bool {
-    cfg!(any(target_os = "macos", target_os = "windows"))
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(window, progress, editor))]
-pub async fn export_video(
-    window: tauri::Window,
-    project_path: PathBuf,
-    progress: tauri::ipc::Channel,
-    settings: ExportSettings,
-    editor: OptionalWindowEditorInstance,
-) -> Result {
-    let window_label = window.label().to_string();
-    let app = window.app_handle().clone();
-    Box::pin(run_export_command(move || async move {
-        let cancellation_guard =
-            ExportCancellationGuard::new(next_export_command_id("export"), Some(window_label));
-        let resources = export_resource_preflight(
-            &app,
-            &project_path,
-            &settings,
-            &editor,
-            None,
-            &cancellation_guard.token(),
-        )
-        .await?;
-        export_video_inner(
-            project_path,
-            settings,
-            editor,
-            ExportProgress(progress),
-            cancellation_guard.token(),
-            resources,
-        )
-        .await
-    }))
-    .await
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(window, progress, editor))]
-pub async fn export_video_with_id(
-    window: tauri::Window,
-    project_path: PathBuf,
-    progress: tauri::ipc::Channel,
-    settings: ExportSettings,
-    export_id: String,
-    editor: OptionalWindowEditorInstance,
-) -> Result {
-    let window_label = window.label().to_string();
-    let app = window.app_handle().clone();
-    Box::pin(run_export_command(move || async move {
-        let cancellation_guard = ExportCancellationGuard::new(export_id, Some(window_label));
-        let resources = export_resource_preflight(
-            &app,
-            &project_path,
-            &settings,
-            &editor,
-            None,
-            &cancellation_guard.token(),
-        )
-        .await?;
-        export_video_inner(
-            project_path,
-            settings,
-            editor,
-            ExportProgress(progress),
-            cancellation_guard.token(),
-            resources,
-        )
-        .await
-    }))
-    .await
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(window, progress, editor))]
-pub async fn export_video_to_file(
-    window: tauri::Window,
-    project_path: PathBuf,
-    progress: tauri::ipc::Channel,
-    settings: ExportSettings,
-    file_name: String,
-    file_type: String,
-    editor: OptionalWindowEditorInstance,
-) -> Result {
-    let app = window.app_handle().clone();
-    let window_label = window.label().to_string();
-    Box::pin(run_export_command(move || async move {
-        let cancellation_guard = ExportCancellationGuard::new(
-            next_export_command_id("export-to-file"),
-            Some(window_label),
-        );
-        export_video_to_file_inner(
-            app.clone(),
-            project_path,
-            settings,
-            editor,
-            ExportProgress(progress),
-            ExportSaveDialogRequest {
-                #[cfg(not(target_os = "linux"))]
-                app,
-                #[cfg(target_os = "linux")]
-                parent: window,
-                #[cfg(target_os = "linux")]
-                cancel_token: cancellation_guard.token(),
-                file_name,
-                file_type,
-            },
-            cancellation_guard.token(),
-        )
-        .await
-    }))
-    .await
-}
-
-async fn export_video_to_file_inner(
-    app: tauri::AppHandle,
-    project_path: PathBuf,
-    settings: ExportSettings,
-    editor: OptionalWindowEditorInstance,
-    progress: ExportProgress,
-    save_dialog: ExportSaveDialogRequest,
-    cancel_token: CancellationToken,
-) -> Result {
-    let _session_guard = ExportSessionGuard::new();
-    let Some(save_path) = show_export_save_dialog(save_dialog).await? else {
-        return Err("Save dialog cancelled".to_string());
-    };
-
-    let destination = match &save_path {
-        ExportSaveDestination::Selected(path) => Some(path.as_path()),
-        #[cfg(any(target_os = "macos", test))]
-        ExportSaveDestination::Default => None,
-    };
-    let resources = export_resource_preflight(
-        &app,
-        &project_path,
-        &settings,
-        &editor,
-        destination,
-        &cancel_token,
-    )
-    .await?;
-    let output_path = export_video_inner(
-        project_path,
-        settings,
-        editor,
-        progress,
-        cancel_token,
-        resources,
-    )
-    .await?;
-    match save_path {
-        ExportSaveDestination::Selected(path) => {
-            copy_export_to_path(&output_path, &path).await?;
-            Ok(path)
-        }
-        #[cfg(any(target_os = "macos", test))]
-        ExportSaveDestination::Default => Ok(output_path),
-    }
-}
-
-async fn export_resource_preflight(
-    app: &tauri::AppHandle,
-    project_path: &Path,
-    settings: &ExportSettings,
-    editor: &OptionalWindowEditorInstance,
-    destination: Option<&Path>,
-    cancel: &CancellationToken,
-) -> Result {
-    if cancel.is_cancelled() {
-        return Err("Export cancelled".into());
-    }
-    let estimate = editor
-        .as_ref()
-        .map(|editor| {
-            let duration = export_estimate_duration(
-                &editor.project_config.1.borrow(),
-                editor.recordings.duration(),
-            );
-            estimated_working_bytes(
-                export_estimates_for_duration(settings, duration).estimated_size_mb,
-            )
-        })
-        .unwrap_or(0);
-    let mut disks = vec![DiskBudget {
-        path: project_path.to_path_buf(),
-        description: "your recording drive",
-        estimated_bytes: estimate,
-    }];
-    if let Some(path) = destination {
-        disks.push(DiskBudget {
-            path: path.to_path_buf(),
-            description: "your export drive",
-            estimated_bytes: estimate,
-        });
-    }
-    let resources = ExportResources::new(disks);
-    if let Some(message) = resources.check().await? {
-        if cancel.is_cancelled() {
-            return Err("Export cancelled".into());
-        }
-        let (sender, receiver) = tokio::sync::oneshot::channel();
-        app.dialog()
-            .message(message)
-            .title("Check export resources")
-            .kind(MessageDialogKind::Warning)
-            .buttons(MessageDialogButtons::OkCancelCustom(
-                "Proceed anyway".into(),
-                "Go back".into(),
-            ))
-            .show(move |confirmed| {
-                let _ = sender.send(confirmed);
-            });
-        let confirmed = tokio::select! {
-            biased;
-            _ = cancel.cancelled() => false,
-            confirmed = receiver => confirmed.unwrap_or(false),
-        };
-        if !confirmed {
-            return Err("Export cancelled".into());
-        }
-        let _ = resources.check().await?;
-    }
-    if cancel.is_cancelled() {
-        return Err("Export cancelled".into());
-    }
-    Ok(resources)
-}
-
-async fn export_video_inner(
-    project_path: PathBuf,
-    settings: ExportSettings,
-    editor: OptionalWindowEditorInstance,
-    progress: ExportProgress,
-    cancel_token: CancellationToken,
-    resources: ExportResources,
-) -> Result {
-    let stopped = cancel_token.child_token();
-    resources
-        .supervise(
-            export_video_attempts(project_path, settings, editor, progress, stopped.clone()),
-            || stopped.cancel(),
-        )
-        .await
-}
-
-async fn export_video_attempts(
-    project_path: PathBuf,
-    settings: ExportSettings,
-    editor: OptionalWindowEditorInstance,
-    progress: ExportProgress,
-    cancel_token: CancellationToken,
-) -> Result {
-    let _session_guard = ExportSessionGuard::new();
-    let force_ffmpeg = should_force_ffmpeg_export(&project_path, &settings);
-    info!(
-        project_path = %project_path.display(),
-        force_ffmpeg,
-        settings = ?settings,
-        "Starting export"
-    );
-
-    let _guard = if let Some(ref ed) = *editor {
-        ed.export_active.store(true, Ordering::Release);
-        tracing::info!("Pausing editor preview during export");
-        Some(ExportActiveGuard(&ed.export_active))
-    } else {
-        None
-    };
-
-    if let Some(ref ed) = *editor {
-        wait_for_export_preview_idle_or_cancel(&ed.export_preview_active, &cancel_token).await?;
-    }
-
-    let result = if should_use_out_of_process_export() {
-        run_out_of_process_export(
-            &project_path,
-            &settings,
-            progress.clone(),
-            force_ffmpeg,
-            cancel_token.clone(),
-        )
-        .await
-    } else {
-        run_protected_export(
-            &project_path,
-            &settings,
-            progress.clone(),
-            force_ffmpeg,
-            cancel_token.clone(),
-        )
-        .await
-    };
-
-    match result {
-        Ok(path) => {
-            info!("Exported to {} completed", path.display());
-            Ok(path)
-        }
-        Err(e) if !force_ffmpeg && is_frame_decode_error(&e) => {
-            if cancel_token.is_cancelled() {
-                return Err("Export cancelled".to_string());
-            }
-
-            info!(
-                "Export failed with frame decode error, retrying with FFmpeg decoder: {}",
-                e
-            );
-
-            let retry_result = if should_use_out_of_process_export() {
-                run_out_of_process_export(
-                    &project_path,
-                    &settings,
-                    progress,
-                    true,
-                    cancel_token.clone(),
-                )
-                .await
-            } else {
-                run_protected_export(
-                    &project_path,
-                    &settings,
-                    progress,
-                    true,
-                    cancel_token.clone(),
-                )
-                .await
-            };
-
-            match retry_result {
-                Ok(path) => {
-                    info!(
-                        "Export succeeded with FFmpeg decoder fallback: {}",
-                        path.display()
-                    );
-                    Ok(path)
-                }
-                Err(retry_e) => {
-                    if cancel_token.is_cancelled() || retry_e == "Export cancelled" {
-                        return Err("Export cancelled".to_string());
-                    }
-
-                    sentry::capture_message(&retry_e, sentry::Level::Error);
-                    Err(retry_e)
-                }
-            }
-        }
-        Err(e) if cancel_token.is_cancelled() || e == "Export cancelled" => {
-            Err("Export cancelled".to_string())
-        }
-        Err(e) => {
-            sentry::capture_message(&e, sentry::Level::Error);
-            Err(e)
-        }
-    }
-}
-
-async fn show_export_save_dialog(
-    request: ExportSaveDialogRequest,
-) -> Result, String> {
-    let ExportSaveDialogRequest {
-        #[cfg(not(target_os = "linux"))]
-        app,
-        #[cfg(target_os = "linux")]
-        parent,
-        #[cfg(target_os = "linux")]
-        cancel_token,
-        file_name,
-        file_type,
-    } = request;
-    info!(file_name, file_type, "Save file dialog requested");
-
-    let (name, extension) = match file_type.as_str() {
-        "mp4" => ("MP4 Video", "mp4"),
-        "gif" => ("GIF Image", "gif"),
-        "mov" => ("MOV Video", "mov"),
-        _ => {
-            warn!(file_type, "Invalid export save file dialog type");
-            return Err("Invalid file type".to_string());
-        }
-    };
-
-    info!(file_name, name, extension, "Showing save file dialog");
-
-    #[cfg(target_os = "linux")]
-    let result = show_linux_save_dialog(parent, cancel_token, file_name, name, extension)
-        .await
-        .map(|path| path.map(ExportSaveDestination::Selected));
-    #[cfg(target_os = "macos")]
-    let result = Ok(resolve_macos_export_destination(
-        show_macos_save_dialog(&app, file_name, extension).await,
-    ));
-    #[cfg(not(any(target_os = "linux", target_os = "macos")))]
-    let result = {
-        let (tx, rx) = tokio::sync::oneshot::channel();
-        app.dialog()
-            .file()
-            .set_title("Save File")
-            .set_file_name(file_name)
-            .add_filter(name, &[extension])
-            .save_file(move |path| {
-                let _ = tx.send(path.and_then(|p| p.as_path().map(PathBuf::from)));
-            });
-        rx.await
-            .map_err(|error| error.to_string())
-            .map(|path| path.map(ExportSaveDestination::Selected))
-    };
-    result.inspect(|result| {
-        info!(path = ?result, "Save file dialog completed");
-    })
-}
-
-#[cfg(target_os = "macos")]
-pub(crate) async fn show_macos_save_dialog(
-    app: &tauri::AppHandle,
-    file_name: String,
-    extension: &'static str,
-) -> Result, String> {
-    let (tx, rx) = tokio::sync::oneshot::channel();
-    app.run_on_main_thread(move || {
-        crate::macos_save_panel::show(&file_name, &[extension], move |result| {
-            let _ = tx.send(result);
-        });
-    })
-    .map_err(|error| format!("Unable to show save dialog: {error}"))?;
-    rx.await
-        .map_err(|error| format!("Save dialog stopped before completing: {error}"))?
-}
-
-#[cfg(target_os = "linux")]
-pub(crate) async fn show_linux_save_dialog(
-    parent: tauri::Window,
-    cancel_token: CancellationToken,
-    file_name: String,
-    name: &'static str,
-    extension: &'static str,
-) -> Result, String> {
-    let (tx, rx) = tokio::sync::oneshot::channel();
-    let window = parent.clone();
-    parent
-        .run_on_main_thread(move || {
-            use gtk::prelude::*;
-
-            let prepared = window
-                .gtk_window()
-                .map_err(|error| format!("Export window is unavailable: {error}"))
-                .map(|parent| parent.upcast::())
-                .and_then(|parent| {
-                    create_linux_export_save_dialog(&parent, &file_name, name, extension)
-                        .map(|dialog| (parent, dialog))
-                });
-            match prepared {
-                Ok((parent, dialog)) => {
-                    run_linux_export_save_dialog(parent, dialog, cancel_token, tx);
-                }
-                Err(error) => {
-                    let _ = tx.send(Err(error));
-                }
-            }
-        })
-        .map_err(|error| format!("Unable to show export save dialog: {error}"))?;
-    rx.await.map_err(|error| error.to_string())?
-}
-
-#[cfg(target_os = "linux")]
-fn create_linux_export_save_dialog(
-    parent: >k::Window,
-    file_name: &str,
-    filter_name: &str,
-    extension: &str,
-) -> Result {
-    use gtk::prelude::*;
-
-    if parent.in_destruction() || !parent.is_mapped() {
-        return Err("Export window is no longer available".to_string());
-    }
-
-    // rfd's GTK backend discards its parent, so tiled compositors can clip the save controls.
-    let dialog = gtk::FileChooserNative::new(
-        Some("Save File"),
-        Some(parent),
-        gtk::FileChooserAction::Save,
-        None,
-        None,
-    );
-    dialog.set_do_overwrite_confirmation(true);
-    if !file_name.contains('\0') {
-        dialog.set_current_name(file_name);
-    }
-    let filter = gtk::FileFilter::new();
-    filter.set_name(Some(filter_name));
-    filter.add_pattern(&format!("*.{extension}"));
-    dialog.add_filter(filter);
-    Ok(dialog)
-}
-
-#[cfg(target_os = "linux")]
-fn run_linux_export_save_dialog(
-    parent: gtk::Window,
-    dialog: gtk::FileChooserNative,
-    cancel_token: CancellationToken,
-    mut result_tx: tokio::sync::oneshot::Sender, String>>,
-) {
-    use gtk::prelude::*;
-
-    let (destroy_tx, destroyed) = tokio::sync::oneshot::channel();
-    let destroy_tx = std::cell::Cell::new(Some(destroy_tx));
-    let parent_destroyed = std::rc::Rc::new(std::cell::Cell::new(false));
-    let destroyed_flag = parent_destroyed.clone();
-    let destroy_handler = parent.connect_destroy(move |_| {
-        destroyed_flag.set(true);
-        if let Some(sender) = destroy_tx.take() {
-            let _ = sender.send(());
-        }
-    });
-    std::mem::drop(gtk::glib::MainContext::default().spawn_local(async move {
-        let result = tokio::select! {
-            biased;
-            _ = cancel_token.cancelled() => Err("Export cancelled".to_string()),
-            _ = result_tx.closed() => Err("Export cancelled".to_string()),
-            _ = destroyed => Err("Export window was closed".to_string()),
-            response = dialog.run_future() => {
-                Ok(if response == gtk::ResponseType::Accept {
-                    dialog.filename()
-                } else {
-                    None
-                })
-            }
-        };
-        if !parent_destroyed.get() {
-            parent.disconnect(destroy_handler);
-        }
-        dialog.destroy();
-        let _ = result_tx.send(result);
-    }));
-}
-
-async fn copy_export_to_path(src: &Path, dst: &Path) -> Result<(), String> {
-    info!(
-        src = %src.display(),
-        dst = %dst.display(),
-        "Copying exported video to selected path"
-    );
-
-    if let Some(parent) = dst.parent() {
-        tokio::fs::create_dir_all(parent)
-            .await
-            .map_err(|e| format!("Failed to create export target directory: {e}"))?;
-    }
-
-    let bytes = tokio::fs::copy(src, dst)
-        .await
-        .map_err(|e| format!("Failed to copy exported file: {e}"))?;
-
-    let src_size = tokio::fs::metadata(src)
-        .await
-        .map_err(|e| format!("Failed to read exported file metadata: {e}"))?
-        .len();
-
-    if bytes != src_size {
-        let _ = tokio::fs::remove_file(dst).await;
-        return Err(format!(
-            "Export copy verification failed: copied {bytes} bytes but source is {src_size} bytes"
-        ));
-    }
-
-    info!(bytes, dst = %dst.display(), "Copied exported video to selected path");
-    Ok(())
-}
-
-#[derive(Debug, serde::Serialize, specta::Type)]
-pub struct ExportEstimates {
-    pub duration_seconds: f64,
-    pub estimated_time_seconds: f64,
-    pub estimated_size_mb: f64,
-}
-
-static EXPORT_ESTIMATE_REQUESTS: LazyLock =
-    LazyLock::new(estimate_request::EstimateRequests::default);
-
-#[tauri::command]
-#[specta::specta]
-pub fn cancel_export_estimates(editor: WindowEditorInstance) {
-    EXPORT_ESTIMATE_REQUESTS.cancel(&editor.project_path);
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(editor, on_estimate))]
-pub async fn get_export_estimates(
-    path: PathBuf,
-    settings: ExportSettings,
-    on_estimate: tauri::ipc::Channel,
-    editor: WindowEditorInstance,
-) -> Result {
-    if path != editor.project_path {
-        return Err("Export estimate does not match the open project".into());
-    }
-    EXPORT_ESTIMATE_REQUESTS
-        .run(path.clone(), |cancel| async move {
-            let project = load_export_preview_config(path, settings.cursor_only()).await?;
-            let settings = match settings {
-                ExportSettings::Mp4(settings) => {
-                    cap_export::settings::ExportSettings::Mp4(settings)
-                }
-                ExportSettings::Gif(settings) => {
-                    cap_export::settings::ExportSettings::Gif(settings)
-                }
-                ExportSettings::Mov(settings) => {
-                    cap_export::settings::ExportSettings::Mov(settings)
-                }
-            };
-            cap_export::estimates::estimate_export(
-                (**editor).clone(),
-                project,
-                settings,
-                cancel,
-                move |estimate| {
-                    let _ = on_estimate.send(estimate);
-                },
-            )
-            .await
-        })
-        .await
-}
-
-fn export_estimates_for_duration(
-    settings: &ExportSettings,
-    duration_seconds: f64,
-) -> ExportEstimates {
-    let (resolution, fps) = match settings {
-        ExportSettings::Mp4(s) => (s.resolution_base, s.fps),
-        ExportSettings::Gif(s) => (s.resolution_base, s.fps),
-        ExportSettings::Mov(s) => (s.resolution_base, s.fps),
-    };
-
-    let (width, height) = (resolution.x, resolution.y);
-    let total_pixels = (width * height) as f64;
-    let fps_f64 = fps as f64;
-    let total_frames = (duration_seconds * fps_f64).ceil();
-
-    let (estimated_size_mb, estimated_time_seconds) = match &settings {
-        ExportSettings::Mp4(mp4_settings) => {
-            let bits_per_pixel = mp4_settings.effective_bpp() as f64;
-            let effective_fps = ((fps_f64 - 30.0).max(0.0) * 0.6) + fps_f64.min(30.0);
-            let video_bitrate = total_pixels * bits_per_pixel * effective_fps;
-            let audio_bitrate = 192_000.0;
-            let total_bitrate = video_bitrate + audio_bitrate;
-            let encoder_efficiency = 0.5;
-            let size_mb =
-                (total_bitrate * encoder_efficiency * duration_seconds) / (8.0 * 1024.0 * 1024.0);
-
-            let effective_render_fps = match (width, height) {
-                (w, _) if w >= 3840 => 175.0,
-                _ => 290.0,
-            };
-            let time_estimate = total_frames / effective_render_fps;
-
-            (size_mb, time_estimate)
-        }
-        ExportSettings::Gif(_) => {
-            let bytes_per_frame = total_pixels * 0.5;
-            let gif_efficiency = 0.07;
-            let size_mb = (bytes_per_frame * gif_efficiency * total_frames) / (1024.0 * 1024.0);
-
-            let frames_per_sec = match (width, height) {
-                (w, h) if w <= 1280 && h <= 720 => 10.0,
-                (w, h) if w <= 1920 && h <= 1080 => 5.0,
-                _ => 2.0,
-            };
-            let time_estimate = total_frames / frames_per_sec;
-
-            (size_mb, time_estimate)
-        }
-        ExportSettings::Mov(_) => {
-            let size_mb = estimate_cursor_only_size_mb(total_pixels, total_frames);
-            let effective_render_fps = match (width, height) {
-                (w, _) if w >= 3840 => 140.0,
-                _ => 220.0,
-            };
-            let time_estimate = total_frames / effective_render_fps;
-
-            (size_mb, time_estimate)
-        }
-    };
-
-    ExportEstimates {
-        duration_seconds,
-        estimated_time_seconds,
-        estimated_size_mb,
-    }
-}
-
-#[derive(Debug, Serialize, Deserialize, Type)]
-pub struct ExportPreviewSettings {
-    pub fps: u32,
-    pub resolution_base: XY,
-    pub compression_bpp: f32,
-    #[serde(default)]
-    pub cursor_only: bool,
-}
-
-#[derive(Debug, Serialize, Deserialize, Type)]
-pub struct ExportPreviewResult {
-    pub jpeg_base64: String,
-    pub estimated_size_mb: f64,
-    pub actual_width: u32,
-    pub actual_height: u32,
-    pub frame_render_time_ms: f64,
-    pub total_frames: u32,
-}
-
-fn estimate_cursor_only_size_mb(total_pixels: f64, total_frames: f64) -> f64 {
-    let bytes_per_frame = total_pixels * 0.4;
-    (bytes_per_frame * total_frames) / (1024.0 * 1024.0)
-}
-
-fn export_estimate_duration(
-    project_config: &cap_project::ProjectConfiguration,
-    source_duration: f64,
-) -> f64 {
-    project_config
-        .timeline
-        .as_ref()
-        .map(cap_project::TimelineConfiguration::duration)
-        .unwrap_or(source_duration)
-}
-
-fn bpp_to_jpeg_quality(bpp: f32) -> u8 {
-    ((bpp - 0.04) / (0.3 - 0.04) * (95.0 - 40.0) + 40.0).clamp(40.0, 95.0) as u8
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip_all)]
-pub async fn generate_export_preview(
-    project_path: PathBuf,
-    frame_time: f64,
-    settings: ExportPreviewSettings,
-) -> Result {
-    match AssertUnwindSafe(generate_export_preview_inner(
-        project_path,
-        frame_time,
-        settings,
-    ))
-    .catch_unwind()
-    .await
-    {
-        Ok(result) => result,
-        Err(panic) => {
-            let panic_msg = panic_message(panic);
-            error!(
-                target: "cap_desktop_export",
-                panic = %panic_msg,
-                "generate_export_preview panicked"
-            );
-            sentry::capture_message(
-                &format!("Export preview panicked: {panic_msg}"),
-                sentry::Level::Error,
-            );
-            Err("Export preview failed unexpectedly".to_string())
-        }
-    }
-}
-
-#[instrument(skip_all)]
-async fn generate_export_preview_inner(
-    project_path: PathBuf,
-    frame_time: f64,
-    settings: ExportPreviewSettings,
-) -> Result {
-    use base64::{Engine, engine::general_purpose::STANDARD};
-    use cap_editor::create_segments;
-    use std::time::Instant;
-
-    let recording_meta = RecordingMeta::load_for_project(&project_path)
-        .map_err(|e| format!("Failed to load recording meta: {e}"))?;
-
-    let cap_project::RecordingMetaInner::Studio(studio_meta) = &recording_meta.inner else {
-        return Err("Cannot preview non-studio recordings".to_string());
-    };
-
-    let mut project_config =
-        export_project_config(recording_meta.project_config(), settings.cursor_only);
-
-    let recordings = Arc::new(
-        ProjectRecordingsMeta::new(&recording_meta.project_path, studio_meta)
-            .map_err(|e| format!("Failed to load recordings: {e}"))?,
-    );
-
-    synchronize_preview_timing(
-        &recording_meta,
-        &mut project_config,
-        &recordings
-            .segments
-            .iter()
-            .map(|segment| segment.display.duration)
-            .collect::>(),
-    );
-    let project_config = Arc::new(project_config);
-
-    let render_constants = Arc::new(
-        RenderVideoConstants::new(
-            &recordings.segments,
-            recording_meta.clone(),
-            (**studio_meta).clone(),
-        )
-        .await
-        .map_err(|e| format!("Failed to create render constants: {e}"))?,
-    );
-
-    let force_ffmpeg = should_force_ffmpeg_preview();
-    info!(
-        project_path = %project_path.display(),
-        force_ffmpeg,
-        "Starting export preview"
-    );
-
-    let segments = create_segments(&recording_meta, studio_meta, force_ffmpeg)
-        .await
-        .map_err(|e| format!("Failed to create segments: {e}"))?;
-
-    let render_segments: Vec = segments
-        .iter()
-        .map(|s| RenderSegment {
-            cursor: s.cursor.clone(),
-            keyboard: s.keyboard.clone(),
-            decoders: s.decoders.clone(),
-            render_display: !settings.cursor_only,
-        })
-        .collect();
-
-    let transition_mapping = project_config.timeline.as_ref().and_then(|timeline| {
-        if timeline.transitions.is_empty() {
-            return None;
-        }
-        match timeline.get_frame_mapping(frame_time) {
-            Some(TimelineFrameMapping::Transition {
-                outgoing,
-                kind,
-                progress,
-                ..
-            }) => Some((outgoing, kind, progress)),
-            _ => None,
-        }
-    });
-
-    let Some((segment_time, segment)) = project_config.get_segment_time(frame_time) else {
-        return Err("Frame time is outside video duration".to_string());
-    };
-
-    let render_segment = &render_segments[segment.recording_clip as usize];
-    let clip_config = project_config
-        .clips
-        .iter()
-        .find(|v| v.index == segment.recording_clip);
-
-    let render_start = Instant::now();
-
-    let segment_frames = render_segment
-        .decoders
-        .get_frames(
-            segment_time as f32,
-            !project_config.camera.hide && render_segment.render_display,
-            render_segment.render_display,
-            clip_config.map(|v| v.offsets).unwrap_or_default(),
-        )
-        .await
-        .ok_or_else(|| "Failed to decode frame".to_string())?;
-
-    let frame_number = (frame_time * settings.fps as f64).floor() as u32;
-    let total_duration = project_config
-        .timeline
-        .as_ref()
-        .map(|t| t.duration())
-        .unwrap_or(0.0);
-
-    let mut zoom_timeline = ZoomTransformTimeline::from_project_for_clip(
-        &project_config,
-        &render_segment.cursor,
-        total_duration,
-        render_constants.options.screen_size,
-        segment.recording_clip,
-    );
-    zoom_timeline.ensure_precomputed_until((frame_number as f32 + 1.0) / settings.fps as f32);
-
-    let uniforms = ProjectUniforms::new(
-        &render_constants,
-        &project_config,
-        frame_number,
-        settings.fps,
-        settings.resolution_base,
-        &render_segment.cursor,
-        &segment_frames,
-        total_duration,
-        &zoom_timeline,
-    );
-
-    let mut frame_renderer = FrameRenderer::new(&render_constants);
-    let mut layers = RendererLayers::new_with_options(
-        &render_constants.device,
-        &render_constants.queue,
-        render_constants.is_software_adapter,
-    );
-
-    let frame = if let Some((outgoing, kind, progress)) = transition_mapping {
-        let outgoing_segment = &render_segments[outgoing.segment.recording_clip as usize];
-        let outgoing_offsets = project_config
-            .clips
-            .iter()
-            .find(|clip| clip.index == outgoing.segment.recording_clip)
-            .map(|clip| clip.offsets)
-            .unwrap_or_default();
-        let outgoing_frames = outgoing_segment
-            .decoders
-            .get_frames(
-                outgoing.source_time as f32,
-                !project_config.camera.hide && outgoing_segment.render_display,
-                outgoing_segment.render_display,
-                outgoing_offsets,
-            )
-            .await
-            .ok_or_else(|| "Failed to decode outgoing frame".to_string())?;
-        let mut outgoing_zoom = ZoomTransformTimeline::from_project_for_outgoing_clip(
-            &project_config,
-            &outgoing_segment.cursor,
-            total_duration,
-            render_constants.options.screen_size,
-            outgoing.segment.recording_clip,
-        );
-        outgoing_zoom.ensure_precomputed_until((frame_number as f32 + 1.0) / settings.fps as f32);
-        let outgoing_uniforms = ProjectUniforms::new(
-            &render_constants,
-            &project_config,
-            frame_number,
-            settings.fps,
-            settings.resolution_base,
-            &outgoing_segment.cursor,
-            &outgoing_frames,
-            total_duration,
-            &outgoing_zoom,
-        );
-        frame_renderer
-            .render_transition_immediate(
-                TransitionRenderInput {
-                    segment_frames: outgoing_frames,
-                    uniforms: outgoing_uniforms,
-                    cursor: &outgoing_segment.cursor,
-                    render_display: outgoing_segment.render_display,
-                },
-                TransitionRenderInput {
-                    segment_frames,
-                    uniforms,
-                    cursor: &render_segment.cursor,
-                    render_display: render_segment.render_display,
-                },
-                kind,
-                progress as f32,
-                &mut layers,
-            )
-            .await
-    } else {
-        frame_renderer
-            .render_immediate(
-                segment_frames,
-                uniforms,
-                &render_segment.cursor,
-                render_segment.render_display,
-                &mut layers,
-            )
-            .await
-    }
-    .map_err(|e| format!("Failed to render frame: {e}"))?;
-
-    let frame_render_time_ms = render_start.elapsed().as_secs_f64() * 1000.0;
-
-    let width = frame.width;
-    let height = frame.height;
-
-    let rgb_data: Vec = frame
-        .data
-        .chunks(frame.padded_bytes_per_row as usize)
-        .flat_map(|row| {
-            row[0..(frame.width * 4) as usize]
-                .chunks(4)
-                .flat_map(|chunk| [chunk[0], chunk[1], chunk[2]])
-        })
-        .collect();
-
-    let jpeg_quality = bpp_to_jpeg_quality(settings.compression_bpp);
-    let mut jpeg_buffer = Vec::new();
-    {
-        let mut encoder = JpegEncoder::new_with_quality(&mut jpeg_buffer, jpeg_quality);
-        encoder
-            .encode(&rgb_data, width, height, image::ExtendedColorType::Rgb8)
-            .map_err(|e| format!("Failed to encode JPEG: {e}"))?;
-    }
-
-    let jpeg_base64 = STANDARD.encode(&jpeg_buffer);
-
-    let total_pixels = (settings.resolution_base.x * settings.resolution_base.y) as f64;
-    let fps_f64 = settings.fps as f64;
-
-    let metadata = get_video_metadata(project_path.clone()).await?;
-    let duration_seconds = export_estimate_duration(&project_config, metadata.duration);
-    let total_frames = (duration_seconds * fps_f64).ceil() as u32;
-
-    let estimated_size_mb = if settings.cursor_only {
-        let total_frames_f64 = (duration_seconds * fps_f64).ceil();
-        estimate_cursor_only_size_mb(total_pixels, total_frames_f64)
-    } else {
-        let effective_fps = ((fps_f64 - 30.0).max(0.0) * 0.6) + fps_f64.min(30.0);
-        let video_bitrate = total_pixels * settings.compression_bpp as f64 * effective_fps;
-        let audio_bitrate = 192_000.0;
-        let total_bitrate = video_bitrate + audio_bitrate;
-        let encoder_efficiency = 0.5;
-        (total_bitrate * encoder_efficiency * duration_seconds) / (8.0 * 1024.0 * 1024.0)
-    };
-
-    Ok(ExportPreviewResult {
-        jpeg_base64,
-        estimated_size_mb,
-        actual_width: width,
-        actual_height: height,
-        frame_render_time_ms,
-        total_frames,
-    })
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use tempfile::tempdir;
-
-    #[test]
-    fn native_save_failure_uses_the_rendered_project_output() {
-        assert_eq!(
-            resolve_macos_export_destination(Err("NSSavePanel unavailable".to_string())),
-            Some(ExportSaveDestination::Default),
-        );
-    }
-
-    #[test]
-    fn cancelling_a_native_save_dialog_does_not_export() {
-        assert_eq!(resolve_macos_export_destination(Ok(None)), None);
-    }
-
-    #[test]
-    fn native_save_selection_keeps_the_requested_destination() {
-        let path = PathBuf::from("selected.mp4");
-        assert_eq!(
-            resolve_macos_export_destination(Ok(Some(path.clone()))),
-            Some(ExportSaveDestination::Selected(path)),
-        );
-    }
-
-    #[tokio::test]
-    async fn export_preview_reads_saved_caption_choice_after_stale_live_preview_update() {
-        for export_with_subtitles in [false, true] {
-            let dir = tempdir().unwrap();
-            let mut saved = cap_project::ProjectConfiguration {
-                captions: Some(cap_project::CaptionsData {
-                    settings: cap_project::CaptionSettings {
-                        enabled: true,
-                        export_with_subtitles,
-                        ..Default::default()
-                    },
-                    ..Default::default()
-                }),
-                ..Default::default()
-            };
-            saved.write(dir.path()).unwrap();
-            let (sender, receiver) = tokio::sync::watch::channel(saved.clone());
-            saved
-                .captions
-                .as_mut()
-                .unwrap()
-                .settings
-                .export_with_subtitles = !export_with_subtitles;
-            saved.captions.as_mut().unwrap().settings.enabled = false;
-            sender.send(saved).unwrap();
-
-            let preview = load_export_preview_config(dir.path().to_path_buf(), false)
-                .await
-                .unwrap();
-            let settings = preview.captions.unwrap().settings;
-            assert!(settings.enabled);
-            assert_eq!(settings.export_with_subtitles, export_with_subtitles);
-            assert!(
-                !receiver
-                    .borrow()
-                    .captions
-                    .as_ref()
-                    .unwrap()
-                    .settings
-                    .enabled
-            );
-            let persisted = cap_project::ProjectConfiguration::load(dir.path()).unwrap();
-            assert!(persisted.captions.as_ref().unwrap().settings.enabled);
-        }
-    }
-
-    #[tokio::test]
-    async fn export_preview_reports_missing_or_malformed_saved_config() {
-        let dir = tempdir().unwrap();
-        let missing = load_export_preview_config(dir.path().to_path_buf(), false)
-            .await
-            .unwrap_err();
-        assert!(missing.contains("Failed to read saved project config"));
-        std::fs::write(dir.path().join("project-config.json"), "{not valid json").unwrap();
-        let malformed = load_export_preview_config(dir.path().to_path_buf(), false)
-            .await
-            .unwrap_err();
-        assert!(malformed.contains("Failed to read saved project config"));
-    }
-
-    #[tokio::test]
-    async fn saved_export_preview_projects_captions_after_a_cut() {
-        let directory = tempdir().unwrap();
-        let mut meta: RecordingMeta = serde_json::from_value(serde_json::json!({
-            "pretty_name":"preview", "segments":[], "cursors":{}
-        }))
-        .unwrap();
-        meta.project_path = directory.path().to_path_buf();
-        let config: cap_project::ProjectConfiguration = serde_json::from_value(serde_json::json!({
-            "timeline": {
-                "segments":[
-                    {"start":0.0,"end":5.0,"timescale":1.0},
-                    {"start":6.0,"end":10.0,"timescale":1.0}
-                ], "zoomSegments":[]
-            },
-            "captions": {
-                "sourceTimed":true, "settings":{},
-                "segments":[{"id":"word","text":"retained","start":8.0,"end":8.5,"words":[]}]
-            }
-        }))
-        .unwrap();
-        config.write(directory.path()).unwrap();
-        let mut preview = load_export_preview_config(directory.path().to_path_buf(), false)
-            .await
-            .unwrap();
-        synchronize_preview_timing(&meta, &mut preview, &[10.0]);
-        let caption = &preview.timeline.as_ref().unwrap().caption_segments[0];
-        assert_eq!(caption.start, 7.0);
-        assert_eq!(caption.end, 7.5);
-        assert_eq!(caption.text, "retained");
-        let mut cursor_only = load_export_preview_config(directory.path().to_path_buf(), true)
-            .await
-            .unwrap();
-        synchronize_preview_timing(&meta, &mut cursor_only, &[10.0]);
-        assert!(cursor_only.captions.is_none());
-    }
-
-    #[test]
-    fn export_preview_rejects_unloaded_incoming_and_outgoing_media() {
-        let medias = ["first", "second"];
-        assert_eq!(export_preview_media(&medias, 0).unwrap(), &"first");
-        assert_eq!(export_preview_media(&medias, 1).unwrap(), &"second");
-        assert!(export_preview_media(&medias, 2).is_err());
-        assert!(export_preview_media(&medias, u32::MAX).is_err());
-        assert!(export_preview_media::<()>(&[], 0).is_err());
-    }
-
-    #[test]
-    fn export_preview_caption_policy_preserves_editor_and_cursor_only_states() {
-        for enabled in [false, true] {
-            for export in [false, true] {
-                for cursor_only in [false, true] {
-                    let editor = cap_project::ProjectConfiguration {
-                        captions: Some(cap_project::CaptionsData {
-                            settings: cap_project::CaptionSettings {
-                                enabled,
-                                export_with_subtitles: export,
-                                ..Default::default()
-                            },
-                            ..Default::default()
-                        }),
-                        ..Default::default()
-                    };
-                    let original = serde_json::to_value(&editor).unwrap();
-                    let preview = export_project_config(editor.clone(), cursor_only);
-                    if cursor_only {
-                        assert!(preview.captions.is_none());
-                    } else {
-                        assert_eq!(preview.captions.unwrap().settings.enabled, enabled);
-                    }
-                    assert_eq!(serde_json::to_value(editor).unwrap(), original);
-                }
-            }
-        }
-    }
-
-    #[test]
-    fn export_estimates_use_source_duration_without_a_timeline() {
-        assert_eq!(
-            export_estimate_duration(&cap_project::ProjectConfiguration::default(), 361.0),
-            361.0
-        );
-    }
-
-    #[test]
-    fn export_estimates_follow_trims_and_playback_speed() {
-        for (timescale, expected) in [(1.0, 12.0), (2.0, 6.0)] {
-            let project = serde_json::from_value(serde_json::json!({
-                "timeline": {
-                    "segments": [{"start": 45.0, "end": 57.0, "timescale": timescale}],
-                    "zoomSegments": []
-                }
-            }))
-            .unwrap();
-
-            assert_eq!(export_estimate_duration(&project, 361.0), expected);
-        }
-    }
-
-    #[test]
-    fn export_estimates_include_transition_overlap() {
-        let project = serde_json::from_value(serde_json::json!({
-            "timeline": {
-                "segments": [
-                    {"start": 5.0, "end": 11.0, "timescale": 1.0},
-                    {"start": 20.0, "end": 26.0, "timescale": 1.0}
-                ],
-                "transitions": [{"segmentIndex": 1, "type": "cross-fade", "duration": 1.0}],
-                "zoomSegments": []
-            }
-        }))
-        .unwrap();
-
-        assert_eq!(export_estimate_duration(&project, 361.0), 11.0);
-    }
-
-    #[test]
-    fn export_settings_exposes_force_ffmpeg_for_mp4_only() {
-        let mp4_settings = ExportSettings::Mp4(cap_export::mp4::Mp4ExportSettings {
-            fps: 30,
-            resolution_base: XY { x: 1280, y: 720 },
-            compression: cap_export::mp4::ExportCompression::Web,
-            custom_bpp: None,
-            force_ffmpeg_decoder: true,
-            optimize_filesize: false,
-        });
-        let gif_settings = ExportSettings::Gif(cap_export::gif::GifExportSettings {
-            fps: 15,
-            resolution_base: XY { x: 1280, y: 720 },
-            quality: None,
-        });
-
-        assert!(mp4_settings.force_ffmpeg_decoder());
-        assert!(!gif_settings.force_ffmpeg_decoder());
-    }
-
-    #[test]
-    fn frame_decode_error_matcher_includes_initial_frame_timeout() {
-        assert!(is_frame_decode_error(
-            "Export timed out 3 times consecutively after 120s each waiting for frame 0"
-        ));
-    }
-
-    #[cfg(not(target_os = "windows"))]
-    #[test]
-    fn recovered_projects_do_not_force_ffmpeg_without_explicit_setting() {
-        let dir = tempdir().unwrap();
-        std::fs::write(
-            dir.path()
-                .join(crate::recording::FRAGMENTED_EXPORT_FFMPEG_MARKER),
-            b"fragmented-remux",
-        )
-        .unwrap();
-
-        let gif_settings = ExportSettings::Gif(cap_export::gif::GifExportSettings {
-            fps: 15,
-            resolution_base: XY { x: 1280, y: 720 },
-            quality: None,
-        });
-
-        assert!(!should_force_ffmpeg_export(dir.path(), &gif_settings));
-    }
-
-    #[test]
-    fn exports_do_not_force_ffmpeg_without_explicit_setting() {
-        let dir = tempdir().unwrap();
-
-        let gif_settings = ExportSettings::Gif(cap_export::gif::GifExportSettings {
-            fps: 15,
-            resolution_base: XY { x: 1280, y: 720 },
-            quality: None,
-        });
-
-        assert!(!should_force_ffmpeg_export(dir.path(), &gif_settings));
-    }
-
-    #[test]
-    fn export_worker_starts_in_hardware_mode() {
-        assert!(!should_start_export_worker_in_software_safe_mode());
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip_all)]
-pub async fn generate_export_preview_fast(
-    editor: WindowEditorInstance,
-    frame_time: f64,
-    settings: ExportPreviewSettings,
-) -> Result {
-    match AssertUnwindSafe(generate_export_preview_fast_inner(
-        editor, frame_time, settings,
-    ))
-    .catch_unwind()
-    .await
-    {
-        Ok(result) => result,
-        Err(panic) => {
-            let panic_msg = panic_message(panic);
-            error!(
-                target: "cap_desktop_export",
-                panic = %panic_msg,
-                "generate_export_preview_fast panicked"
-            );
-            sentry::capture_message(
-                &format!("Export preview panicked: {panic_msg}"),
-                sentry::Level::Error,
-            );
-            Err("Export preview failed unexpectedly".to_string())
-        }
-    }
-}
-
-async fn load_export_preview_config(
-    project_path: PathBuf,
-    cursor_only: bool,
-) -> Result {
-    tokio::task::spawn_blocking(move || {
-        cap_project::ProjectConfiguration::load(&project_path)
-            .map(|config| export_project_config(config, cursor_only))
-            .map_err(|error| {
-                format!("Failed to read saved project config for export preview: {error}")
-            })
-    })
-    .await
-    .map_err(|error| format!("Failed to load export preview config: {error}"))?
-}
-
-fn synchronize_preview_timing(
-    meta: &RecordingMeta,
-    project: &mut cap_project::ProjectConfiguration,
-    display_durations: &[f64],
-) {
-    cap_project::synchronize_legacy_keyboard(meta, project);
-    cap_project::synchronize_captions(project, display_durations);
-}
-
-fn export_preview_media(medias: &[T], recording_clip: u32) -> Result<&T, String> {
-    medias.get(recording_clip as usize).ok_or_else(|| {
-        format!(
-            "Recording clip {recording_clip} is unavailable in this editor. Reopen the project before exporting."
-        )
-    })
-}
-
-#[instrument(skip_all)]
-async fn generate_export_preview_fast_inner(
-    editor: WindowEditorInstance,
-    frame_time: f64,
-    settings: ExportPreviewSettings,
-) -> Result {
-    if editor.export_active.load(Ordering::Acquire) {
-        return Err("Export is in progress - preview generation skipped".to_string());
-    }
-
-    use base64::{Engine, engine::general_purpose::STANDARD};
-    use std::time::Instant;
-
-    let _preview_guard = ExportPreviewActiveGuard::try_new(&editor.export_preview_active)?;
-
-    crate::gpu_context::ensure_shared_device_available()?;
-
-    let mut project_config =
-        load_export_preview_config(editor.project_path.clone(), settings.cursor_only).await?;
-    let meta = editor.meta().clone();
-    let recordings = editor.recordings.clone();
-    let project_config = tokio::task::spawn_blocking(move || {
-        synchronize_preview_timing(
-            &meta,
-            &mut project_config,
-            &recordings
-                .segments
-                .iter()
-                .map(|segment| segment.display.duration)
-                .collect::>(),
-        );
-        project_config
-    })
-    .await
-    .map_err(|error| format!("Failed to synchronize export preview timing: {error}"))?;
-    let project_config = Arc::new(project_config);
-    let transition_mapping = project_config.timeline.as_ref().and_then(|timeline| {
-        if timeline.transitions.is_empty() {
-            return None;
-        }
-        match timeline.get_frame_mapping(frame_time) {
-            Some(TimelineFrameMapping::Transition {
-                outgoing,
-                kind,
-                progress,
-                ..
-            }) => Some((outgoing, kind, progress)),
-            _ => None,
-        }
-    });
-
-    let Some((segment_time, segment)) = project_config.get_segment_time(frame_time) else {
-        return Err("Frame time is outside video duration".to_string());
-    };
-
-    let segment_media = export_preview_media(&editor.segment_medias, segment.recording_clip)?;
-    let clip_config = project_config
-        .clips
-        .iter()
-        .find(|v| v.index == segment.recording_clip);
-
-    let render_start = Instant::now();
-
-    let segment_frames = segment_media
-        .decoders
-        .get_frames(
-            segment_time as f32,
-            !project_config.camera.hide && !settings.cursor_only,
-            !settings.cursor_only,
-            clip_config.map(|v| v.offsets).unwrap_or_default(),
-        )
-        .await;
-    let segment_frames = segment_frames.ok_or_else(|| "Failed to decode frame".to_string())?;
-
-    let frame_number = (frame_time * settings.fps as f64).floor() as u32;
-    let total_duration = project_config
-        .timeline
-        .as_ref()
-        .map(|t| t.duration())
-        .unwrap_or(0.0);
-
-    let mut zoom_timeline = ZoomTransformTimeline::from_project_for_clip(
-        &project_config,
-        &segment_media.cursor,
-        total_duration,
-        editor.render_constants.options.screen_size,
-        segment.recording_clip,
-    );
-    zoom_timeline.ensure_precomputed_until((frame_number as f32 + 1.0) / settings.fps as f32);
-
-    let uniforms = ProjectUniforms::new(
-        &editor.render_constants,
-        &project_config,
-        frame_number,
-        settings.fps,
-        settings.resolution_base,
-        &segment_media.cursor,
-        &segment_frames,
-        total_duration,
-        &zoom_timeline,
-    );
-
-    crate::gpu_context::ensure_shared_device_available()?;
-    let mut frame_renderer = FrameRenderer::new(&editor.render_constants);
-    let mut layers = RendererLayers::new_with_options(
-        &editor.render_constants.device,
-        &editor.render_constants.queue,
-        editor.render_constants.is_software_adapter,
-    );
-
-    let frame = if let Some((outgoing, kind, progress)) = transition_mapping {
-        let outgoing_media =
-            export_preview_media(&editor.segment_medias, outgoing.segment.recording_clip)?;
-        let outgoing_offsets = project_config
-            .clips
-            .iter()
-            .find(|clip| clip.index == outgoing.segment.recording_clip)
-            .map(|clip| clip.offsets)
-            .unwrap_or_default();
-        let outgoing_frames = outgoing_media
-            .decoders
-            .get_frames(
-                outgoing.source_time as f32,
-                !project_config.camera.hide && !settings.cursor_only,
-                !settings.cursor_only,
-                outgoing_offsets,
-            )
-            .await
-            .ok_or_else(|| "Failed to decode outgoing frame".to_string())?;
-        let mut outgoing_zoom = ZoomTransformTimeline::from_project_for_outgoing_clip(
-            &project_config,
-            &outgoing_media.cursor,
-            total_duration,
-            editor.render_constants.options.screen_size,
-            outgoing.segment.recording_clip,
-        );
-        outgoing_zoom.ensure_precomputed_until((frame_number as f32 + 1.0) / settings.fps as f32);
-        let outgoing_uniforms = ProjectUniforms::new(
-            &editor.render_constants,
-            &project_config,
-            frame_number,
-            settings.fps,
-            settings.resolution_base,
-            &outgoing_media.cursor,
-            &outgoing_frames,
-            total_duration,
-            &outgoing_zoom,
-        );
-        frame_renderer
-            .render_transition_immediate(
-                TransitionRenderInput {
-                    segment_frames: outgoing_frames,
-                    uniforms: outgoing_uniforms,
-                    cursor: &outgoing_media.cursor,
-                    render_display: !settings.cursor_only,
-                },
-                TransitionRenderInput {
-                    segment_frames,
-                    uniforms,
-                    cursor: &segment_media.cursor,
-                    render_display: !settings.cursor_only,
-                },
-                kind,
-                progress as f32,
-                &mut layers,
-            )
-            .await
-    } else {
-        frame_renderer
-            .render_immediate(
-                segment_frames,
-                uniforms,
-                &segment_media.cursor,
-                !settings.cursor_only,
-                &mut layers,
-            )
-            .await
-    }
-    .map_err(|e| format!("Failed to render frame: {e}"))?;
-
-    let frame_render_time_ms = render_start.elapsed().as_secs_f64() * 1000.0;
-
-    let width = frame.width;
-    let height = frame.height;
-
-    let rgb_data: Vec = frame
-        .data
-        .chunks(frame.padded_bytes_per_row as usize)
-        .flat_map(|row| {
-            row[0..(frame.width * 4) as usize]
-                .chunks(4)
-                .flat_map(|chunk| [chunk[0], chunk[1], chunk[2]])
-        })
-        .collect();
-
-    let jpeg_quality = bpp_to_jpeg_quality(settings.compression_bpp);
-    let mut jpeg_buffer = Vec::new();
-    {
-        let mut encoder = JpegEncoder::new_with_quality(&mut jpeg_buffer, jpeg_quality);
-        encoder
-            .encode(&rgb_data, width, height, image::ExtendedColorType::Rgb8)
-            .map_err(|e| format!("Failed to encode JPEG: {e}"))?;
-    }
-
-    let jpeg_base64 = STANDARD.encode(&jpeg_buffer);
-
-    let total_pixels = (settings.resolution_base.x * settings.resolution_base.y) as f64;
-    let fps_f64 = settings.fps as f64;
-
-    let duration_seconds = export_estimate_duration(&project_config, editor.recordings.duration());
-    let total_frames = (duration_seconds * fps_f64).ceil() as u32;
-
-    let estimated_size_mb = if settings.cursor_only {
-        let total_frames_f64 = (duration_seconds * fps_f64).ceil();
-        estimate_cursor_only_size_mb(total_pixels, total_frames_f64)
-    } else {
-        let effective_fps = ((fps_f64 - 30.0).max(0.0) * 0.6) + fps_f64.min(30.0);
-        let video_bitrate = total_pixels * settings.compression_bpp as f64 * effective_fps;
-        let audio_bitrate = 192_000.0;
-        let total_bitrate = video_bitrate + audio_bitrate;
-        let encoder_efficiency = 0.5;
-        (total_bitrate * encoder_efficiency * duration_seconds) / (8.0 * 1024.0 * 1024.0)
-    };
-
-    Ok(ExportPreviewResult {
-        jpeg_base64,
-        estimated_size_mb,
-        actual_width: width,
-        actual_height: height,
-        frame_render_time_ms,
-        total_frames,
-    })
-}
diff --git a/apps/desktop/src-tauri/src/export/estimate_request.rs b/apps/desktop/src-tauri/src/export/estimate_request.rs
deleted file mode 100644
index b8d6d347fdc..00000000000
--- a/apps/desktop/src-tauri/src/export/estimate_request.rs
+++ /dev/null
@@ -1,290 +0,0 @@
-use futures::FutureExt;
-use std::{
-    collections::HashMap,
-    future::Future,
-    panic::AssertUnwindSafe,
-    path::{Path, PathBuf},
-    sync::{
-        Arc, Mutex,
-        atomic::{AtomicBool, Ordering},
-    },
-};
-
-#[derive(Default)]
-pub struct EstimateRequests {
-    cancellations: Mutex>>,
-}
-
-impl EstimateRequests {
-    pub async fn run(
-        &self,
-        path: PathBuf,
-        estimate: impl FnOnce(Arc) -> Fut,
-    ) -> Result
-    where
-        Fut: Future>,
-    {
-        let request = self.start(path)?;
-        let cancel = request.cancellation();
-        request.run(async move { estimate(cancel).await }).await
-    }
-
-    fn start(&self, path: PathBuf) -> Result, String> {
-        let cancel = Arc::new(AtomicBool::new(false));
-        if let Some(previous) = self
-            .cancellations
-            .lock()
-            .map_err(|error| error.to_string())?
-            .insert(path.clone(), cancel.clone())
-        {
-            previous.store(true, Ordering::Release);
-        }
-        Ok(EstimateRequest {
-            requests: self,
-            path,
-            cancel,
-        })
-    }
-
-    pub fn cancel(&self, path: &Path) {
-        if let Ok(cancellations) = self.cancellations.lock()
-            && let Some(cancel) = cancellations.get(path)
-        {
-            cancel.store(true, Ordering::Release);
-        }
-    }
-}
-
-struct EstimateRequest<'a> {
-    requests: &'a EstimateRequests,
-    path: PathBuf,
-    cancel: Arc,
-}
-
-impl EstimateRequest<'_> {
-    fn cancellation(&self) -> Arc {
-        self.cancel.clone()
-    }
-
-    async fn run(self, future: impl Future>) -> Result {
-        match AssertUnwindSafe(future).catch_unwind().await {
-            Ok(result) => result,
-            Err(_) => {
-                tracing::error!(target: "cap_desktop_export", "Export estimate panicked");
-                Err("Export estimate failed unexpectedly".to_string())
-            }
-        }
-    }
-}
-
-impl Drop for EstimateRequest<'_> {
-    fn drop(&mut self) {
-        self.cancel.store(true, Ordering::Release);
-        if let Ok(mut cancellations) = self.requests.cancellations.lock()
-            && cancellations
-                .get(&self.path)
-                .is_some_and(|current| Arc::ptr_eq(current, &self.cancel))
-        {
-            let _ = cancellations.remove(&self.path);
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use futures::{executor::block_on, future};
-    use std::task::Poll;
-
-    struct DropSignal(Arc);
-
-    impl Drop for DropSignal {
-        fn drop(&mut self) {
-            self.0.store(true, Ordering::Release);
-        }
-    }
-
-    #[test]
-    fn successful_request_returns_estimate_and_cleans_up() {
-        let requests = EstimateRequests::default();
-        let request = requests.start("example.cap".into()).unwrap();
-        let cancel = request.cancellation();
-        let result = block_on(request.run(async { Ok(42) }));
-        assert_eq!(result, Ok(42));
-        assert!(cancel.load(Ordering::Acquire));
-        assert!(requests.cancellations.lock().unwrap().is_empty());
-    }
-
-    #[test]
-    fn ordinary_error_is_preserved_and_cleans_up() {
-        let requests = EstimateRequests::default();
-        let request = requests.start("example.cap".into()).unwrap();
-        let result = block_on(request.run(async { Err::<(), _>("Invalid resolution".into()) }));
-        assert_eq!(result, Err("Invalid resolution".into()));
-        assert!(requests.cancellations.lock().unwrap().is_empty());
-    }
-
-    #[test]
-    fn polling_panic_returns_safe_error_and_drops_sample_resources() {
-        let requests = EstimateRequests::default();
-        let request = requests.start("example.cap".into()).unwrap();
-        let cancel = request.cancellation();
-        let dropped = Arc::new(AtomicBool::new(false));
-        let signal = dropped.clone();
-        let result = block_on(request.run(async move {
-            let _sample = DropSignal(signal);
-            let mut yielded = false;
-            future::poll_fn(|cx| {
-                if yielded {
-                    Poll::Ready(())
-                } else {
-                    yielded = true;
-                    cx.waker().wake_by_ref();
-                    Poll::Pending
-                }
-            })
-            .await;
-            future::poll_fn(|_| -> Poll> {
-                panic!("synthetic pipeline validation failure with private details")
-            })
-            .await
-        }));
-        assert_eq!(result, Err("Export estimate failed unexpectedly".into()));
-        assert!(dropped.load(Ordering::Acquire));
-        assert!(cancel.load(Ordering::Acquire));
-        assert!(requests.cancellations.lock().unwrap().is_empty());
-    }
-
-    #[test]
-    fn dropping_pending_request_cancels_and_cleans_up() {
-        let requests = EstimateRequests::default();
-        let request = requests.start("example.cap".into()).unwrap();
-        let cancel = request.cancellation();
-        let mut running = Box::pin(request.run(future::pending::>()));
-        assert!(running.as_mut().now_or_never().is_none());
-        assert!(!cancel.load(Ordering::Acquire));
-        drop(running);
-        assert!(cancel.load(Ordering::Acquire));
-        assert!(requests.cancellations.lock().unwrap().is_empty());
-    }
-
-    #[test]
-    fn superseded_request_cannot_remove_replacement() {
-        let requests = EstimateRequests::default();
-        let path = PathBuf::from("example.cap");
-        let first = requests.start(path.clone()).unwrap();
-        let first_cancel = first.cancellation();
-        let second = requests.start(path.clone()).unwrap();
-        let second_cancel = second.cancellation();
-        assert!(first_cancel.load(Ordering::Acquire));
-        assert_eq!(block_on(first.run(async { Ok(()) })), Ok(()));
-        assert!(!second_cancel.load(Ordering::Acquire));
-        assert!(Arc::ptr_eq(
-            requests.cancellations.lock().unwrap().get(&path).unwrap(),
-            &second_cancel,
-        ));
-        requests.cancel(&path);
-        assert!(second_cancel.load(Ordering::Acquire));
-        drop(second);
-        assert!(requests.cancellations.lock().unwrap().is_empty());
-    }
-
-    #[test]
-    fn panicking_request_cannot_remove_replacement() {
-        let requests = EstimateRequests::default();
-        let path = PathBuf::from("example.cap");
-        let first = requests.start(path.clone()).unwrap();
-        let second = requests.start(path.clone()).unwrap();
-        let second_cancel = second.cancellation();
-        let result = block_on(first.run(future::poll_fn(|_| -> Poll> {
-            panic!("synthetic failure")
-        })));
-        assert!(result.is_err());
-        assert!(Arc::ptr_eq(
-            requests.cancellations.lock().unwrap().get(&path).unwrap(),
-            &second_cancel,
-        ));
-        assert!(!second_cancel.load(Ordering::Acquire));
-        requests.cancel(&path);
-        assert!(second_cancel.load(Ordering::Acquire));
-    }
-
-    #[test]
-    fn dropping_unpolled_request_cleans_up_registration() {
-        let requests = EstimateRequests::default();
-        let request = requests.start("example.cap".into()).unwrap();
-        let cancel = request.cancellation();
-        drop(request.run(future::pending::>()));
-        assert!(cancel.load(Ordering::Acquire));
-        assert!(requests.cancellations.lock().unwrap().is_empty());
-    }
-
-    #[test]
-    fn cancellation_is_scoped_to_the_requested_project() {
-        let requests = EstimateRequests::default();
-        let first = requests.start("first.cap".into()).unwrap();
-        let second = requests.start("second.cap".into()).unwrap();
-        requests.cancel(Path::new("first.cap"));
-        assert!(first.cancellation().load(Ordering::Acquire));
-        assert!(!second.cancellation().load(Ordering::Acquire));
-    }
-
-    #[test]
-    fn run_passes_the_registered_cancellation_to_the_estimate() {
-        let requests = EstimateRequests::default();
-        let path = PathBuf::from("example.cap");
-        let result = block_on(requests.run(path.clone(), |cancel| {
-            let requests = &requests;
-            let path = path.clone();
-            async move {
-                assert!(!cancel.load(Ordering::Acquire));
-                requests.cancel(&path);
-                Ok(cancel.load(Ordering::Acquire))
-            }
-        }));
-        assert_eq!(result, Ok(true));
-        assert!(requests.cancellations.lock().unwrap().is_empty());
-    }
-
-    #[test]
-    fn run_settles_a_panicking_estimate_and_cleans_up() {
-        let requests = EstimateRequests::default();
-        let observed = Arc::new(Mutex::new(None));
-        let seen = observed.clone();
-        let result = block_on(requests.run("example.cap".into(), |cancel| {
-            *seen.lock().unwrap() = Some(cancel);
-            future::poll_fn(|_| -> Poll> {
-                panic!("synthetic rendering failure")
-            })
-        }));
-        assert_eq!(result, Err("Export estimate failed unexpectedly".into()));
-        let cancel = observed.lock().unwrap().take().unwrap();
-        assert!(cancel.load(Ordering::Acquire));
-        assert!(requests.cancellations.lock().unwrap().is_empty());
-    }
-
-    #[test]
-    fn run_settles_a_panic_while_building_the_estimate() {
-        let requests = EstimateRequests::default();
-        let result = block_on(requests.run(
-            "example.cap".into(),
-            |_| -> future::Ready> { panic!("synthetic setup failure") },
-        ));
-        assert_eq!(result, Err("Export estimate failed unexpectedly".into()));
-        assert!(requests.cancellations.lock().unwrap().is_empty());
-    }
-
-    #[test]
-    fn new_request_can_succeed_after_a_panic() {
-        let requests = EstimateRequests::default();
-        let first = requests.start("example.cap".into()).unwrap();
-        let result = block_on(first.run(future::poll_fn(|_| -> Poll> {
-            panic!("synthetic failure")
-        })));
-        assert!(result.is_err());
-        let second = requests.start("example.cap".into()).unwrap();
-        assert!(!second.cancellation().load(Ordering::Acquire));
-        assert_eq!(block_on(second.run(async { Ok(42) })), Ok(42));
-        assert!(requests.cancellations.lock().unwrap().is_empty());
-    }
-}
diff --git a/apps/desktop/src-tauri/src/fake_window.rs b/apps/desktop/src-tauri/src/fake_window.rs
deleted file mode 100644
index 1b6d6302afe..00000000000
--- a/apps/desktop/src-tauri/src/fake_window.rs
+++ /dev/null
@@ -1,962 +0,0 @@
-use cap_recording::sources::screen_capture::ScreenCaptureTarget;
-use scap_targets::{Display, DisplayId, Window as ScapWindow, bounds::LogicalBounds};
-use std::{
-    collections::HashMap,
-    sync::{
-        Arc, Mutex,
-        atomic::{AtomicU64, Ordering},
-    },
-    time::Duration,
-};
-use tauri::{AppHandle, Manager, WebviewWindow};
-use tokio::{sync::RwLock, time::sleep};
-use tokio_util::sync::CancellationToken;
-use tracing::{debug, instrument};
-
-use crate::{App, ArcLock, RecordingState};
-
-const RECORDING_CONTROLS_LABEL: &str = "in-progress-recording";
-#[cfg(any(target_os = "macos", test))]
-const RECORDING_CONTROLS_BOUNDS_NAME: &str = "recording-controls-interactive-area";
-const RECORDING_CONTROLS_WIDTH: f64 = 320.0;
-const RECORDING_CONTROLS_HEIGHT: f64 = 150.0;
-const RECORDING_CONTROLS_BAR_HEIGHT: f64 = 40.0;
-const RECORDING_CONTROLS_BOTTOM_PADDING: f64 = 12.0;
-const RECORDING_CONTROLS_OFFSET_Y: f64 = 120.0;
-const TICK_INTERVAL: Duration = Duration::from_millis(50);
-const DEAD_WINDOW_ERROR_THRESHOLD: u8 = 5;
-const HIT_TEST_PADDING_PHYSICAL: f64 = 2.0;
-const RECORDING_CONTROLS_FALLBACK_PADDING_LOGICAL: f64 = 48.0;
-const MAX_INTERACTIVE_BOUNDS_WIDTH: f64 = 360.0;
-const MAX_INTERACTIVE_BOUNDS_HEIGHT: f64 = 220.0;
-
-pub struct FakeWindowBounds(pub Arc>>>);
-
-struct TokenEntry {
-    id: u64,
-    token: CancellationToken,
-}
-
-#[derive(Default)]
-pub struct FakeWindowListeners {
-    tokens: Mutex>,
-    next_id: AtomicU64,
-}
-
-impl FakeWindowListeners {
-    fn register(&self, label: String) -> (u64, CancellationToken) {
-        let id = self.next_id.fetch_add(1, Ordering::Relaxed);
-        let token = CancellationToken::new();
-        let mut guard = self.tokens.lock().unwrap_or_else(|e| e.into_inner());
-        if let Some(previous) = guard.insert(
-            label,
-            TokenEntry {
-                id,
-                token: token.clone(),
-            },
-        ) {
-            previous.token.cancel();
-        }
-        (id, token)
-    }
-
-    fn finish(&self, label: &str, id: u64) -> bool {
-        let mut guard = self.tokens.lock().unwrap_or_else(|e| e.into_inner());
-        if let Some(current) = guard.get(label)
-            && current.id == id
-        {
-            guard.remove(label);
-            return true;
-        }
-        false
-    }
-
-    pub fn cancel(&self, label: &str) {
-        let guard = self.tokens.lock().unwrap_or_else(|e| e.into_inner());
-        if let Some(entry) = guard.get(label) {
-            entry.token.cancel();
-        }
-    }
-
-    pub fn cancel_all(&self) {
-        let guard = self.tokens.lock().unwrap_or_else(|e| e.into_inner());
-        for entry in guard.values() {
-            entry.token.cancel();
-        }
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(state))]
-pub async fn set_fake_window_bounds(
-    window: tauri::Window,
-    name: String,
-    bounds: LogicalBounds,
-    state: tauri::State<'_, FakeWindowBounds>,
-) -> Result<(), String> {
-    let mut state = state.0.write().await;
-    let map = state.entry(window.label().to_string()).or_default();
-
-    map.insert(name, bounds);
-
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(state, window))]
-pub async fn remove_fake_window(
-    window: tauri::Window,
-    name: String,
-    state: tauri::State<'_, FakeWindowBounds>,
-) -> Result<(), String> {
-    let mut state = state.0.write().await;
-    let Some(map) = state.get_mut(window.label()) else {
-        return Ok(());
-    };
-
-    map.remove(&name);
-
-    if map.is_empty() {
-        state.remove(window.label());
-    }
-
-    Ok(())
-}
-
-fn should_ignore_cursor_events(
-    window_position: tauri::PhysicalPosition,
-    mouse_position: tauri::PhysicalPosition,
-    scale_factor: f64,
-    windows: &HashMap,
-    default_ignore: bool,
-    allow_default_interaction: bool,
-) -> bool {
-    let mut saw_bounds = false;
-
-    for bounds in windows.values() {
-        let width = bounds.size().width();
-        let height = bounds.size().height();
-        if width <= 0.0
-            || height <= 0.0
-            || width > MAX_INTERACTIVE_BOUNDS_WIDTH
-            || height > MAX_INTERACTIVE_BOUNDS_HEIGHT
-        {
-            continue;
-        }
-
-        saw_bounds = true;
-        let x_min = (window_position.x as f64) + bounds.position().x() * scale_factor
-            - HIT_TEST_PADDING_PHYSICAL;
-        let x_max = (window_position.x as f64)
-            + (bounds.position().x() + bounds.size().width()) * scale_factor
-            + HIT_TEST_PADDING_PHYSICAL;
-        let y_min = (window_position.y as f64) + bounds.position().y() * scale_factor
-            - HIT_TEST_PADDING_PHYSICAL;
-        let y_max = (window_position.y as f64)
-            + (bounds.position().y() + bounds.size().height()) * scale_factor
-            + HIT_TEST_PADDING_PHYSICAL;
-
-        if mouse_position.x >= x_min
-            && mouse_position.x <= x_max
-            && mouse_position.y >= y_min
-            && mouse_position.y <= y_max
-        {
-            return false;
-        }
-    }
-
-    if saw_bounds {
-        return true;
-    }
-
-    default_ignore || !allow_default_interaction
-}
-
-#[cfg(any(target_os = "macos", test))]
-fn macos_cursor_in_window_scale(
-    cursor: tauri::PhysicalPosition,
-    primary_scale: f64,
-    window_scale: f64,
-) -> Option> {
-    if !primary_scale.is_finite()
-        || primary_scale <= 0.0
-        || !window_scale.is_finite()
-        || window_scale <= 0.0
-        || !cursor.x.is_finite()
-        || !cursor.y.is_finite()
-    {
-        return None;
-    }
-    // Tao scales global mouse coordinates by the primary display, but window
-    // positions and DOM bounds use the window's display scale.
-    let factor = window_scale / primary_scale;
-    Some(tauri::PhysicalPosition::new(
-        cursor.x * factor,
-        cursor.y * factor,
-    ))
-}
-
-fn recording_controls_size_allows_default_interaction(
-    window_size: tauri::PhysicalSize,
-    scale_factor: f64,
-) -> bool {
-    let scale_factor = scale_factor.max(1.0);
-    let max_width =
-        (RECORDING_CONTROLS_WIDTH + RECORDING_CONTROLS_FALLBACK_PADDING_LOGICAL) * scale_factor;
-    let max_height =
-        (RECORDING_CONTROLS_HEIGHT + RECORDING_CONTROLS_FALLBACK_PADDING_LOGICAL) * scale_factor;
-
-    (window_size.width as f64) <= max_width && (window_size.height as f64) <= max_height
-}
-
-fn prepare_recording_controls_default_interaction(window: &WebviewWindow) -> bool {
-    let (Ok(window_size), Ok(scale_factor)) = (window.outer_size(), window.scale_factor()) else {
-        let _ = window.set_ignore_cursor_events(true);
-        return false;
-    };
-
-    if recording_controls_size_allows_default_interaction(window_size, scale_factor) {
-        return true;
-    }
-
-    if window.set_ignore_cursor_events(true).is_err() {
-        let _ = window.hide();
-        return false;
-    }
-
-    let _ = window.set_size(tauri::LogicalSize::new(
-        RECORDING_CONTROLS_WIDTH,
-        RECORDING_CONTROLS_HEIGHT,
-    ));
-
-    false
-}
-
-fn spawn_recording_controls_sanity_checks(app: AppHandle, window: WebviewWindow) {
-    let label = window.label().to_string();
-
-    tokio::spawn(async move {
-        for delay in [
-            Duration::from_millis(250),
-            Duration::from_secs(2),
-            Duration::from_secs(5),
-        ] {
-            sleep(delay).await;
-
-            if crate::app_is_exiting(&app) {
-                break;
-            }
-
-            if crate::power_observer::is_system_asleep() {
-                continue;
-            }
-
-            let Some(window) = app.get_webview_window(&label) else {
-                break;
-            };
-
-            let ignore = !prepare_recording_controls_default_interaction(&window);
-            let _ = window.set_ignore_cursor_events(ignore);
-        }
-    });
-}
-
-#[cfg(any(target_os = "macos", test))]
-fn ensure_recording_controls_bounds(
-    bounds: &mut HashMap,
-    width: f64,
-    height: f64,
-) {
-    bounds
-        .entry(RECORDING_CONTROLS_BOUNDS_NAME.to_string())
-        .or_insert_with(|| {
-            LogicalBounds::new(
-                scap_targets::bounds::LogicalPosition::new(
-                    RECORDING_CONTROLS_BOTTOM_PADDING,
-                    height - RECORDING_CONTROLS_BOTTOM_PADDING - RECORDING_CONTROLS_BAR_HEIGHT,
-                ),
-                scap_targets::bounds::LogicalSize::new(
-                    width - RECORDING_CONTROLS_BOTTOM_PADDING * 2.0,
-                    RECORDING_CONTROLS_BAR_HEIGHT,
-                ),
-            )
-        });
-}
-
-#[cfg(any(target_os = "macos", test))]
-fn preserve_pointer_gesture(ignore: bool, pressed: bool, was_ignoring: bool) -> bool {
-    ignore && (!pressed || was_ignoring)
-}
-
-#[cfg(target_os = "macos")]
-async fn update_recording_controls_hit_test(
-    window: &WebviewWindow,
-    mut bounds: HashMap,
-    token: CancellationToken,
-) -> Option {
-    use objc2_app_kit::{NSEvent, NSWindow};
-    use objc2_foundation::NSSize;
-
-    let (tx, rx) = tokio::sync::oneshot::channel();
-    let handle = window.clone();
-    window
-        .run_on_main_thread(move || {
-            if tx.is_closed() || token.is_cancelled() {
-                return;
-            }
-            let result = objc2::rc::autoreleasepool(|_| {
-                let ptr = handle.ns_window().ok()? as *const NSWindow;
-                let native = unsafe { ptr.as_ref()? };
-                let view = native.contentView()?;
-                let frame = native.frame();
-                let scale = native.backingScaleFactor();
-                let small = recording_controls_size_allows_default_interaction(
-                    tauri::LogicalSize::new(frame.size.width, frame.size.height).to_physical(scale),
-                    scale,
-                );
-                let pressed = unsafe { NSEvent::pressedMouseButtons() } & 1 != 0;
-                if !small {
-                    native.setIgnoresMouseEvents(true);
-                    native.setContentSize(NSSize::new(
-                        RECORDING_CONTROLS_WIDTH,
-                        RECORDING_CONTROLS_HEIGHT,
-                    ));
-                    return Some(pressed);
-                }
-                let point = view.convertPoint_fromView(
-                    unsafe { native.mouseLocationOutsideOfEventStream() },
-                    None,
-                );
-                let view_bounds = view.bounds();
-                ensure_recording_controls_bounds(
-                    &mut bounds,
-                    view_bounds.size.width,
-                    view_bounds.size.height,
-                );
-                let y = if view.isFlipped() {
-                    point.y - view_bounds.origin.y
-                } else {
-                    view_bounds.origin.y + view_bounds.size.height - point.y
-                };
-                let ignore = should_ignore_cursor_events(
-                    tauri::PhysicalPosition::new(0, 0),
-                    tauri::PhysicalPosition::new(
-                        (point.x - view_bounds.origin.x) * scale,
-                        y * scale,
-                    ),
-                    scale,
-                    &bounds,
-                    false,
-                    true,
-                );
-                // Keep the mouse-up routed to this panel when a drag crosses its hit area.
-                let ignore = preserve_pointer_gesture(ignore, pressed, unsafe {
-                    native.ignoresMouseEvents()
-                });
-                if unsafe { native.ignoresMouseEvents() } != ignore {
-                    native.setIgnoresMouseEvents(ignore);
-                    debug!(
-                        ignore,
-                        pressed,
-                        bounds = bounds.len(),
-                        "Recording controls hit test changed"
-                    );
-                }
-                Some(pressed)
-            });
-            let _ = tx.send(result);
-        })
-        .ok()?;
-    tokio::time::timeout(Duration::from_millis(250), rx)
-        .await
-        .ok()?
-        .ok()?
-}
-
-fn get_display_id_for_cursor() -> Option {
-    Display::get_containing_cursor().map(|d| d.id())
-}
-
-fn get_display_by_id(id: &DisplayId) -> Option {
-    Display::list().into_iter().find(|d| &d.id() == id)
-}
-
-fn calculate_bottom_center_position(display: &Display) -> Option<(f64, f64)> {
-    let bounds = display.raw_handle().logical_bounds()?;
-    let x = bounds.position().x();
-    let y = bounds.position().y();
-    let width = bounds.size().width();
-    let height = bounds.size().height();
-
-    let pos_x = x + (width - RECORDING_CONTROLS_WIDTH) / 2.0;
-    let pos_y = y + height - RECORDING_CONTROLS_HEIGHT - RECORDING_CONTROLS_OFFSET_Y;
-    Some((pos_x, pos_y))
-}
-
-const TARGET_CONTROLS_OFFSET_Y: f64 = 48.0;
-const AREA_CONTROLS_MARGIN: f64 = 16.0;
-
-fn calculate_area_recording_controls_position(
-    display_bounds: LogicalBounds,
-    area_bounds: LogicalBounds,
-) -> (f64, f64) {
-    let display_left = display_bounds.position().x();
-    let display_top = display_bounds.position().y();
-    let display_right = display_left + display_bounds.size().width();
-    let display_bottom = display_top + display_bounds.size().height();
-    let area_left = display_left + area_bounds.position().x();
-    let area_top = display_top + area_bounds.position().y();
-    let area_bottom = area_top + area_bounds.size().height();
-
-    let max_x = (display_right - RECORDING_CONTROLS_WIDTH).max(display_left);
-    let pos_x = (area_left + (area_bounds.size().width() - RECORDING_CONTROLS_WIDTH) / 2.0)
-        .clamp(display_left, max_x);
-    let bar_top_offset = RECORDING_CONTROLS_HEIGHT
-        - RECORDING_CONTROLS_BOTTOM_PADDING
-        - RECORDING_CONTROLS_BAR_HEIGHT;
-    let bar_bottom_offset = RECORDING_CONTROLS_HEIGHT - RECORDING_CONTROLS_BOTTOM_PADDING;
-
-    let below_y = area_bottom + AREA_CONTROLS_MARGIN - bar_top_offset;
-    if below_y >= display_top && below_y + RECORDING_CONTROLS_HEIGHT <= display_bottom {
-        return (pos_x, below_y);
-    }
-
-    let above_y = area_top - AREA_CONTROLS_MARGIN - bar_bottom_offset;
-    if above_y >= display_top && above_y + RECORDING_CONTROLS_HEIGHT <= display_bottom {
-        return (pos_x, above_y);
-    }
-
-    let max_y = (display_bottom - RECORDING_CONTROLS_HEIGHT).max(display_top);
-    let fallback_y = (area_bottom - RECORDING_CONTROLS_HEIGHT - TARGET_CONTROLS_OFFSET_Y)
-        .clamp(display_top, max_y);
-    (pos_x, fallback_y)
-}
-
-pub fn calculate_recording_controls_position_for_target(
-    capture_target: &ScreenCaptureTarget,
-) -> Option<(f64, f64)> {
-    match capture_target {
-        ScreenCaptureTarget::Window { id } => {
-            let window = ScapWindow::from_id(id)?;
-            let bounds = window.raw_handle().logical_bounds()?;
-            let pos_x =
-                bounds.position().x() + (bounds.size().width() - RECORDING_CONTROLS_WIDTH) / 2.0;
-            let pos_y = bounds.position().y() + bounds.size().height()
-                - RECORDING_CONTROLS_HEIGHT
-                - TARGET_CONTROLS_OFFSET_Y;
-            Some((pos_x, pos_y))
-        }
-        ScreenCaptureTarget::Area { screen, bounds } => {
-            let display = Display::from_id(screen)?;
-            let display_bounds = display.raw_handle().logical_bounds()?;
-            Some(calculate_area_recording_controls_position(
-                display_bounds,
-                *bounds,
-            ))
-        }
-        _ => None,
-    }
-}
-
-pub fn spawn_fake_window_listener(app: AppHandle, window: WebviewWindow) {
-    let label = window.label().to_string();
-    let is_recording_controls = label == RECORDING_CONTROLS_LABEL;
-    let default_ignore = !is_recording_controls;
-    let initial_ignore = if is_recording_controls {
-        !prepare_recording_controls_default_interaction(&window)
-    } else {
-        default_ignore
-    };
-    window.set_ignore_cursor_events(initial_ignore).ok();
-    let listeners = app.state::();
-    let (listener_id, token) = listeners.register(label.clone());
-
-    if is_recording_controls {
-        spawn_recording_controls_sanity_checks(app.clone(), window.clone());
-    }
-
-    tokio::spawn(async move {
-        let listeners = app.state::();
-        let state = app.state::();
-        let mut current_display_id: Option = get_display_id_for_cursor();
-        let mut last_target_pos: Option<(f64, f64)> = None;
-        let mut consecutive_errors: u8 = 0;
-
-        loop {
-            tokio::select! {
-                biased;
-                _ = token.cancelled() => {
-                    debug!(window = %label, "Fake window listener cancelled");
-                    break;
-                }
-                _ = sleep(TICK_INTERVAL) => {}
-            }
-
-            if crate::app_is_exiting(&app) {
-                break;
-            }
-
-            if crate::power_observer::is_system_asleep() {
-                continue;
-            }
-
-            if !app.webview_windows().contains_key(&label) {
-                debug!(window = %label, "Fake window listener stopping: window no longer exists");
-                break;
-            }
-
-            #[cfg(target_os = "macos")]
-            let controls_pressed = if is_recording_controls {
-                let bounds = state
-                    .0
-                    .read()
-                    .await
-                    .get(&label)
-                    .cloned()
-                    .unwrap_or_default();
-                match update_recording_controls_hit_test(&window, bounds, token.clone()).await {
-                    Some(pressed) => pressed,
-                    None => continue,
-                }
-            } else {
-                false
-            };
-            #[cfg(not(target_os = "macos"))]
-            let controls_pressed = false;
-
-            if is_recording_controls && !controls_pressed {
-                let capture_target = app.state::>().try_read().ok().and_then(|s| {
-                    match &s.recording_state {
-                        RecordingState::Pending { target, .. } => Some(target.clone()),
-                        RecordingState::Active(inner) => Some(inner.capture_target().clone()),
-                        RecordingState::None => None,
-                    }
-                });
-
-                let mut handled = false;
-
-                if let Some(ref target) = capture_target {
-                    match target {
-                        ScreenCaptureTarget::Window { .. } => {
-                            if let Some((px, py)) =
-                                calculate_recording_controls_position_for_target(target)
-                            {
-                                let changed = match last_target_pos {
-                                    Some((lx, ly)) => {
-                                        (px - lx).abs() > 0.5 || (py - ly).abs() > 0.5
-                                    }
-                                    None => true,
-                                };
-                                if changed {
-                                    let _ = window.set_position(
-                                        crate::windows::logical_point_position(px, py),
-                                    );
-                                    last_target_pos = Some((px, py));
-                                }
-                                handled = true;
-                            }
-                        }
-                        ScreenCaptureTarget::Area { .. } => {
-                            handled = true;
-                        }
-                        _ => {}
-                    }
-                }
-
-                if !handled && let Some(cursor_display_id) = get_display_id_for_cursor() {
-                    let display_changed = current_display_id.as_ref() != Some(&cursor_display_id);
-
-                    if display_changed
-                        && let Some(display) = get_display_by_id(&cursor_display_id)
-                        && let Some((pos_x, pos_y)) = calculate_bottom_center_position(&display)
-                    {
-                        let _ = window
-                            .set_position(crate::windows::logical_point_position(pos_x, pos_y));
-                        current_display_id = Some(cursor_display_id);
-                    }
-                }
-            }
-
-            #[cfg(target_os = "macos")]
-            if is_recording_controls {
-                continue;
-            }
-
-            let windows = state.0.read().await.get(&label).cloned();
-
-            let Some(windows) = windows else {
-                let ignore = if is_recording_controls {
-                    !prepare_recording_controls_default_interaction(&window)
-                } else {
-                    default_ignore
-                };
-                if window.set_ignore_cursor_events(ignore).is_err() {
-                    consecutive_errors = consecutive_errors.saturating_add(1);
-                    if consecutive_errors >= DEAD_WINDOW_ERROR_THRESHOLD {
-                        debug!(
-                            window = %label,
-                            "Fake window listener stopping: window handle is no longer responsive"
-                        );
-                        break;
-                    }
-                } else {
-                    consecutive_errors = 0;
-                }
-                continue;
-            };
-
-            let (Ok(window_position), Ok(mouse_position), Ok(scale_factor)) = (
-                window.outer_position(),
-                window.cursor_position(),
-                window.scale_factor(),
-            ) else {
-                consecutive_errors = consecutive_errors.saturating_add(1);
-                if consecutive_errors >= DEAD_WINDOW_ERROR_THRESHOLD {
-                    debug!(
-                        window = %label,
-                        "Fake window listener stopping: repeated failures querying window state"
-                    );
-                    break;
-                }
-                let ignore = if is_recording_controls {
-                    !prepare_recording_controls_default_interaction(&window)
-                } else {
-                    default_ignore
-                };
-                let _ = window.set_ignore_cursor_events(ignore);
-                continue;
-            };
-
-            consecutive_errors = 0;
-            #[cfg(target_os = "macos")]
-            let mouse_position = match objc2::rc::autoreleasepool(|_| {
-                window.primary_monitor().ok().flatten().and_then(|monitor| {
-                    macos_cursor_in_window_scale(
-                        mouse_position,
-                        monitor.scale_factor(),
-                        scale_factor,
-                    )
-                })
-            }) {
-                Some(position) => position,
-                None => {
-                    let ignore = !is_recording_controls
-                        || !prepare_recording_controls_default_interaction(&window);
-                    let _ = window.set_ignore_cursor_events(ignore);
-                    continue;
-                }
-            };
-            let allow_default_interaction = if is_recording_controls {
-                prepare_recording_controls_default_interaction(&window)
-            } else {
-                false
-            };
-
-            let ignore = should_ignore_cursor_events(
-                window_position,
-                mouse_position,
-                scale_factor,
-                &windows,
-                default_ignore,
-                allow_default_interaction,
-            );
-
-            window.set_ignore_cursor_events(ignore).ok();
-
-            let focused = window.is_focused().unwrap_or(false);
-            if !ignore {
-                if !focused {
-                    window.set_focus().ok();
-                }
-            } else if focused {
-                window.set_ignore_cursor_events(ignore).ok();
-            }
-        }
-
-        let mut map = state.0.write().await;
-        if listeners.finish(&label, listener_id) && !app.webview_windows().contains_key(&label) {
-            map.remove(&label);
-        }
-    });
-}
-
-pub fn cancel_fake_window_listener(app: &AppHandle, label: &str) {
-    if let Some(listeners) = app.try_state::() {
-        listeners.cancel(label);
-    }
-}
-
-pub fn cancel_all_fake_window_listeners(app: &AppHandle) {
-    if let Some(listeners) = app.try_state::() {
-        listeners.cancel_all();
-    }
-}
-
-pub fn init(app: &AppHandle) {
-    app.manage(FakeWindowBounds(Default::default()));
-    app.manage(FakeWindowListeners::default());
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use scap_targets::bounds::{LogicalPosition, LogicalSize};
-
-    #[test]
-    fn tooltip_only_bounds_do_not_disable_the_recording_bar() {
-        let mut registered = HashMap::from([("tooltip".into(), bounds(30.0, 60.0, 80.0, 24.0))]);
-        ensure_recording_controls_bounds(&mut registered, 320.0, 150.0);
-        for (x, y, ignore) in [(24.0, 110.0, false), (40.0, 70.0, false), (4.0, 30.0, true)] {
-            assert_eq!(
-                should_ignore_cursor_events(
-                    tauri::PhysicalPosition::new(0, 0),
-                    tauri::PhysicalPosition::new(x, y),
-                    1.0,
-                    ®istered,
-                    false,
-                    true,
-                ),
-                ignore,
-            );
-        }
-    }
-
-    #[test]
-    fn registered_issue_panel_bounds_are_preserved() {
-        let issue = bounds(12.0, 40.0, 296.0, 98.0);
-        let mut registered = HashMap::from([(RECORDING_CONTROLS_BOUNDS_NAME.into(), issue)]);
-        ensure_recording_controls_bounds(&mut registered, 320.0, 150.0);
-        let actual = registered[RECORDING_CONTROLS_BOUNDS_NAME];
-        assert_eq!(actual.position().x(), issue.position().x());
-        assert_eq!(actual.position().y(), issue.position().y());
-        assert_eq!(actual.size().width(), issue.size().width());
-        assert_eq!(actual.size().height(), issue.size().height());
-    }
-
-    #[test]
-    fn replaced_listener_cannot_finish_the_current_listener() {
-        let listeners = FakeWindowListeners::default();
-        let (old, old_token) = listeners.register("controls".into());
-        let (current, current_token) = listeners.register("controls".into());
-        assert!(old_token.is_cancelled());
-        assert!(!listeners.finish("controls", old));
-        assert!(!current_token.is_cancelled());
-        assert!(listeners.finish("controls", current));
-    }
-
-    #[test]
-    fn cancelled_listener_retains_ownership_until_cleanup() {
-        let listeners = FakeWindowListeners::default();
-        let (id, token) = listeners.register("controls".into());
-        listeners.cancel("controls");
-        assert!(token.is_cancelled());
-        assert!(listeners.finish("controls", id));
-    }
-
-    #[test]
-    fn pointer_gesture_remains_interactive_until_release() {
-        assert!(!preserve_pointer_gesture(true, true, false));
-        assert!(preserve_pointer_gesture(true, false, false));
-        assert!(preserve_pointer_gesture(true, true, true));
-        assert!(!preserve_pointer_gesture(false, true, true));
-    }
-
-    fn bounds(x: f64, y: f64, width: f64, height: f64) -> LogicalBounds {
-        LogicalBounds::new(LogicalPosition::new(x, y), LogicalSize::new(width, height))
-    }
-
-    #[test]
-    fn macos_hit_testing_uses_the_same_scale_on_secondary_displays() {
-        let mut windows = HashMap::new();
-        windows.insert("controls".to_string(), bounds(10.0, 20.0, 100.0, 40.0));
-        for (origin, primary_scale, window_scale) in [
-            ((1920.0, 100.0), 2.0, 1.0),
-            ((-1280.0, 100.0), 1.0, 2.0),
-            ((0.0, -900.0), 2.0, 1.0),
-            ((0.0, 0.0), 2.0, 2.0),
-        ] {
-            let position =
-                tauri::LogicalPosition::new(origin.0, origin.1).to_physical::(window_scale);
-            for (offset, ignored) in [((30.0, 30.0), false), ((150.0, 80.0), true)] {
-                let mouse = tauri::LogicalPosition::new(origin.0 + offset.0, origin.1 + offset.1)
-                    .to_physical::(primary_scale);
-                let mouse =
-                    macos_cursor_in_window_scale(mouse, primary_scale, window_scale).unwrap();
-                assert_eq!(
-                    should_ignore_cursor_events(
-                        position,
-                        mouse,
-                        window_scale,
-                        &windows,
-                        false,
-                        true,
-                    ),
-                    ignored,
-                );
-            }
-        }
-    }
-
-    #[test]
-    fn macos_hit_testing_rejects_invalid_coordinate_scales() {
-        for scale in [0.0, -1.0, f64::NAN, f64::INFINITY] {
-            assert!(
-                macos_cursor_in_window_scale(tauri::PhysicalPosition::new(20.0, 30.0), scale, 2.0,)
-                    .is_none()
-            );
-        }
-    }
-
-    #[test]
-    fn recording_controls_without_bounds_are_interactive() {
-        assert!(!should_ignore_cursor_events(
-            tauri::PhysicalPosition::new(100, 200),
-            tauri::PhysicalPosition::new(150.0, 240.0),
-            2.0,
-            &HashMap::new(),
-            false,
-            true,
-        ));
-    }
-
-    #[test]
-    fn recording_controls_without_bounds_pass_through_when_window_is_large() {
-        assert!(should_ignore_cursor_events(
-            tauri::PhysicalPosition::new(0, 0),
-            tauri::PhysicalPosition::new(150.0, 240.0),
-            2.0,
-            &HashMap::new(),
-            false,
-            false,
-        ));
-    }
-
-    #[test]
-    fn non_recording_windows_without_bounds_pass_through() {
-        assert!(should_ignore_cursor_events(
-            tauri::PhysicalPosition::new(100, 200),
-            tauri::PhysicalPosition::new(150.0, 240.0),
-            2.0,
-            &HashMap::new(),
-            true,
-            false,
-        ));
-    }
-
-    #[test]
-    fn cursor_inside_registered_bounds_is_interactive() {
-        let mut windows = HashMap::new();
-        windows.insert("controls".to_string(), bounds(10.0, 20.0, 100.0, 40.0));
-
-        assert!(!should_ignore_cursor_events(
-            tauri::PhysicalPosition::new(100, 200),
-            tauri::PhysicalPosition::new(150.0, 250.0),
-            2.0,
-            &windows,
-            false,
-            true,
-        ));
-    }
-
-    #[test]
-    fn cursor_outside_registered_bounds_passes_through() {
-        let mut windows = HashMap::new();
-        windows.insert("controls".to_string(), bounds(10.0, 20.0, 100.0, 40.0));
-
-        assert!(should_ignore_cursor_events(
-            tauri::PhysicalPosition::new(100, 200),
-            tauri::PhysicalPosition::new(50.0, 250.0),
-            2.0,
-            &windows,
-            false,
-            true,
-        ));
-    }
-
-    #[test]
-    fn zero_sized_recording_bounds_fail_open() {
-        let mut windows = HashMap::new();
-        windows.insert("controls".to_string(), bounds(10.0, 20.0, 0.0, 40.0));
-
-        assert!(!should_ignore_cursor_events(
-            tauri::PhysicalPosition::new(100, 200),
-            tauri::PhysicalPosition::new(50.0, 250.0),
-            2.0,
-            &windows,
-            false,
-            true,
-        ));
-    }
-
-    #[test]
-    fn oversized_bounds_do_not_make_the_window_interactive() {
-        let mut windows = HashMap::new();
-        windows.insert("controls".to_string(), bounds(0.0, 0.0, 1440.0, 900.0));
-
-        assert!(should_ignore_cursor_events(
-            tauri::PhysicalPosition::new(0, 0),
-            tauri::PhysicalPosition::new(150.0, 240.0),
-            2.0,
-            &windows,
-            false,
-            false,
-        ));
-    }
-
-    #[test]
-    fn recording_controls_default_interaction_is_size_limited() {
-        assert!(recording_controls_size_allows_default_interaction(
-            tauri::PhysicalSize::new(640, 300),
-            2.0,
-        ));
-        assert!(!recording_controls_size_allows_default_interaction(
-            tauri::PhysicalSize::new(1920, 1080),
-            2.0,
-        ));
-    }
-
-    #[test]
-    fn area_recording_controls_prefer_below_the_capture() {
-        let display = bounds(100.0, 200.0, 1920.0, 1080.0);
-        let area = bounds(200.0, 100.0, 800.0, 500.0);
-
-        let position = calculate_area_recording_controls_position(display, area);
-
-        assert_eq!(position, (540.0, 718.0));
-    }
-
-    #[test]
-    fn area_recording_controls_move_above_when_below_does_not_fit() {
-        let display = bounds(0.0, 0.0, 1920.0, 1080.0);
-        let area = bounds(300.0, 600.0, 800.0, 440.0);
-
-        let position = calculate_area_recording_controls_position(display, area);
-
-        assert_eq!(position, (540.0, 446.0));
-    }
-
-    #[test]
-    fn area_recording_controls_keep_the_existing_inside_fallback() {
-        let display = bounds(0.0, 0.0, 1920.0, 1080.0);
-        let area = bounds(300.0, 40.0, 800.0, 1000.0);
-
-        let position = calculate_area_recording_controls_position(display, area);
-
-        assert_eq!(position, (540.0, 842.0));
-    }
-
-    #[test]
-    fn area_recording_controls_stay_within_horizontal_display_edges() {
-        let display = bounds(100.0, 200.0, 1920.0, 1080.0);
-        let left_area = bounds(0.0, 100.0, 150.0, 300.0);
-        let right_area = bounds(1770.0, 100.0, 150.0, 300.0);
-
-        let left_position = calculate_area_recording_controls_position(display, left_area);
-        let right_position = calculate_area_recording_controls_position(display, right_area);
-
-        assert_eq!(left_position.0, 100.0);
-        assert_eq!(right_position.0, 1700.0);
-    }
-}
diff --git a/apps/desktop/src-tauri/src/flags.rs b/apps/desktop/src-tauri/src/flags.rs
deleted file mode 100644
index 0d763f50210..00000000000
--- a/apps/desktop/src-tauri/src/flags.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-pub mod plugin {
-    use cap_flags::FLAGS;
-    use tauri::{
-        Runtime,
-        plugin::{Builder, TauriPlugin},
-    };
-
-    pub fn init() -> TauriPlugin {
-        Builder::new("cap-flags")
-            .js_init_script(format!(
-                "window.FLAGS = {}",
-                serde_json::to_string_pretty(&FLAGS).unwrap()
-            ))
-            .build()
-    }
-}
diff --git a/apps/desktop/src-tauri/src/frame_ws.rs b/apps/desktop/src-tauri/src/frame_ws.rs
deleted file mode 100644
index a6e6503d1b5..00000000000
--- a/apps/desktop/src-tauri/src/frame_ws.rs
+++ /dev/null
@@ -1,1260 +0,0 @@
-use axum::body::Bytes;
-use serde::Deserialize;
-use std::sync::Arc;
-use std::sync::atomic::{AtomicUsize, Ordering};
-use std::time::Instant;
-use std::time::{SystemTime, UNIX_EPOCH};
-use tokio::sync::{broadcast, watch};
-use tokio_util::sync::CancellationToken;
-
-const NV12_VIDEO_FORMAT_MAGIC: u32 = 0x4e563132;
-const NV12_FULL_FORMAT_MAGIC: u32 = 0x4e563146;
-
-fn pack_frame_data(
-    mut data: Vec,
-    stride: u32,
-    height: u32,
-    width: u32,
-    frame_number: u32,
-    target_time_ns: u64,
-) -> Vec {
-    data.reserve_exact(24);
-    data.extend_from_slice(&stride.to_le_bytes());
-    data.extend_from_slice(&height.to_le_bytes());
-    data.extend_from_slice(&width.to_le_bytes());
-    data.extend_from_slice(&frame_number.to_le_bytes());
-    data.extend_from_slice(&target_time_ns.to_le_bytes());
-    data
-}
-
-#[derive(Clone, Copy, PartialEq, Eq)]
-pub enum WSFrameFormat {
-    Rgba,
-    Nv12 { full_range: bool },
-}
-
-#[derive(Clone)]
-pub enum WSFrameData {
-    Raw(Arc>),
-    Packed(Bytes),
-}
-
-impl From>> for WSFrameData {
-    fn from(data: Arc>) -> Self {
-        Self::Raw(data)
-    }
-}
-
-#[derive(Clone)]
-pub struct WSFrame {
-    pub data: WSFrameData,
-    pub width: u32,
-    pub height: u32,
-    pub stride: u32,
-    pub frame_number: u32,
-    pub target_time_ns: u64,
-    pub format: WSFrameFormat,
-    #[allow(dead_code)]
-    pub created_at: Instant,
-}
-
-impl WSFrame {
-    pub fn into_packed(mut self) -> Self {
-        if let WSFrameData::Raw(data) = self.data {
-            self.data = WSFrameData::Packed(pack_frame_payload(
-                Arc::unwrap_or_clone(data),
-                self.stride,
-                self.height,
-                self.width,
-                self.frame_number,
-                self.target_time_ns,
-                self.format,
-            ));
-        }
-        self
-    }
-}
-
-fn pack_ws_frame(frame: &WSFrame) -> Bytes {
-    let data = match &frame.data {
-        WSFrameData::Raw(data) => data,
-        WSFrameData::Packed(data) => return data.clone(),
-    };
-    let metadata_size = match frame.format {
-        WSFrameFormat::Nv12 { .. } => 28usize,
-        WSFrameFormat::Rgba => 24,
-    };
-    let mut buf = Vec::with_capacity(data.len() + metadata_size);
-    buf.extend_from_slice(data);
-    pack_frame_payload(
-        buf,
-        frame.stride,
-        frame.height,
-        frame.width,
-        frame.frame_number,
-        frame.target_time_ns,
-        frame.format,
-    )
-}
-
-fn pack_frame_payload(
-    mut data: Vec,
-    stride: u32,
-    height: u32,
-    width: u32,
-    frame_number: u32,
-    target_time_ns: u64,
-    format: WSFrameFormat,
-) -> Bytes {
-    if matches!(format, WSFrameFormat::Nv12 { .. }) {
-        data.reserve_exact(28);
-    }
-    let mut buf = pack_frame_data(data, stride, height, width, frame_number, target_time_ns);
-    if let WSFrameFormat::Nv12 { full_range } = format {
-        let magic = if full_range {
-            NV12_FULL_FORMAT_MAGIC
-        } else {
-            NV12_VIDEO_FORMAT_MAGIC
-        };
-        buf.extend_from_slice(&magic.to_le_bytes());
-    }
-
-    buf.into()
-}
-
-fn duration_ns(duration: std::time::Duration) -> u64 {
-    duration.as_nanos().min(u128::from(u64::MAX)) as u64
-}
-
-#[derive(Default)]
-struct WsFrameStats {
-    total_bytes_sent: u64,
-    total_frames_sent: u32,
-    last_log_time_ms: u64,
-    total_pack_ns: u64,
-    max_pack_ns: u64,
-    total_send_ns: u64,
-    max_send_ns: u64,
-    total_created_to_sent_ns: u64,
-    max_created_to_sent_ns: u64,
-}
-
-impl WsFrameStats {
-    fn record(
-        &mut self,
-        packed_len: usize,
-        pack_duration: std::time::Duration,
-        send_duration: std::time::Duration,
-        created_to_sent: std::time::Duration,
-    ) {
-        self.total_bytes_sent += packed_len as u64;
-        self.total_frames_sent += 1;
-        let pack_ns = duration_ns(pack_duration);
-        let send_ns = duration_ns(send_duration);
-        let created_to_sent_ns = duration_ns(created_to_sent);
-        self.total_pack_ns += pack_ns;
-        self.max_pack_ns = self.max_pack_ns.max(pack_ns);
-        self.total_send_ns += send_ns;
-        self.max_send_ns = self.max_send_ns.max(send_ns);
-        self.total_created_to_sent_ns += created_to_sent_ns;
-        self.max_created_to_sent_ns = self.max_created_to_sent_ns.max(created_to_sent_ns);
-    }
-
-    fn reset_window(&mut self, now_ms: u64) -> WsFrameStatsWindow {
-        self.last_log_time_ms = now_ms;
-        WsFrameStatsWindow {
-            total_bytes_sent: std::mem::take(&mut self.total_bytes_sent),
-            total_frames_sent: std::mem::take(&mut self.total_frames_sent),
-            total_pack_ns: std::mem::take(&mut self.total_pack_ns),
-            max_pack_ns: std::mem::take(&mut self.max_pack_ns),
-            total_send_ns: std::mem::take(&mut self.total_send_ns),
-            max_send_ns: std::mem::take(&mut self.max_send_ns),
-            total_created_to_sent_ns: std::mem::take(&mut self.total_created_to_sent_ns),
-            max_created_to_sent_ns: std::mem::take(&mut self.max_created_to_sent_ns),
-        }
-    }
-}
-
-struct WsFrameStatsWindow {
-    total_bytes_sent: u64,
-    total_frames_sent: u32,
-    total_pack_ns: u64,
-    max_pack_ns: u64,
-    total_send_ns: u64,
-    max_send_ns: u64,
-    total_created_to_sent_ns: u64,
-    max_created_to_sent_ns: u64,
-}
-
-struct SubscriberCountGuard {
-    subscribers: Arc,
-    instant_subscribers: Option>,
-}
-
-impl Drop for SubscriberCountGuard {
-    fn drop(&mut self) {
-        self.subscribers.fetch_sub(1, Ordering::AcqRel);
-        if let Some(instant_subscribers) = &self.instant_subscribers {
-            instant_subscribers.fetch_sub(1, Ordering::AcqRel);
-        }
-    }
-}
-
-#[derive(Deserialize)]
-struct WatchFrameQuery {
-    #[serde(default)]
-    instant: bool,
-}
-
-fn is_normal_socket_disconnect(error: &impl std::fmt::Debug) -> bool {
-    let error = format!("{error:?}");
-    error.contains("BrokenPipe")
-        || error.contains("Broken pipe")
-        || error.contains("ConnectionReset")
-        || error.contains("Connection reset by peer")
-}
-
-pub async fn create_watch_frame_ws(
-    frame_rx: watch::Receiver>>,
-    subscribers: Arc,
-) -> (u16, CancellationToken) {
-    create_watch_frame_ws_inner(frame_rx, subscribers, None).await
-}
-
-pub async fn create_watch_frame_ws_with_instant_tracking(
-    frame_rx: watch::Receiver>>,
-    subscribers: Arc,
-    instant_subscribers: Arc,
-) -> (u16, CancellationToken) {
-    create_watch_frame_ws_inner(frame_rx, subscribers, Some(instant_subscribers)).await
-}
-
-async fn create_watch_frame_ws_inner(
-    frame_rx: watch::Receiver>>,
-    subscribers: Arc,
-    instant_subscribers: Option>,
-) -> (u16, CancellationToken) {
-    use axum::{
-        extract::{
-            Query, State,
-            ws::{Message, WebSocket, WebSocketUpgrade},
-        },
-        response::IntoResponse,
-        routing::get,
-    };
-
-    type RouterState = (
-        watch::Receiver>>,
-        Arc,
-        Option>,
-        CancellationToken,
-    );
-
-    #[axum::debug_handler]
-    async fn ws_handler(
-        ws: WebSocketUpgrade,
-        Query(query): Query,
-        State((state, subscribers, instant_subscribers, shutdown)): State,
-    ) -> impl IntoResponse {
-        let instant_subscribers = query.instant.then_some(instant_subscribers).flatten();
-        ws.read_buffer_size(4096)
-            .on_upgrade(move |socket| async move {
-                tokio::select! {
-                    biased;
-                    _ = shutdown.cancelled() => {},
-                    _ = handle_socket(socket, state, subscribers, instant_subscribers) => {},
-                }
-            })
-    }
-
-    async fn handle_socket(
-        mut socket: WebSocket,
-        mut camera_rx: watch::Receiver>>,
-        subscribers: Arc,
-        instant_subscribers: Option>,
-    ) {
-        tracing::info!("Socket connection established");
-        let now = std::time::Instant::now();
-        let mut stats = WsFrameStats::default();
-
-        subscribers.fetch_add(1, Ordering::AcqRel);
-        if let Some(instant_subscribers) = &instant_subscribers {
-            instant_subscribers.fetch_add(1, Ordering::AcqRel);
-        }
-        let _subscriber_guard = SubscriberCountGuard {
-            subscribers,
-            instant_subscribers,
-        };
-
-        {
-            let packed = {
-                let borrowed = camera_rx.borrow();
-                borrowed
-                    .as_deref()
-                    .map(|frame| (pack_ws_frame(frame), frame.created_at.elapsed()))
-            };
-            match packed {
-                Some((packed, frame_age)) => {
-                    if let Err(e) = socket.send(Message::Binary(packed)).await {
-                        if is_normal_socket_disconnect(&e) {
-                            tracing::debug!(
-                                "Initial frame send skipped because socket closed: {:?}",
-                                e
-                            );
-                        } else {
-                            tracing::error!("Failed to send initial frame to socket: {:?}", e);
-                        }
-                        return;
-                    }
-                    tracing::info!(
-                        frame_age_ms = frame_age.as_millis() as u64,
-                        "Editor open: initial frame delivered to new socket"
-                    );
-                }
-                None => {
-                    tracing::info!("Editor open: socket connected before any frame was rendered");
-                }
-            }
-        }
-
-        loop {
-            tokio::select! {
-                msg = socket.recv() => {
-                    match msg {
-                        Some(Ok(Message::Close(_))) | None => {
-                            tracing::info!("WebSocket closed");
-                            break;
-                        }
-                        Some(Ok(_)) => {}
-                        Some(Err(e)) => {
-                            if is_normal_socket_disconnect(&e) {
-                                tracing::debug!("WebSocket closed by client: {:?}", e);
-                            } else {
-                                tracing::error!("WebSocket error: {:?}", e);
-                            }
-                            break;
-                        }
-                    }
-                },
-                changed = camera_rx.changed() => {
-                    if changed.is_err() {
-                        break;
-                    }
-                    let frame_arc = camera_rx.borrow_and_update().clone();
-                    if let Some(ref frame) = frame_arc {
-                        let width = frame.width;
-                        let height = frame.height;
-                        let format_label = match frame.format {
-                            WSFrameFormat::Nv12 { full_range: false } => "NV12",
-                            WSFrameFormat::Nv12 { full_range: true } => "NV12-full",
-                            WSFrameFormat::Rgba => "RGBA",
-                        };
-
-                        let pack_start = Instant::now();
-                        let packed = pack_ws_frame(frame);
-                        let pack_duration = pack_start.elapsed();
-                        let packed_len = packed.len();
-
-                        let send_start = Instant::now();
-                        match socket.send(Message::Binary(packed)).await {
-                            Ok(()) => {
-                                let send_duration = send_start.elapsed();
-                                stats.record(
-                                    packed_len,
-                                    pack_duration,
-                                    send_duration,
-                                    frame.created_at.elapsed(),
-                                );
-                                let now_ms = SystemTime::now()
-                                    .duration_since(UNIX_EPOCH)
-                                    .map(|duration| duration.as_millis() as u64)
-                                    .unwrap_or_default();
-                                if now_ms.saturating_sub(stats.last_log_time_ms) > 2000 {
-                                    let window = stats.reset_window(now_ms);
-                                    let frames = window.total_frames_sent.max(1) as f64;
-                                    let mb_per_sec = window.total_bytes_sent as f64 / 1_000_000.0 / 2.0;
-                                    tracing::info!(
-                                        fps = window.total_frames_sent / 2,
-                                        mb_per_sec = format!("{:.1}", mb_per_sec),
-                                        avg_kb = format!("{:.1}", (window.total_bytes_sent as f64 / window.total_frames_sent.max(1) as f64) / 1024.0),
-                                        pack_avg_ms = format!("{:.3}", window.total_pack_ns as f64 / frames / 1_000_000.0),
-                                        pack_max_ms = format!("{:.3}", window.max_pack_ns as f64 / 1_000_000.0),
-                                        send_avg_ms = format!("{:.3}", window.total_send_ns as f64 / frames / 1_000_000.0),
-                                        send_max_ms = format!("{:.3}", window.max_send_ns as f64 / 1_000_000.0),
-                                        created_to_sent_avg_ms = format!("{:.3}", window.total_created_to_sent_ns as f64 / frames / 1_000_000.0),
-                                        created_to_sent_max_ms = format!("{:.3}", window.max_created_to_sent_ns as f64 / 1_000_000.0),
-                                        dims = format!("{}x{}", width, height),
-                                        format = format_label,
-                                        "WS frame stats"
-                                    );
-                                }
-                            }
-                            Err(e) => {
-                                if is_normal_socket_disconnect(&e) {
-                                    tracing::debug!("Frame send stopped because socket closed: {:?}", e);
-                                } else {
-                                    tracing::error!("Failed to send frame to socket: {:?}", e);
-                                }
-                                break;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        let elapsed = now.elapsed();
-        tracing::info!("Websocket closing after {elapsed:.2?}");
-    }
-
-    let cancel_token = CancellationToken::new();
-    let server_shutdown = cancel_token.child_token();
-    let router = axum::Router::new().route("/", get(ws_handler)).with_state((
-        frame_rx,
-        subscribers,
-        instant_subscribers,
-        server_shutdown.clone(),
-    ));
-    let listener = match tokio::net::TcpListener::bind("127.0.0.1:0").await {
-        Ok(listener) => listener,
-        Err(err) => {
-            tracing::error!("Failed to bind watch frame websocket listener: {err}");
-            cancel_token.cancel();
-            return (0, cancel_token);
-        }
-    };
-    let port = match listener.local_addr() {
-        Ok(addr) => addr.port(),
-        Err(err) => {
-            tracing::error!("Failed to read watch frame websocket listener address: {err}");
-            cancel_token.cancel();
-            return (0, cancel_token);
-        }
-    };
-    tracing::info!("WebSocket server listening on port {}", port);
-
-    tokio::spawn(async move {
-        let _shutdown_guard = server_shutdown.clone().drop_guard();
-        let server = axum::serve(listener, router.into_make_service())
-            .with_graceful_shutdown(server_shutdown.clone().cancelled_owned());
-        tokio::select! {
-            biased;
-            _ = server_shutdown.cancelled() => {
-                tracing::info!("WebSocket server shutting down");
-            },
-            _ = server => {},
-        }
-    });
-
-    (port, cancel_token)
-}
-
-pub async fn create_frame_ws(frame_tx: broadcast::Sender) -> (u16, CancellationToken) {
-    use axum::{
-        extract::{
-            State,
-            ws::{Message, WebSocket, WebSocketUpgrade},
-        },
-        response::IntoResponse,
-        routing::get,
-    };
-
-    type RouterState = (broadcast::Sender, CancellationToken);
-
-    #[axum::debug_handler]
-    async fn ws_handler(
-        ws: WebSocketUpgrade,
-        State((state, shutdown)): State,
-    ) -> impl IntoResponse {
-        let rx = state.subscribe();
-        ws.read_buffer_size(4096)
-            .on_upgrade(move |socket| async move {
-                tokio::select! {
-                    biased;
-                    _ = shutdown.cancelled() => {},
-                    _ = handle_socket(socket, rx) => {},
-                }
-            })
-    }
-
-    async fn handle_socket(mut socket: WebSocket, mut camera_rx: broadcast::Receiver) {
-        tracing::info!("Socket connection established");
-        let now = std::time::Instant::now();
-
-        loop {
-            tokio::select! {
-                msg = socket.recv() => {
-                    match msg {
-                        Some(Ok(Message::Close(_))) | None => {
-                            tracing::info!("WebSocket closed");
-                            break;
-                        }
-                        Some(Ok(_)) => {
-                             tracing::info!("Received message from socket (ignoring)");
-                        }
-                        Some(Err(e)) => {
-                            if is_normal_socket_disconnect(&e) {
-                                tracing::debug!("WebSocket closed by client: {:?}", e);
-                            } else {
-                                tracing::error!("WebSocket error: {:?}", e);
-                            }
-                            break;
-                        }
-                    }
-                },
-                incoming_frame = camera_rx.recv() => {
-                    match incoming_frame {
-                        Ok(frame) => {
-                            let packed = pack_ws_frame(&frame.into_packed());
-
-                            if let Err(e) = socket.send(Message::Binary(packed)).await {
-                                if is_normal_socket_disconnect(&e) {
-                                    tracing::debug!("Frame send stopped because socket closed: {:?}", e);
-                                } else {
-                                    tracing::error!("Failed to send frame to socket: {:?}", e);
-                                }
-                                break;
-                            }
-                        }
-                        Err(broadcast::error::RecvError::Closed) => {
-                            tracing::error!(
-                                "Connection has been lost! Shutting down websocket server"
-                            );
-                            break;
-                        }
-                        Err(broadcast::error::RecvError::Lagged(_skipped)) => {
-                            continue;
-                        }
-                    }
-                }
-            }
-        }
-
-        let elapsed = now.elapsed();
-        tracing::info!("Websocket closing after {elapsed:.2?}");
-    }
-
-    let cancel_token = CancellationToken::new();
-    let server_shutdown = cancel_token.child_token();
-    let router = axum::Router::new()
-        .route("/", get(ws_handler))
-        .with_state((frame_tx, server_shutdown.clone()));
-    let listener = match tokio::net::TcpListener::bind("127.0.0.1:0").await {
-        Ok(listener) => listener,
-        Err(err) => {
-            tracing::error!("Failed to bind frame websocket listener: {err}");
-            cancel_token.cancel();
-            return (0, cancel_token);
-        }
-    };
-    let port = match listener.local_addr() {
-        Ok(addr) => addr.port(),
-        Err(err) => {
-            tracing::error!("Failed to read frame websocket listener address: {err}");
-            cancel_token.cancel();
-            return (0, cancel_token);
-        }
-    };
-    tracing::info!("WebSocket server listening on port {}", port);
-
-    tokio::spawn(async move {
-        let _shutdown_guard = server_shutdown.clone().drop_guard();
-        let server = axum::serve(listener, router.into_make_service())
-            .with_graceful_shutdown(server_shutdown.clone().cancelled_owned());
-        tokio::select! {
-            biased;
-            _ = server_shutdown.cancelled() => {
-                tracing::info!("WebSocket server shutting down");
-            },
-            _ = server => {},
-        }
-    });
-
-    (port, cancel_token)
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    fn frame(format: WSFrameFormat) -> WSFrame {
-        WSFrame {
-            data: Arc::new(vec![1, 2, 3, 4, 5, 6]).into(),
-            width: 2,
-            height: 2,
-            stride: 2,
-            frame_number: 7,
-            target_time_ns: 8,
-            format,
-            created_at: Instant::now(),
-        }
-    }
-
-    #[test]
-    fn packs_rgba_frame_with_legacy_metadata_shape() {
-        let packed = pack_ws_frame(&frame(WSFrameFormat::Rgba));
-
-        assert_eq!(packed.len(), 30);
-        assert_eq!(&packed[..6], &[1, 2, 3, 4, 5, 6]);
-        assert_eq!(u32::from_le_bytes(packed[6..10].try_into().unwrap()), 2);
-        assert_eq!(u32::from_le_bytes(packed[18..22].try_into().unwrap()), 7);
-        assert_eq!(u64::from_le_bytes(packed[22..30].try_into().unwrap()), 8);
-    }
-
-    #[test]
-    fn packs_nv12_frame_with_video_range_marker() {
-        let packed = pack_ws_frame(&frame(WSFrameFormat::Nv12 { full_range: false }));
-
-        assert_eq!(packed.len(), 34);
-        assert_eq!(
-            u32::from_le_bytes(packed[30..34].try_into().unwrap()),
-            NV12_VIDEO_FORMAT_MAGIC
-        );
-    }
-
-    #[test]
-    fn owned_frame_packing_reuses_pixels_and_replay_shares_the_packet() {
-        for format in [
-            WSFrameFormat::Rgba,
-            WSFrameFormat::Nv12 { full_range: false },
-            WSFrameFormat::Nv12 { full_range: true },
-        ] {
-            let mut frame = frame(format);
-            let mut pixels = Vec::with_capacity(6 + 28);
-            pixels.extend_from_slice(&[1, 2, 3, 4, 5, 6]);
-            let allocation = pixels.as_ptr();
-            frame.data = Arc::new(pixels).into();
-            let expected = pack_ws_frame(&frame);
-            let packed_frame = frame.into_packed();
-            let first = pack_ws_frame(&packed_frame);
-            let replay = pack_ws_frame(&packed_frame.clone().into_packed());
-            assert_eq!(first, expected);
-            assert_eq!(replay, expected);
-            assert_eq!(first.as_ptr(), allocation);
-            assert_eq!(replay.as_ptr(), allocation);
-        }
-    }
-
-    #[test]
-    fn packing_shared_pixels_preserves_other_readers_and_camera_pool_contents() {
-        let pixels = Arc::new(vec![1, 2, 3, 4, 5, 6]);
-        let mut frame = frame(WSFrameFormat::Rgba);
-        frame.data = pixels.clone().into();
-        let expected = pack_ws_frame(&frame);
-        let packed = pack_ws_frame(&frame.into_packed());
-        assert_eq!(packed, expected);
-        assert_eq!(pixels.as_slice(), &[1, 2, 3, 4, 5, 6]);
-        assert_ne!(packed.as_ptr(), pixels.as_ptr());
-    }
-
-    #[test]
-    fn subscriber_guard_decrements_both_counts() {
-        let subscribers = Arc::new(AtomicUsize::new(1));
-        let instant_subscribers = Arc::new(AtomicUsize::new(1));
-
-        drop(SubscriberCountGuard {
-            subscribers: subscribers.clone(),
-            instant_subscribers: Some(instant_subscribers.clone()),
-        });
-
-        assert_eq!(subscribers.load(Ordering::Acquire), 0);
-        assert_eq!(instant_subscribers.load(Ordering::Acquire), 0);
-    }
-}
-
-#[cfg(test)]
-mod shutdown_tests {
-    use super::*;
-    use std::time::Duration;
-    use tokio::io::{AsyncReadExt, AsyncWriteExt};
-    use tokio::net::{TcpListener, TcpStream};
-
-    fn frame() -> WSFrame {
-        WSFrame {
-            data: Arc::new(vec![1, 2, 3, 4]).into(),
-            width: 1,
-            height: 1,
-            stride: 4,
-            frame_number: 42,
-            target_time_ns: 1234,
-            format: WSFrameFormat::Rgba,
-            created_at: Instant::now(),
-        }
-    }
-
-    async fn wait_until(condition: impl Fn() -> bool) {
-        tokio::time::timeout(Duration::from_secs(2), async {
-            while !condition() {
-                tokio::time::sleep(Duration::from_millis(5)).await;
-            }
-        })
-        .await
-        .expect("shutdown condition did not settle");
-    }
-
-    async fn connect(port: u16, instant: bool) -> TcpStream {
-        assert_ne!(port, 0);
-        tokio::time::timeout(Duration::from_secs(2), async {
-            let mut stream = TcpStream::connect(("127.0.0.1", port)).await.unwrap();
-            let path = if instant { "/?instant=true" } else { "/" };
-            let request = format!(
-                "GET {path} HTTP/1.1\r\nHost: 127.0.0.1:{port}\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\n\r\n"
-            );
-            stream.write_all(request.as_bytes()).await.unwrap();
-            let mut response = Vec::new();
-            while !response.ends_with(b"\r\n\r\n") {
-                assert!(response.len() < 4096);
-                response.push(stream.read_u8().await.unwrap());
-            }
-            assert!(response.starts_with(b"HTTP/1.1 101"));
-            stream
-        })
-        .await
-        .expect("websocket handshake timed out")
-    }
-
-    async fn read_binary(stream: &mut TcpStream) -> Vec {
-        tokio::time::timeout(Duration::from_secs(2), async {
-            assert_eq!(stream.read_u8().await.unwrap(), 0x82);
-            let length = stream.read_u8().await.unwrap();
-            assert!(length < 126);
-            let mut data = vec![0; usize::from(length)];
-            stream.read_exact(&mut data).await.unwrap();
-            data
-        })
-        .await
-        .expect("frame delivery timed out")
-    }
-
-    async fn assert_disconnected(stream: &mut TcpStream) {
-        tokio::time::timeout(Duration::from_secs(2), async {
-            let mut buffer = [0; 8192];
-            loop {
-                match stream.read(&mut buffer).await {
-                    Ok(0) | Err(_) => break,
-                    Ok(_) => {}
-                }
-            }
-        })
-        .await
-        .expect("connected websocket did not close");
-    }
-
-    async fn assert_listener_closed(port: u16) {
-        // Windows can take just over two seconds to report a refused loopback connection.
-        let timeout = Duration::from_secs(if cfg!(windows) { 5 } else { 2 });
-        tokio::time::timeout(timeout, async {
-            while TcpStream::connect(("127.0.0.1", port)).await.is_ok() {
-                tokio::time::sleep(Duration::from_millis(5)).await;
-            }
-        })
-        .await
-        .expect("websocket listener still accepts connections");
-    }
-
-    async fn assert_unused_port_released(port: u16) {
-        let listener = tokio::time::timeout(Duration::from_secs(2), async {
-            loop {
-                if let Ok(listener) = TcpListener::bind(("127.0.0.1", port)).await {
-                    break listener;
-                }
-                tokio::time::sleep(Duration::from_millis(5)).await;
-            }
-        })
-        .await
-        .expect("websocket listener still owns its port");
-        drop(listener);
-        assert_listener_closed(port).await;
-    }
-
-    #[tokio::test]
-    async fn watch_listener_releases_port_after_cancel_before_server_poll() {
-        let (_tx, rx) = watch::channel(None);
-        let (port, shutdown) = create_watch_frame_ws(rx, Default::default()).await;
-        shutdown.cancel();
-        assert_unused_port_released(port).await;
-    }
-
-    #[tokio::test]
-    async fn broadcast_listener_releases_port_after_cancel_before_server_poll() {
-        let (tx, _rx) = broadcast::channel(2);
-        let (port, shutdown) = create_frame_ws(tx).await;
-        shutdown.cancel();
-        assert_unused_port_released(port).await;
-    }
-
-    #[tokio::test]
-    async fn watch_shutdown_drains_existing_clients_and_subscriber_counts() {
-        let (tx, rx) = watch::channel(None);
-        let subscribers = Arc::new(AtomicUsize::new(0));
-        let instant = Arc::new(AtomicUsize::new(0));
-        let (port, shutdown) =
-            create_watch_frame_ws_with_instant_tracking(rx, subscribers.clone(), instant.clone())
-                .await;
-        let mut first = connect(port, false).await;
-        let mut second = connect(port, true).await;
-        wait_until(|| subscribers.load(Ordering::Acquire) == 2).await;
-        assert_eq!(instant.load(Ordering::Acquire), 1);
-        let frame = frame();
-        let expected = pack_ws_frame(&frame);
-        tx.send(Some(Arc::new(frame))).unwrap();
-        assert_eq!(read_binary(&mut first).await, expected);
-        assert_eq!(read_binary(&mut second).await, expected);
-        shutdown.cancel();
-        assert_disconnected(&mut first).await;
-        assert_disconnected(&mut second).await;
-        wait_until(|| subscribers.load(Ordering::Acquire) == 0 && tx.receiver_count() == 0).await;
-        assert_eq!(instant.load(Ordering::Acquire), 0);
-        assert_listener_closed(port).await;
-    }
-
-    #[tokio::test]
-    async fn broadcast_shutdown_drains_existing_clients() {
-        let (tx, rx) = broadcast::channel(2);
-        drop(rx);
-        let (port, shutdown) = create_frame_ws(tx.clone()).await;
-        let mut first = connect(port, false).await;
-        let mut second = connect(port, false).await;
-        let frame = frame();
-        let expected = pack_ws_frame(&frame);
-        assert!(matches!(tx.send(frame), Ok(2)));
-        assert_eq!(read_binary(&mut first).await, expected);
-        assert_eq!(read_binary(&mut second).await, expected);
-        shutdown.cancel();
-        assert_disconnected(&mut first).await;
-        assert_disconnected(&mut second).await;
-        wait_until(|| tx.receiver_count() == 0).await;
-        assert_listener_closed(port).await;
-    }
-
-    #[tokio::test]
-    async fn packed_frames_replay_to_late_clients_and_deliver_replacements() {
-        let initial = frame();
-        let expected_initial = pack_ws_frame(&initial);
-        let (tx, rx) = watch::channel(Some(Arc::new(initial.into_packed())));
-        let subscribers = Arc::new(AtomicUsize::new(0));
-        let (port, shutdown) = create_watch_frame_ws(rx, subscribers.clone()).await;
-        let mut first = connect(port, false).await;
-        assert_eq!(read_binary(&mut first).await, expected_initial);
-        let mut second = connect(port, false).await;
-        assert_eq!(read_binary(&mut second).await, expected_initial);
-        let mut replacement = frame();
-        replacement.frame_number += 1;
-        replacement.target_time_ns += 1;
-        replacement.data = Arc::new(vec![5, 6, 7, 8]).into();
-        let expected_replacement = pack_ws_frame(&replacement);
-        tx.send(Some(Arc::new(replacement.into_packed()))).unwrap();
-        assert_eq!(read_binary(&mut first).await, expected_replacement);
-        assert_eq!(read_binary(&mut second).await, expected_replacement);
-        shutdown.cancel();
-        assert_disconnected(&mut first).await;
-        assert_disconnected(&mut second).await;
-        wait_until(|| subscribers.load(Ordering::Acquire) == 0 && tx.receiver_count() == 0).await;
-        assert_listener_closed(port).await;
-    }
-
-    #[tokio::test]
-    async fn watch_source_close_does_not_resend_retained_frame() {
-        let frame = Arc::new(frame());
-        let (tx, rx) = watch::channel(Some(frame.clone()));
-        let subscribers = Arc::new(AtomicUsize::new(0));
-        let (port, shutdown) = create_watch_frame_ws(rx, subscribers.clone()).await;
-        let mut client = connect(port, false).await;
-        assert_eq!(read_binary(&mut client).await, pack_ws_frame(&frame));
-        drop(tx);
-        wait_until(|| subscribers.load(Ordering::Acquire) == 0).await;
-        assert_disconnected(&mut client).await;
-        shutdown.cancel();
-        assert_listener_closed(port).await;
-    }
-
-    #[tokio::test]
-    async fn watch_shutdown_interrupts_stalled_initial_send() {
-        let mut frame = frame();
-        frame.width = 4096;
-        frame.height = 1024;
-        frame.stride = 4096 * 4;
-        let data = Arc::new(vec![0; frame.stride as usize * frame.height as usize]);
-        let weak_data = Arc::downgrade(&data);
-        frame.data = data.into();
-        let (tx, rx) = watch::channel(Some(Arc::new(frame)));
-        let subscribers = Arc::new(AtomicUsize::new(0));
-        let (port, shutdown) = create_watch_frame_ws(rx, subscribers.clone()).await;
-        let client = connect(port, false).await;
-        wait_until(|| subscribers.load(Ordering::Acquire) == 1).await;
-        tokio::time::sleep(Duration::from_millis(20)).await;
-        shutdown.cancel();
-        wait_until(|| subscribers.load(Ordering::Acquire) == 0 && tx.receiver_count() == 0).await;
-        drop(tx);
-        assert!(weak_data.upgrade().is_none());
-        drop(client);
-        assert_listener_closed(port).await;
-    }
-
-    #[tokio::test]
-    async fn cancelling_owner_child_does_not_stop_sibling_server() {
-        let (tx, rx) = watch::channel(None);
-        let (port, shutdown) = create_watch_frame_ws(rx, Default::default()).await;
-        shutdown.child_token().cancel();
-        assert!(!shutdown.is_cancelled());
-        let mut client = connect(port, false).await;
-        let frame = frame();
-        let expected = pack_ws_frame(&frame);
-        tx.send(Some(Arc::new(frame))).unwrap();
-        assert_eq!(read_binary(&mut client).await, expected);
-        shutdown.cancel();
-        assert_disconnected(&mut client).await;
-        assert_listener_closed(port).await;
-    }
-
-    #[tokio::test]
-    async fn dropping_owner_token_preserves_app_scoped_camera_server() {
-        let (tx, rx) = watch::channel(None);
-        let (port, shutdown) = create_watch_frame_ws(rx, Default::default()).await;
-        drop(shutdown);
-        let mut client = connect(port, false).await;
-        let frame = frame();
-        let expected = pack_ws_frame(&frame);
-        tx.send(Some(Arc::new(frame))).unwrap();
-        assert_eq!(read_binary(&mut client).await, expected);
-    }
-
-    #[tokio::test]
-    async fn aborted_construction_drop_guard_releases_listener() {
-        let (port_tx, port_rx) = tokio::sync::oneshot::channel();
-        let construction = tokio::spawn(async move {
-            let (_tx, rx) = watch::channel(None);
-            let (port, shutdown) = create_watch_frame_ws(rx, Default::default()).await;
-            let _guard = shutdown.clone().drop_guard();
-            port_tx.send(port).unwrap();
-            std::future::pending::<()>().await;
-        });
-        let port = port_rx.await.unwrap();
-        construction.abort();
-        assert!(construction.await.unwrap_err().is_cancelled());
-        assert_unused_port_released(port).await;
-    }
-
-    #[tokio::test]
-    async fn successful_construction_disarms_guard_until_owner_cancels() {
-        let (tx, rx) = watch::channel(None);
-        let (port, shutdown) = create_watch_frame_ws(rx, Default::default()).await;
-        let guard = shutdown.clone().drop_guard();
-        drop(guard.disarm());
-        let mut client = connect(port, false).await;
-        let frame = frame();
-        let expected = pack_ws_frame(&frame);
-        tx.send(Some(Arc::new(frame))).unwrap();
-        assert_eq!(read_binary(&mut client).await, expected);
-        shutdown.cancel();
-        assert_disconnected(&mut client).await;
-        assert_listener_closed(port).await;
-    }
-
-    #[tokio::test]
-    async fn repeated_watch_open_cancel_releases_every_port() {
-        for _ in 0..20 {
-            let (_tx, rx) = watch::channel(None);
-            let (port, shutdown) = create_watch_frame_ws(rx, Default::default()).await;
-            let mut client = connect(port, false).await;
-            shutdown.cancel();
-            assert_disconnected(&mut client).await;
-            assert_listener_closed(port).await;
-        }
-    }
-
-    async fn connect_http_client(port: u16) -> TcpStream {
-        tokio::time::timeout(Duration::from_secs(2), async {
-            let mut client = TcpStream::connect(("127.0.0.1", port)).await.unwrap();
-            client
-                .write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n")
-                .await
-                .unwrap();
-            let mut response = Vec::new();
-            while !response.ends_with(b"\r\n\r\n") {
-                assert!(response.len() < 4096);
-                response.push(client.read_u8().await.unwrap());
-            }
-            assert!(response.starts_with(b"HTTP/1.1 400"));
-            let headers = std::str::from_utf8(&response).unwrap();
-            let length = headers
-                .lines()
-                .filter_map(|line| line.split_once(':'))
-                .find(|(name, _)| name.eq_ignore_ascii_case("content-length"))
-                .unwrap()
-                .1
-                .trim()
-                .parse::()
-                .unwrap();
-            assert!(length < 4096);
-            client.read_exact(&mut vec![0; length]).await.unwrap();
-            client
-        })
-        .await
-        .expect("HTTP connection did not become ready")
-    }
-
-    #[tokio::test]
-    async fn watch_shutdown_drains_incomplete_http_upgrade() {
-        let (tx, rx) = watch::channel(None);
-        let (port, shutdown) = create_watch_frame_ws(rx, Default::default()).await;
-        let mut client = connect_http_client(port).await;
-        client
-            .write_all(b"GET / HTTP/1.1\r\nUpgrade: websocket\r\n")
-            .await
-            .unwrap();
-        tokio::task::yield_now().await;
-        shutdown.cancel();
-        assert_disconnected(&mut client).await;
-        wait_until(|| tx.receiver_count() == 0).await;
-        assert_listener_closed(port).await;
-    }
-
-    #[tokio::test]
-    async fn broadcast_shutdown_drains_incomplete_http_upgrade() {
-        let (tx, rx) = broadcast::channel(2);
-        drop(rx);
-        let (port, shutdown) = create_frame_ws(tx.clone()).await;
-        let mut client = connect_http_client(port).await;
-        client
-            .write_all(b"GET / HTTP/1.1\r\nUpgrade: websocket\r\n")
-            .await
-            .unwrap();
-        tokio::task::yield_now().await;
-        shutdown.cancel();
-        assert_disconnected(&mut client).await;
-        wait_until(|| tx.strong_count() == 1).await;
-        assert_listener_closed(port).await;
-    }
-
-    #[tokio::test]
-    async fn watch_shutdown_drains_http_keep_alive_connection() {
-        let (tx, rx) = watch::channel(None);
-        let (port, shutdown) = create_watch_frame_ws(rx, Default::default()).await;
-        let mut client = connect_http_client(port).await;
-        shutdown.cancel();
-        assert_disconnected(&mut client).await;
-        wait_until(|| tx.receiver_count() == 0).await;
-        assert_listener_closed(port).await;
-    }
-}
-
-pub(crate) struct OwnedWatchFrameWs {
-    pub(crate) url: String,
-    shutdown: CancellationToken,
-    task: Option>>,
-}
-
-impl OwnedWatchFrameWs {
-    pub(crate) fn is_finished(&self) -> bool {
-        self.task
-            .as_ref()
-            .is_none_or(tokio::task::JoinHandle::is_finished)
-    }
-
-    pub(crate) async fn stop_and_wait(mut self) -> Result<(), String> {
-        self.shutdown.cancel();
-        self.task
-            .take()
-            .ok_or_else(|| "Preparing frame transport already joined".to_string())?
-            .await
-            .map_err(|error| format!("Preparing frame transport join failed: {error}"))?
-    }
-}
-
-impl Drop for OwnedWatchFrameWs {
-    fn drop(&mut self) {
-        self.shutdown.cancel();
-    }
-}
-
-pub(crate) async fn create_owned_watch_frame_ws(
-    frame_rx: watch::Receiver>>,
-    accepts: Arc bool + Send + Sync>,
-) -> Result {
-    use futures::{SinkExt, StreamExt};
-    use tokio_tungstenite::tungstenite::Message;
-
-    let listener = tokio::net::TcpListener::bind("127.0.0.1:0")
-        .await
-        .map_err(|error| error.to_string())?;
-    let port = listener
-        .local_addr()
-        .map_err(|error| error.to_string())?
-        .port();
-    let route = format!("/{}", uuid::Uuid::new_v4());
-    let url = format!("ws://127.0.0.1:{port}{route}");
-    let shutdown = CancellationToken::new();
-    let cancelled = shutdown.clone();
-    let task = tokio::spawn(async move {
-        let mut connections = tokio::task::JoinSet::new();
-        let mut failure = None;
-        loop {
-            tokio::select! {
-                biased;
-                _ = cancelled.cancelled() => break,
-                joined = connections.join_next(), if !connections.is_empty() => {
-                    if let Some(Err(error)) = joined {
-                        failure = Some(format!("Preparing frame connection join failed: {error}"));
-                        break;
-                    }
-                }
-                accepted = listener.accept() => {
-                    let (stream, _) = match accepted {
-                        Ok(value) => value,
-                        Err(error) => {
-                            tracing::debug!(%error, "Preparing frame transport accept stopped");
-                            break;
-                        }
-                    };
-                    if connections.len() >= 8 {
-                        drop(stream);
-                        continue;
-                    }
-                    let expected = route.clone();
-                    let mut frames = frame_rx.clone();
-                    let accepts = accepts.clone();
-                    let cancelled = cancelled.clone();
-                    connections.spawn(async move {
-                        let exchange = async move {
-                            let Ok(mut socket) = tokio_tungstenite::accept_hdr_async(
-                                stream,
-                                move |request: &tokio_tungstenite::tungstenite::handshake::server::Request, response| {
-                                    if request.uri().path() == expected && request.uri().query().is_none() {
-                                        Ok(response)
-                                    } else {
-                                        Err(tokio_tungstenite::tungstenite::http::Response::builder().status(404).body(None).unwrap())
-                                    }
-                                },
-                            ).await else { return; };
-                            loop {
-                                let frame = frames.borrow_and_update().clone();
-                                if let Some(frame) = frame
-                                    && accepts()
-                                    && socket.send(Message::Binary(pack_ws_frame(&frame).to_vec())).await.is_err()
-                                {
-                                    return;
-                                }
-                                tokio::select! {
-                                    changed = frames.changed() => if changed.is_err() { return; },
-                                    message = socket.next() => match message {
-                                        None | Some(Err(_)) | Some(Ok(Message::Close(_))) => return,
-                                        _ => {}
-                                    }
-                                }
-                            }
-                        };
-                        tokio::select! {
-                            biased;
-                            _ = cancelled.cancelled() => {},
-                            _ = exchange => {},
-                        }
-                    });
-                }
-            }
-        }
-        cancelled.cancel();
-        drop(listener);
-        while let Some(joined) = connections.join_next().await {
-            if let Err(error) = joined {
-                failure.get_or_insert_with(|| {
-                    format!("Preparing frame connection join failed: {error}")
-                });
-            }
-        }
-        failure.map_or(Ok(()), Err)
-    });
-    Ok(OwnedWatchFrameWs {
-        url,
-        shutdown,
-        task: Some(task),
-    })
-}
-
-#[cfg(test)]
-mod owned_preparing_tests {
-    use super::*;
-    use futures::StreamExt;
-    use tokio::io::AsyncWriteExt;
-
-    #[tokio::test]
-    async fn owned_transport_joins_incomplete_handshake_and_releases_port() {
-        let (_frames, rx) = watch::channel(None);
-        let server = create_owned_watch_frame_ws(rx, Arc::new(|| true))
-            .await
-            .unwrap();
-        let address = server
-            .url
-            .strip_prefix("ws://")
-            .unwrap()
-            .split('/')
-            .next()
-            .unwrap()
-            .to_string();
-        let mut client = tokio::net::TcpStream::connect(&address).await.unwrap();
-        client.write_all(b"GET / HTTP/1.1\r\n").await.unwrap();
-        tokio::task::yield_now().await;
-        tokio::time::timeout(std::time::Duration::from_secs(2), server.stop_and_wait())
-            .await
-            .unwrap()
-            .unwrap();
-        let listener = tokio::net::TcpListener::bind(address).await.unwrap();
-        drop(listener);
-    }
-
-    #[tokio::test]
-    async fn owned_transport_keeps_exact_frame_encoding_and_joins_live_client() {
-        let frame = Arc::new(WSFrame {
-            data: Arc::new(vec![1, 2, 3, 4]).into(),
-            width: 1,
-            height: 1,
-            stride: 4,
-            frame_number: 0,
-            target_time_ns: 0,
-            format: WSFrameFormat::Rgba,
-            created_at: Instant::now(),
-        });
-        let weak = Arc::downgrade(&frame);
-        let expected = pack_ws_frame(&frame);
-        let (frames, rx) = watch::channel(Some(frame));
-        let server = create_owned_watch_frame_ws(rx, Arc::new(|| true))
-            .await
-            .unwrap();
-        let (mut socket, _) = tokio_tungstenite::connect_async(&server.url).await.unwrap();
-        assert_eq!(socket.next().await.unwrap().unwrap().into_data(), expected);
-        tokio::time::timeout(std::time::Duration::from_secs(2), server.stop_and_wait())
-            .await
-            .unwrap()
-            .unwrap();
-        drop(frames);
-        assert!(weak.upgrade().is_none());
-    }
-
-    #[tokio::test]
-    async fn owned_transport_cancellation_joins_stalled_large_frame_send() {
-        let frame = Arc::new(WSFrame {
-            data: Arc::new(vec![1; 16 * 1024 * 1024]).into(),
-            width: 2048,
-            height: 2048,
-            stride: 8192,
-            frame_number: 0,
-            target_time_ns: 0,
-            format: WSFrameFormat::Rgba,
-            created_at: Instant::now(),
-        });
-        let weak = Arc::downgrade(&frame);
-        let (frames, rx) = watch::channel(Some(frame));
-        let server = create_owned_watch_frame_ws(rx, Arc::new(|| true))
-            .await
-            .unwrap();
-        let (socket, _) = tokio_tungstenite::connect_async(&server.url).await.unwrap();
-        tokio::time::sleep(std::time::Duration::from_millis(25)).await;
-        tokio::time::timeout(std::time::Duration::from_secs(2), server.stop_and_wait())
-            .await
-            .unwrap()
-            .unwrap();
-        drop(socket);
-        drop(frames);
-        assert!(weak.upgrade().is_none());
-    }
-}
diff --git a/apps/desktop/src-tauri/src/general_settings.rs b/apps/desktop/src-tauri/src/general_settings.rs
deleted file mode 100644
index 5a1c296f1ff..00000000000
--- a/apps/desktop/src-tauri/src/general_settings.rs
+++ /dev/null
@@ -1,999 +0,0 @@
-use crate::updates::UpdateChannel;
-use crate::window_exclusion::WindowExclusion;
-use scap_targets::DisplayId;
-use serde::{Deserialize, Serialize};
-use serde_json::{Value, json};
-use specta::Type;
-use std::collections::BTreeMap;
-use std::io::Write;
-use std::path::{Path, PathBuf};
-#[cfg(target_os = "macos")]
-use tauri::Listener;
-use tauri::{AppHandle, Manager, Wry};
-use tauri_plugin_store::StoreExt;
-use tracing::{error, instrument};
-use uuid::Uuid;
-
-#[derive(Default, Serialize, Deserialize, Type, Debug, Clone, Copy)]
-#[serde(rename_all = "camelCase")]
-pub enum PostStudioRecordingBehaviour {
-    #[default]
-    OpenEditor,
-    ShowOverlay,
-}
-
-#[derive(Default, Serialize, Deserialize, Type, Debug, Clone, Copy)]
-#[serde(rename_all = "camelCase")]
-pub enum MainWindowRecordingStartBehaviour {
-    #[default]
-    Close,
-    Minimise,
-}
-
-#[derive(Default, Serialize, Deserialize, Type, Debug, Clone, Copy)]
-#[serde(rename_all = "camelCase")]
-pub enum PostDeletionBehaviour {
-    #[default]
-    DoNothing,
-    ReopenRecordingWindow,
-}
-
-#[derive(Default, Serialize, Deserialize, Type, Debug, Clone, Copy)]
-#[serde(rename_all = "camelCase")]
-pub enum EditorPreviewQuality {
-    Quarter,
-    #[default]
-    Half,
-    Full,
-}
-
-#[derive(Serialize, Deserialize, Type, Debug, Clone, Copy, PartialEq, Eq)]
-#[serde(rename_all = "camelCase")]
-pub enum StudioRecordingQuality {
-    Compatibility,
-    Balanced,
-    Ultra,
-}
-
-impl Default for StudioRecordingQuality {
-    fn default() -> Self {
-        default_studio_recording_quality()
-    }
-}
-
-impl From for StudioRecordingQuality {
-    fn from(value: cap_recording::StudioQuality) -> Self {
-        match value {
-            cap_recording::StudioQuality::Compatibility => Self::Compatibility,
-            cap_recording::StudioQuality::Balanced => Self::Balanced,
-            cap_recording::StudioQuality::Ultra => Self::Ultra,
-        }
-    }
-}
-
-impl From for cap_recording::StudioQuality {
-    fn from(value: StudioRecordingQuality) -> Self {
-        match value {
-            StudioRecordingQuality::Compatibility => Self::Compatibility,
-            StudioRecordingQuality::Balanced => Self::Balanced,
-            StudioRecordingQuality::Ultra => Self::Ultra,
-        }
-    }
-}
-
-pub fn default_studio_recording_quality() -> StudioRecordingQuality {
-    cap_recording::default_studio_recording_quality().into()
-}
-
-impl MainWindowRecordingStartBehaviour {
-    pub fn perform(&self, window: &tauri::WebviewWindow) -> tauri::Result<()> {
-        match self {
-            Self::Close => {
-                // On Windows, hide() leaves the DirectComposition surface composited on screen as
-                // a white ghost box. minimize() releases the surface without leaving an artifact.
-                #[cfg(windows)]
-                return window.minimize();
-                #[cfg(not(windows))]
-                {
-                    crate::hide_main_window(window.app_handle());
-                    Ok(())
-                }
-            }
-            Self::Minimise => window.minimize(),
-        }
-    }
-}
-
-// NOTE: Do not add "Cap Target Select" here — on Windows, WDA_EXCLUDEFROMCAPTURE applied to that
-// hidden window causes it to reappear as a ghost overlay after recording ends.
-const DEFAULT_EXCLUDED_WINDOW_TITLES: &[&str] = &[
-    "Cap",
-    "Cap Settings",
-    "Cap Recording Controls",
-    "Cap Camera",
-    "Cap Window Capture Occluder",
-    "Cap Capture Area",
-    "Cap Mode Selection",
-    "Cap Recordings Overlay",
-    "Cap Teleprompter",
-];
-
-pub fn default_excluded_windows() -> Vec {
-    DEFAULT_EXCLUDED_WINDOW_TITLES
-        .iter()
-        .map(|title| WindowExclusion {
-            bundle_identifier: None,
-            owner_name: None,
-            window_title: Some((*title).to_string()),
-        })
-        .collect()
-}
-
-fn append_missing_default_excluded_windows(excluded_windows: &mut Vec) -> bool {
-    let mut changed = false;
-
-    for default in default_excluded_windows() {
-        if !excluded_windows.contains(&default) {
-            excluded_windows.push(default);
-            changed = true;
-        }
-    }
-
-    changed
-}
-
-// When adding fields here, #[serde(default)] defines the value to use for existing configurations,
-// and `Default::default` defines the value to use for new configurations.
-// Things that affect the user experience should only be enabled by default for new configurations.
-#[derive(Serialize, Deserialize, Type, Debug, Clone)]
-#[serde(rename_all = "camelCase")]
-pub struct WindowPosition {
-    pub x: f64,
-    pub y: f64,
-    #[serde(default)]
-    pub display_id: Option,
-}
-
-#[derive(Serialize, Deserialize, Type, Debug, Clone)]
-#[serde(rename_all = "camelCase")]
-pub struct GeneralSettingsStore {
-    #[serde(default = "uuid::Uuid::new_v4")]
-    pub instance_id: Uuid,
-    #[serde(default)]
-    pub upload_individual_files: bool,
-    #[serde(default)]
-    pub hide_dock_icon: bool,
-    #[serde(default)]
-    pub auto_create_shareable_link: bool,
-    #[serde(default = "default_true")]
-    pub enable_notifications: bool,
-    #[serde(default)]
-    pub disable_auto_open_links: bool,
-    #[serde(default = "default_true")]
-    pub has_completed_startup: bool,
-    #[serde(default)]
-    pub theme: AppTheme,
-    #[serde(default)]
-    pub commercial_license: Option,
-    #[serde(default)]
-    pub last_version: Option,
-    #[serde(default)]
-    pub window_transparency: bool,
-    #[serde(default)]
-    pub post_studio_recording_behaviour: PostStudioRecordingBehaviour,
-    #[serde(default)]
-    pub main_window_recording_start_behaviour: MainWindowRecordingStartBehaviour,
-    #[serde(
-        default = "default_custom_cursor_capture",
-        rename = "custom_cursor_capture2"
-    )]
-    pub custom_cursor_capture: bool,
-    #[serde(default = "default_server_url")]
-    pub server_url: String,
-    #[serde(default)]
-    pub recording_countdown: Option,
-    #[serde(
-        default = "default_enable_native_camera_preview",
-        skip_serializing_if = "no"
-    )]
-    pub enable_native_camera_preview: bool,
-    #[serde(default = "default_true")]
-    pub auto_zoom_on_clicks: bool,
-    #[serde(default)]
-    pub default_zoom_amount: Option,
-    /// `None` until [`init`] seeds it from whether this machine has a notched
-    /// display. From then on it is the user's preference and nothing re-reads
-    /// the hardware, so moving between machines can't silently flip it.
-    #[serde(default)]
-    pub macbook_notch_overlay: Option,
-    #[serde(default = "default_capture_keyboard_events")]
-    pub capture_keyboard_events: bool,
-    #[serde(default)]
-    pub post_deletion_behaviour: PostDeletionBehaviour,
-    #[serde(default = "default_excluded_windows")]
-    pub excluded_windows: Vec,
-    #[serde(default)]
-    pub delete_instant_recordings_after_upload: bool,
-    #[serde(default = "default_instant_mode_max_resolution")]
-    pub instant_mode_max_resolution: u32,
-    #[serde(default)]
-    pub default_project_name_template: Option,
-    #[serde(default = "default_crash_recovery_recording")]
-    pub crash_recovery_recording: bool,
-    #[serde(default = "default_max_fps")]
-    pub max_fps: u32,
-    #[serde(default = "default_transcription_hints")]
-    pub transcription_hints: Vec,
-    #[serde(default)]
-    pub editor_preview_quality: EditorPreviewQuality,
-    #[serde(default)]
-    pub studio_recording_quality: StudioRecordingQuality,
-    #[serde(default)]
-    pub main_window_position: Option,
-    #[serde(default)]
-    pub camera_window_position: Option,
-    #[serde(default)]
-    pub camera_window_positions_by_monitor_name: BTreeMap,
-    #[serde(default = "default_true")]
-    pub has_completed_onboarding: bool,
-    #[serde(default = "default_true")]
-    pub enable_telemetry: bool,
-    #[serde(default)]
-    pub out_of_process_muxer: bool,
-    #[serde(default)]
-    pub recordings_path: Option,
-    /// Custom recordings folders that were used before; recordings left in
-    /// them stay visible in the library. Most recent last.
-    #[serde(default)]
-    pub previous_recordings_paths: Vec,
-    /// App version at which camera background blur was disabled after a crash
-    /// was attributed to the blur pipeline; `None` means blur is allowed.
-    /// Cleared automatically when the app version changes (one retry per
-    /// update, since a new ort/wgpu/driver stack may have fixed the crash).
-    #[serde(default)]
-    pub camera_blur_disabled_by_crash: Option,
-    #[serde(default)]
-    pub update_channel: UpdateChannel,
-    /// Run the experimental gpui-native app (`cap-gpui`) *instead of* this one:
-    /// while enabled, startup hands off to it and exits, and the native app's
-    /// own Experimental page hands back. See `gpui_app.rs`.
-    #[serde(default)]
-    pub enable_gpui_app: bool,
-}
-
-fn default_enable_native_camera_preview() -> bool {
-    false
-}
-
-fn no(_: &bool) -> bool {
-    false
-}
-
-fn default_true() -> bool {
-    true
-}
-
-fn default_instant_mode_max_resolution() -> u32 {
-    cap_recording::DEFAULT_INSTANT_MODE_MAX_RESOLUTION
-}
-
-fn default_max_fps() -> u32 {
-    cap_recording::DEFAULT_STUDIO_MAX_FPS
-}
-
-fn default_custom_cursor_capture() -> bool {
-    cap_recording::DEFAULT_CUSTOM_CURSOR_CAPTURE
-}
-
-fn default_capture_keyboard_events() -> bool {
-    cap_recording::DEFAULT_CAPTURE_KEYBOARD_EVENTS
-}
-
-fn default_crash_recovery_recording() -> bool {
-    cap_recording::DEFAULT_CRASH_RECOVERY_RECORDING
-}
-
-fn default_transcription_hints() -> Vec {
-    vec![
-        "Cap".to_string(),
-        "TypeScript".to_string(),
-        "My Brand Name".to_string(),
-        "mywebsite.com".to_string(),
-    ]
-}
-
-fn default_server_url() -> String {
-    std::option_env!("VITE_SERVER_URL")
-        .unwrap_or("https://cap.so")
-        .to_string()
-}
-
-#[derive(Serialize, Deserialize, Type, Debug, Clone)]
-#[serde(rename_all = "camelCase")]
-pub struct CommercialLicense {
-    license_key: String,
-    expiry_date: Option,
-    refresh: f64,
-    activated_on: f64,
-}
-
-impl Default for GeneralSettingsStore {
-    fn default() -> Self {
-        Self {
-            instance_id: uuid::Uuid::new_v4(),
-            upload_individual_files: false,
-            hide_dock_icon: false,
-            auto_create_shareable_link: false,
-            enable_notifications: true,
-            disable_auto_open_links: false,
-            has_completed_startup: false,
-            theme: AppTheme::System,
-            commercial_license: None,
-            last_version: None,
-            window_transparency: false,
-            post_studio_recording_behaviour: PostStudioRecordingBehaviour::OpenEditor,
-            main_window_recording_start_behaviour: MainWindowRecordingStartBehaviour::Close,
-            custom_cursor_capture: cap_recording::DEFAULT_CUSTOM_CURSOR_CAPTURE,
-            server_url: default_server_url(),
-            recording_countdown: Some(3),
-            enable_native_camera_preview: default_enable_native_camera_preview(),
-            // Keep aligned with the field's serde `default_true`: auto zooms
-            // are on by default, matching configs that never stored the key.
-            auto_zoom_on_clicks: true,
-            default_zoom_amount: None,
-            macbook_notch_overlay: None,
-            capture_keyboard_events: cap_recording::DEFAULT_CAPTURE_KEYBOARD_EVENTS,
-            post_deletion_behaviour: PostDeletionBehaviour::DoNothing,
-            excluded_windows: default_excluded_windows(),
-            delete_instant_recordings_after_upload: false,
-            instant_mode_max_resolution: cap_recording::DEFAULT_INSTANT_MODE_MAX_RESOLUTION,
-            default_project_name_template: None,
-            crash_recovery_recording: cap_recording::DEFAULT_CRASH_RECOVERY_RECORDING,
-            max_fps: cap_recording::DEFAULT_STUDIO_MAX_FPS,
-            transcription_hints: default_transcription_hints(),
-            editor_preview_quality: EditorPreviewQuality::Half,
-            studio_recording_quality: default_studio_recording_quality(),
-            main_window_position: None,
-            camera_window_position: None,
-            camera_window_positions_by_monitor_name: BTreeMap::new(),
-            has_completed_onboarding: false,
-            enable_telemetry: true,
-            out_of_process_muxer: cap_recording::DEFAULT_OUT_OF_PROCESS_MUXER,
-            recordings_path: None,
-            previous_recordings_paths: Vec::new(),
-            camera_blur_disabled_by_crash: None,
-            update_channel: UpdateChannel::Stable,
-            enable_gpui_app: false,
-        }
-    }
-}
-
-#[derive(Default, Debug, Copy, Clone, Serialize, Deserialize, Type)]
-#[serde(rename_all = "camelCase")]
-pub enum AppTheme {
-    #[default]
-    System,
-    Light,
-    Dark,
-}
-
-struct GeneralSettingsSnapshot {
-    original: Option,
-    settings: GeneralSettingsStore,
-    invalid_fields: Vec,
-}
-
-impl GeneralSettingsSnapshot {
-    fn load(original: Option) -> Result {
-        let Some(raw) = original.as_ref() else {
-            return Ok(Self {
-                original,
-                settings: GeneralSettingsStore::default(),
-                invalid_fields: Vec::new(),
-            });
-        };
-        if raw.is_object()
-            && let Ok(settings) = serde_json::from_value(raw.clone())
-        {
-            return Ok(Self {
-                original,
-                settings,
-                invalid_fields: Vec::new(),
-            });
-        }
-
-        let mut invalid_fields = Vec::new();
-        let settings = if let Some(fields) = raw.as_object() {
-            let mut recovered = fields.clone();
-            for (key, value) in fields {
-                let field = Value::Object([(key.clone(), value.clone())].into_iter().collect());
-                if serde_json::from_value::(field).is_err() {
-                    let _ = recovered.remove(key);
-                    invalid_fields.push(key.clone());
-                }
-            }
-            serde_json::from_value(Value::Object(recovered))
-                .map_err(|_| "Could not recover general settings fields".to_string())?
-        } else {
-            invalid_fields.push("general_settings".to_string());
-            GeneralSettingsStore::default()
-        };
-
-        Ok(Self {
-            original,
-            settings,
-            invalid_fields,
-        })
-    }
-
-    fn persist(
-        &self,
-        settings: &GeneralSettingsStore,
-        backup: impl FnOnce(&Value) -> Result<(), String>,
-        save: impl FnOnce(Value) -> Result<(), String>,
-    ) -> Result<(), String> {
-        let before = serde_json::to_value(&self.settings).map_err(|error| error.to_string())?;
-        let after = serde_json::to_value(settings).map_err(|error| error.to_string())?;
-        let mut original = self.original.clone().unwrap_or(Value::Null);
-        if let Some(fields) = original.as_object_mut() {
-            for key in &self.invalid_fields {
-                let _ = fields.remove(key);
-            }
-        }
-        let merged = merge_settings_changes(&original, &before, &after);
-
-        if !self.invalid_fields.is_empty()
-            && let Some(raw) = self.original.as_ref()
-        {
-            backup(raw)?;
-        }
-        save(merged)
-    }
-}
-
-fn merge_settings_changes(original: &Value, before: &Value, after: &Value) -> Value {
-    if let (Some(original), Some(before), Some(after)) =
-        (original.as_object(), before.as_object(), after.as_object())
-    {
-        let mut merged = original.clone();
-        for (key, value) in after {
-            let next = match (original.get(key), before.get(key)) {
-                (Some(original), Some(before)) if before == value => original.clone(),
-                (Some(original), Some(before)) => merge_settings_changes(original, before, value),
-                _ => value.clone(),
-            };
-            let _ = merged.insert(key.clone(), next);
-        }
-        for key in before.keys() {
-            if !after.contains_key(key) {
-                let _ = merged.remove(key);
-            }
-        }
-        Value::Object(merged)
-    } else if let (Some(original), Some(before), Some(after)) =
-        (original.as_array(), before.as_array(), after.as_array())
-    {
-        let mut used = vec![false; before.len()];
-        Value::Array(
-            after
-                .iter()
-                .map(|value| {
-                    let matching = before
-                        .iter()
-                        .enumerate()
-                        .find(|(index, previous)| !used[*index] && *previous == value);
-                    if let Some((index, _)) = matching {
-                        used[index] = true;
-                        original
-                            .get(index)
-                            .cloned()
-                            .unwrap_or_else(|| value.clone())
-                    } else {
-                        value.clone()
-                    }
-                })
-                .collect(),
-        )
-    } else {
-        after.clone()
-    }
-}
-
-fn backup_general_settings(directory: &Path, original: &Value) -> Result {
-    std::fs::create_dir_all(directory).map_err(|error| error.to_string())?;
-    let path = directory.join(format!("general-settings-recovery-{}.json", Uuid::new_v4()));
-    let mut options = std::fs::OpenOptions::new();
-    options.write(true).create_new(true);
-    #[cfg(unix)]
-    {
-        use std::os::unix::fs::OpenOptionsExt;
-        options.mode(0o600);
-    }
-    let mut file = options.open(&path).map_err(|error| error.to_string())?;
-    let bytes = serde_json::to_vec_pretty(original).map_err(|error| error.to_string())?;
-    file.write_all(&bytes).map_err(|error| error.to_string())?;
-    file.sync_all().map_err(|error| error.to_string())?;
-    Ok(path)
-}
-
-fn persist_general_settings(
-    app: &AppHandle,
-    store: &tauri_plugin_store::Store,
-    snapshot: &GeneralSettingsSnapshot,
-    settings: &GeneralSettingsStore,
-) -> Result<(), String> {
-    snapshot.persist(
-        settings,
-        |original| {
-            let directory = app
-                .path()
-                .app_data_dir()
-                .map_err(|error| error.to_string())?;
-            let path = backup_general_settings(&directory, original).map_err(|error| {
-                format!("Could not back up malformed general settings: {error}")
-            })?;
-            tracing::warn!(
-                fields = ?snapshot.invalid_fields,
-                backup = %path.display(),
-                "Recovered malformed general settings fields"
-            );
-            Ok(())
-        },
-        |value| {
-            store.set("general_settings", value);
-            store.save().map_err(|error| error.to_string())
-        },
-    )
-}
-
-impl GeneralSettingsStore {
-    pub fn recordings_dir(app: &AppHandle) -> std::path::PathBuf {
-        let custom = Self::get(app)
-            .map_err(|e| tracing::warn!("Failed to read general settings for recordings_dir: {e}"))
-            .ok()
-            .flatten()
-            .and_then(|s| s.recordings_path)
-            .and_then(|p| {
-                let path = std::path::PathBuf::from(&p);
-                if path.is_absolute() { Some(path) } else { None }
-            });
-
-        // A custom folder can become unavailable (unplugged drive, deleted
-        // path). Recording must keep working, so fall back to the default
-        // location instead of failing; the library lists recordings from
-        // every known folder, so nothing goes missing when this happens.
-        if let Some(path) = custom {
-            match std::fs::create_dir_all(&path) {
-                Ok(()) => return path,
-                Err(e) => {
-                    tracing::warn!(
-                        ?path, %e,
-                        "Custom recordings directory unavailable; falling back to default"
-                    );
-                }
-            }
-        }
-
-        let path = app.path().app_data_dir().unwrap().join("recordings");
-        if let Err(e) = std::fs::create_dir_all(&path) {
-            tracing::warn!(?path, %e, "Failed to create recordings directory");
-        }
-        path
-    }
-
-    // The effective value: the native preview is macOS-only; it is not
-    // reliable on Windows, so the stored setting is ignored there and the
-    // websocket preview is always used.
-    pub fn native_camera_preview_enabled(app: &AppHandle) -> bool {
-        if cfg!(not(target_os = "macos")) {
-            return false;
-        }
-        Self::get(app)
-            .ok()
-            .flatten()
-            .map(|settings| settings.enable_native_camera_preview)
-            .unwrap_or_else(default_enable_native_camera_preview)
-    }
-
-    pub fn get(app: &AppHandle) -> Result, String> {
-        match app.store("store").map(|s| s.get("general_settings")) {
-            Ok(Some(raw)) => {
-                GeneralSettingsSnapshot::load(Some(raw)).map(|snapshot| Some(snapshot.settings))
-            }
-            _ => Ok(None),
-        }
-    }
-
-    // i don't trust anyone to not overwrite the whole store lols
-    pub fn update(app: &AppHandle, update: impl FnOnce(&mut Self)) -> Result<(), String> {
-        let Ok(store) = app.store("store") else {
-            return Err("Store not found".to_string());
-        };
-
-        let snapshot = GeneralSettingsSnapshot::load(store.get("general_settings"))?;
-        let mut settings = snapshot.settings.clone();
-        update(&mut settings);
-        persist_general_settings(app, &store, &snapshot, &settings)?;
-
-        crate::telemetry::set_telemetry_enabled(settings.enable_telemetry);
-
-        #[cfg(target_os = "macos")]
-        crate::permissions::sync_macos_dock_visibility(app);
-
-        Ok(())
-    }
-
-    fn save(&self, app: &AppHandle) -> Result<(), String> {
-        let Ok(store) = app.store("store") else {
-            return Err("Store not found".to_string());
-        };
-
-        let snapshot = GeneralSettingsSnapshot::load(store.get("general_settings"))?;
-        persist_general_settings(app, &store, &snapshot, self)
-    }
-}
-
-#[cfg(target_os = "macos")]
-#[derive(Deserialize)]
-struct StoreChangePayload {
-    key: String,
-}
-
-#[cfg(target_os = "macos")]
-fn sync_dock_visibility_on_general_settings_change(app: &AppHandle) {
-    let app_for_listener = app.clone();
-    app.listen("store://change", move |event| {
-        let Ok(payload) = serde_json::from_str::(event.payload()) else {
-            return;
-        };
-
-        if payload.key == "general_settings" {
-            crate::permissions::schedule_macos_dock_visibility_sync(&app_for_listener);
-        }
-    });
-}
-
-/// Always false off macOS, so the overlay starts off and waits to be asked for.
-fn machine_has_notched_display() -> bool {
-    scap_targets::Display::list()
-        .iter()
-        .any(|display| display.notch().is_some())
-}
-
-pub fn init(app: &AppHandle) {
-    let mut store = match GeneralSettingsStore::get(app) {
-        Ok(Some(store)) => store,
-        Ok(None) => GeneralSettingsStore::default(),
-        Err(e) => {
-            error!("Failed to deserialize general settings store: {}", e);
-            GeneralSettingsStore::default()
-        }
-    };
-
-    append_missing_default_excluded_windows(&mut store.excluded_windows);
-
-    if store.macbook_notch_overlay.is_none() {
-        store.macbook_notch_overlay = Some(machine_has_notched_display());
-    }
-
-    const REMOVE_TARGET_SELECT_MIGRATION_KEY: &str = "remove_cap_target_select_exclusion_v1";
-    if let Ok(raw_store) = app.store("store")
-        && raw_store.get(REMOVE_TARGET_SELECT_MIGRATION_KEY).is_none()
-    {
-        store
-            .excluded_windows
-            .retain(|w| w.window_title.as_deref() != Some("Cap Target Select"));
-        raw_store.set(REMOVE_TARGET_SELECT_MIGRATION_KEY, json!(true));
-    }
-
-    crate::telemetry::set_telemetry_enabled(store.enable_telemetry);
-    register_bundled_muxer_binary(app);
-
-    #[cfg(target_os = "macos")]
-    {
-        const NATIVE_PREVIEW_MIGRATION_KEY: &str = "native_camera_preview_default_rollback_v1";
-        if let Ok(raw_store) = app.store("store")
-            && raw_store.get(NATIVE_PREVIEW_MIGRATION_KEY).is_none()
-        {
-            store.enable_native_camera_preview = false;
-            raw_store.set(NATIVE_PREVIEW_MIGRATION_KEY, json!(true));
-        }
-    }
-
-    if let Err(e) = store.save(app) {
-        error!("Failed to save general settings: {}", e);
-    }
-
-    #[cfg(target_os = "macos")]
-    sync_dock_visibility_on_general_settings_change(app);
-
-    #[cfg(target_os = "macos")]
-    crate::permissions::sync_macos_dock_visibility(app);
-}
-
-fn register_bundled_muxer_binary(_app: &AppHandle) {
-    if std::env::var_os(cap_recording::oop_muxer::ENV_BIN_PATH).is_some() {
-        return;
-    }
-
-    if let Ok(exe) = std::env::current_exe()
-        && let Some(dir) = exe.parent()
-    {
-        let candidate = dir.join(bundled_muxer_bin_name());
-        if candidate.is_file() {
-            match cap_recording::oop_muxer::set_muxer_binary_override(candidate.clone()) {
-                Ok(()) => {
-                    tracing::info!(
-                        path = %candidate.display(),
-                        "Registered executable-adjacent cap-muxer binary for out-of-process muxer"
-                    );
-                }
-                Err(existing) => {
-                    tracing::debug!(
-                        existing = %existing.display(),
-                        candidate = %candidate.display(),
-                        "cap-muxer override already registered; keeping existing"
-                    );
-                }
-            }
-        }
-    }
-}
-
-fn bundled_muxer_bin_name() -> &'static str {
-    if cfg!(windows) {
-        "cap-muxer.exe"
-    } else {
-        "cap-muxer"
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument]
-pub fn get_default_excluded_windows() -> Vec {
-    default_excluded_windows()
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    fn settings_with_preserved_values() -> Value {
-        json!({
-            "instanceId": "123e4567-e89b-42d3-a456-426614174000",
-            "commercialLicense": {
-                "licenseKey": "test-license",
-                "expiryDate": null,
-                "refresh": 123.0,
-                "activatedOn": 100.0,
-                "futureLicenseField": { "preserve": true }
-            },
-            "recordingsPath": "/Volumes/Test Recordings",
-            "previousRecordingsPaths": ["/Volumes/Previous"],
-            "theme": "dark",
-            "futureSetting": { "preserve": [1, 2, 3] },
-            "mainWindowPosition": { "x": 20.0, "y": 30.0, "futurePositionField": true },
-            "excludedWindows": [{ "windowTitle": "Custom", "futureExclusionField": true }]
-        })
-    }
-
-    #[test]
-    fn malformed_field_recovery_preserves_identity_license_paths_and_unknown_fields() {
-        let mut original = settings_with_preserved_values();
-        original["theme"] = json!({ "system": {}, "dark": {} });
-        original["maxFps"] = json!("invalid");
-        let snapshot = GeneralSettingsSnapshot::load(Some(original.clone())).unwrap();
-        assert_eq!(snapshot.invalid_fields, ["maxFps", "theme"]);
-        assert_eq!(
-            snapshot.settings.instance_id.to_string(),
-            original["instanceId"]
-        );
-        assert_eq!(
-            snapshot.settings.recordings_path.as_deref(),
-            original["recordingsPath"].as_str()
-        );
-        snapshot
-            .persist(
-                &snapshot.settings,
-                |backup| {
-                    assert_eq!(backup, &original);
-                    Ok(())
-                },
-                |saved| {
-                    for key in [
-                        "instanceId",
-                        "commercialLicense",
-                        "recordingsPath",
-                        "previousRecordingsPaths",
-                        "futureSetting",
-                        "mainWindowPosition",
-                        "excludedWindows",
-                    ] {
-                        assert_eq!(saved[key], original[key], "{key}");
-                    }
-                    assert_eq!(saved["theme"], "system");
-                    assert_eq!(saved["maxFps"], cap_recording::DEFAULT_STUDIO_MAX_FPS);
-                    assert!(serde_json::from_value::(saved).is_ok());
-                    Ok(())
-                },
-            )
-            .unwrap();
-    }
-
-    #[test]
-    fn settings_updates_preserve_unknown_nested_fields_and_unchanged_array_entries() {
-        let original = settings_with_preserved_values();
-        let snapshot = GeneralSettingsSnapshot::load(Some(original.clone())).unwrap();
-        let mut updated = snapshot.settings.clone();
-        updated.hide_dock_icon = true;
-        updated.main_window_position.as_mut().unwrap().x = 90.0;
-        updated.commercial_license.as_mut().unwrap().refresh = 456.0;
-        append_missing_default_excluded_windows(&mut updated.excluded_windows);
-        snapshot
-            .persist(
-                &updated,
-                |_| panic!("valid settings must not need recovery"),
-                |saved| {
-                    assert_eq!(saved["hideDockIcon"], true);
-                    assert_eq!(saved["mainWindowPosition"]["x"], 90.0);
-                    assert_eq!(saved["mainWindowPosition"]["futurePositionField"], true);
-                    assert_eq!(saved["commercialLicense"]["refresh"], 456.0);
-                    assert_eq!(
-                        saved["commercialLicense"]["futureLicenseField"],
-                        original["commercialLicense"]["futureLicenseField"]
-                    );
-                    assert_eq!(saved["futureSetting"], original["futureSetting"]);
-                    assert_eq!(saved["excludedWindows"][0], original["excludedWindows"][0]);
-                    Ok(())
-                },
-            )
-            .unwrap();
-    }
-
-    #[test]
-    fn healthy_settings_keep_existing_values_and_do_not_create_backups() {
-        let original = settings_with_preserved_values();
-        let snapshot = GeneralSettingsSnapshot::load(Some(original.clone())).unwrap();
-        snapshot
-            .persist(
-                &snapshot.settings,
-                |_| panic!("valid settings must not need recovery"),
-                |saved| {
-                    for (key, value) in original.as_object().unwrap() {
-                        assert_eq!(&saved[key], value, "{key}");
-                    }
-                    Ok(())
-                },
-            )
-            .unwrap();
-    }
-
-    #[test]
-    fn failed_backup_does_not_overwrite_malformed_section() {
-        let original = json!({ "theme": "future-theme", "recordingsPath": "/Volumes/Test" });
-        let snapshot = GeneralSettingsSnapshot::load(Some(original.clone())).unwrap();
-        let result = snapshot.persist(
-            &snapshot.settings,
-            |backup| {
-                assert_eq!(backup, &original);
-                Err("injected backup failure".into())
-            },
-            |_| panic!("the original section must survive a failed backup"),
-        );
-        assert_eq!(result.unwrap_err(), "injected backup failure");
-    }
-
-    #[test]
-    fn non_object_section_is_backed_up_before_recovery() {
-        let original = json!(["unreadable", 123]);
-        let snapshot = GeneralSettingsSnapshot::load(Some(original.clone())).unwrap();
-        let backed_up = std::cell::Cell::new(false);
-        snapshot
-            .persist(
-                &snapshot.settings,
-                |backup| {
-                    assert_eq!(backup, &original);
-                    backed_up.set(true);
-                    Ok(())
-                },
-                |saved| {
-                    assert!(backed_up.get());
-                    assert!(serde_json::from_value::(saved).is_ok());
-                    Ok(())
-                },
-            )
-            .unwrap();
-    }
-
-    #[test]
-    fn missing_section_keeps_new_install_defaults_without_recovery() {
-        let snapshot = GeneralSettingsSnapshot::load(None).unwrap();
-        assert!(!snapshot.settings.has_completed_onboarding);
-        assert!(!snapshot.settings.has_completed_startup);
-        assert_eq!(snapshot.settings.recording_countdown, Some(3));
-        snapshot
-            .persist(
-                &snapshot.settings,
-                |_| panic!("new settings must not need recovery"),
-                |saved| {
-                    assert_eq!(saved["hasCompletedOnboarding"], false);
-                    assert_eq!(saved["recordingCountdown"], 3);
-                    Ok(())
-                },
-            )
-            .unwrap();
-    }
-
-    #[test]
-    fn recovery_backups_are_exact_unique_and_private() {
-        let directory = tempfile::tempdir().unwrap();
-        let original = settings_with_preserved_values();
-        let first = backup_general_settings(directory.path(), &original).unwrap();
-        let second = backup_general_settings(directory.path(), &json!("another section")).unwrap();
-        assert_ne!(first, second);
-        let saved: Value = serde_json::from_slice(&std::fs::read(&first).unwrap()).unwrap();
-        assert_eq!(saved, original);
-        #[cfg(unix)]
-        {
-            use std::os::unix::fs::PermissionsExt;
-            assert_eq!(
-                std::fs::metadata(first).unwrap().permissions().mode() & 0o777,
-                0o600
-            );
-        }
-    }
-
-    #[test]
-    fn recovery_backup_reports_unwritable_destination() {
-        let directory = tempfile::tempdir().unwrap();
-        let blocker = directory.path().join("file");
-        std::fs::write(&blocker, "keep").unwrap();
-        assert!(backup_general_settings(&blocker, &json!({ "theme": [] })).is_err());
-        assert_eq!(std::fs::read_to_string(blocker).unwrap(), "keep");
-    }
-
-    fn title_exclusion(title: &str) -> WindowExclusion {
-        WindowExclusion {
-            bundle_identifier: None,
-            owner_name: None,
-            window_title: Some(title.to_string()),
-        }
-    }
-
-    #[test]
-    fn appends_missing_default_excluded_windows() {
-        let mut excluded_windows = vec![
-            title_exclusion("Cap"),
-            WindowExclusion {
-                bundle_identifier: None,
-                owner_name: Some("Preview".to_string()),
-                window_title: Some("Private Preview".to_string()),
-            },
-        ];
-
-        let changed = append_missing_default_excluded_windows(&mut excluded_windows);
-
-        assert!(changed);
-        assert!(
-            default_excluded_windows()
-                .iter()
-                .all(|default| excluded_windows.contains(default))
-        );
-        assert!(excluded_windows.iter().any(|entry| {
-            entry.owner_name.as_deref() == Some("Preview")
-                && entry.window_title.as_deref() == Some("Private Preview")
-        }));
-    }
-
-    #[test]
-    fn does_not_duplicate_default_excluded_windows() {
-        let mut excluded_windows = default_excluded_windows();
-        let len = excluded_windows.len();
-
-        let changed = append_missing_default_excluded_windows(&mut excluded_windows);
-
-        assert!(!changed);
-        assert_eq!(excluded_windows.len(), len);
-    }
-}
diff --git a/apps/desktop/src-tauri/src/gpu_context.rs b/apps/desktop/src-tauri/src/gpu_context.rs
deleted file mode 100644
index 9472df5d298..00000000000
--- a/apps/desktop/src-tauri/src/gpu_context.rs
+++ /dev/null
@@ -1,206 +0,0 @@
-use std::{
-    collections::HashMap,
-    sync::{Arc, RwLock},
-    time::Instant,
-};
-use tokio::sync::OnceCell;
-
-#[derive(Clone)]
-pub struct PendingScreenshot {
-    pub data: Vec,
-    pub width: u32,
-    pub height: u32,
-    pub channels: u32,
-    pub created_at: Instant,
-}
-
-pub struct PendingScreenshots(pub Arc>>);
-
-impl Default for PendingScreenshots {
-    fn default() -> Self {
-        Self(Arc::new(RwLock::new(HashMap::new())))
-    }
-}
-
-impl PendingScreenshots {
-    pub fn insert(&self, key: String, screenshot: PendingScreenshot) {
-        let mut guard = self.0.write().unwrap();
-        guard.retain(|_, v| v.created_at.elapsed() < std::time::Duration::from_secs(10));
-        guard.insert(key, screenshot);
-    }
-
-    pub fn remove(&self, key: &str) -> Option {
-        self.0.write().unwrap().remove(key)
-    }
-
-    pub fn get(&self, key: &str) -> Option {
-        self.0.read().unwrap().get(key).cloned()
-    }
-}
-
-pub struct SharedGpuContext {
-    health: crate::gpu_device_health::GpuDeviceHealth,
-    pub device: Arc,
-    pub queue: Arc,
-    pub adapter: Arc,
-    pub instance: Arc,
-    pub is_software_adapter: bool,
-    pub background_cache: Arc,
-}
-
-static GPU: OnceCell> = OnceCell::const_new();
-
-/// Marks the crash sentinel while GPU adapter/device initialisation is in flight, so
-/// a process death inside that window is attributable to graphics bring-up. Dropping
-/// the guard (including during unwind from a caught panic) disarms the marker — a
-/// survivable failure is not a GPU crash.
-struct GpuInitPhaseGuard;
-
-impl GpuInitPhaseGuard {
-    fn arm() -> Self {
-        crate::crash_sentinel::enter_gpu_init_phase();
-        Self
-    }
-}
-
-impl Drop for GpuInitPhaseGuard {
-    fn drop(&mut self) {
-        crate::crash_sentinel::exit_gpu_init_phase();
-    }
-}
-
-async fn init_gpu_inner() -> Option {
-    let _gpu_init_phase = GpuInitPhaseGuard::arm();
-
-    let instance = cap_rendering::create_wgpu_instance().await;
-
-    let force_software_adapter = cap_rendering::force_software_wgpu_adapter();
-    if force_software_adapter {
-        tracing::warn!("Forcing software WGPU adapter for shared context");
-    }
-
-    let hardware_adapter = if force_software_adapter {
-        None
-    } else {
-        instance
-            .request_adapter(&wgpu::RequestAdapterOptions {
-                power_preference: wgpu::PowerPreference::HighPerformance,
-                force_fallback_adapter: false,
-                compatible_surface: None,
-            })
-            .await
-            .ok()
-    };
-
-    let (adapter, is_software_adapter) = if let Some(adapter) = hardware_adapter {
-        let adapter_info = adapter.get_info();
-        let is_software_adapter = cap_rendering::is_software_wgpu_adapter(&adapter_info);
-
-        if is_software_adapter {
-            tracing::warn!(
-                adapter_name = adapter_info.name,
-                adapter_backend = ?adapter_info.backend,
-                adapter_device_type = ?adapter_info.device_type,
-                "Selected shared-context adapter behaves like a software renderer"
-            );
-        } else {
-            tracing::info!(
-                adapter_name = adapter_info.name,
-                adapter_backend = ?adapter_info.backend,
-                adapter_device_type = ?adapter_info.device_type,
-                "Using hardware GPU adapter for shared context"
-            );
-        }
-
-        (adapter, is_software_adapter)
-    } else {
-        tracing::warn!(
-            "No hardware GPU adapter found, attempting software fallback for shared context"
-        );
-        let software_adapter = instance
-            .request_adapter(&wgpu::RequestAdapterOptions {
-                power_preference: wgpu::PowerPreference::LowPower,
-                force_fallback_adapter: true,
-                compatible_surface: None,
-            })
-            .await
-            .ok()?;
-
-        let adapter_info = software_adapter.get_info();
-
-        tracing::info!(
-            adapter_name = adapter_info.name,
-            adapter_backend = ?adapter_info.backend,
-            adapter_device_type = ?adapter_info.device_type,
-            "Using software adapter for shared context (CPU rendering - performance may be reduced)"
-        );
-        (software_adapter, true)
-    };
-
-    let (device, queue) = adapter
-        .request_device(&wgpu::DeviceDescriptor {
-            label: Some("cap-shared-gpu-device"),
-            required_features: wgpu::Features::empty(),
-            ..Default::default()
-        })
-        .await
-        .ok()?;
-
-    let health = crate::gpu_device_health::GpuDeviceHealth::track(&device, |reason, message| {
-        tracing::error!(?reason, %message, "Shared GPU device lost");
-        if reason == wgpu::DeviceLostReason::Unknown {
-            sentry::capture_message("Shared GPU device lost", sentry::Level::Error);
-        }
-    });
-
-    Some(SharedGpuContext {
-        health,
-        device: Arc::new(device),
-        queue: Arc::new(queue),
-        adapter: Arc::new(adapter),
-        instance: Arc::new(instance),
-        is_software_adapter,
-        background_cache: Arc::new(cap_rendering::BackgroundTextureCache::default()),
-    })
-}
-
-pub async fn get_shared_gpu() -> Option<&'static SharedGpuContext> {
-    GPU.get_or_init(|| async {
-        let result = tokio::spawn(init_gpu_inner()).await;
-
-        match result {
-            Ok(ctx) => ctx,
-            Err(e) => {
-                if e.is_panic() {
-                    tracing::error!(
-                        "GPU initialization panicked (wgpu internal error). \
-                         The app will continue without GPU acceleration."
-                    );
-                } else {
-                    tracing::error!(
-                        error = %e,
-                        "GPU initialization task failed"
-                    );
-                }
-                None
-            }
-        }
-    })
-    .await
-    .as_ref()
-}
-
-pub fn prewarm_gpu() {
-    tokio::spawn(async {
-        get_shared_gpu().await;
-    });
-}
-
-// Every Tauri video editor uses this OnceCell's device when initialization succeeds.
-// Its resources cannot recover by reopening the editor or replacing only the device.
-pub fn ensure_shared_device_available() -> Result<(), String> {
-    if let Some(Some(gpu)) = GPU.get() {
-        gpu.health.ensure_available().map_err(str::to_string)?;
-    }
-    Ok(())
-}
diff --git a/apps/desktop/src-tauri/src/gpu_device_health.rs b/apps/desktop/src-tauri/src/gpu_device_health.rs
deleted file mode 100644
index 382faaa7b0a..00000000000
--- a/apps/desktop/src-tauri/src/gpu_device_health.rs
+++ /dev/null
@@ -1,119 +0,0 @@
-use std::sync::{
-    Arc,
-    atomic::{AtomicBool, Ordering},
-};
-
-#[derive(Clone)]
-pub struct GpuDeviceHealth {
-    lost: Arc,
-}
-
-impl GpuDeviceHealth {
-    pub fn track(
-        device: &wgpu::Device,
-        on_lost: impl Fn(wgpu::DeviceLostReason, String) + Send + 'static,
-    ) -> Self {
-        let lost = Arc::new(AtomicBool::new(false));
-        let callback_lost = lost.clone();
-        device.set_device_lost_callback(move |reason, message| {
-            callback_lost.store(true, Ordering::Release);
-            on_lost(reason, message);
-        });
-        Self { lost }
-    }
-
-    pub fn ensure_available(&self) -> Result<(), &'static str> {
-        if self.lost.load(Ordering::Acquire) {
-            return Err("The graphics device was lost. Restart Cap to generate an export preview.");
-        }
-        Ok(())
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use std::sync::atomic::AtomicUsize;
-
-    fn device() -> (wgpu::Device, wgpu::Queue) {
-        wgpu::Device::noop(&wgpu::DeviceDescriptor::default())
-    }
-
-    fn preview_pipeline(
-        health: &GpuDeviceHealth,
-        device: &wgpu::Device,
-    ) -> Result {
-        health.ensure_available()?;
-        Ok(device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor::default()))
-    }
-
-    #[test]
-    fn unguarded_repeated_previews_panic_after_device_loss() {
-        let (device, _queue) = device();
-        device.destroy();
-        device.poll(wgpu::PollType::Poll).unwrap();
-
-        for _ in 0..9 {
-            let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
-                device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
-                    label: Some("NV12 Converter Pipeline Layout"),
-                    ..Default::default()
-                })
-            }));
-            assert!(result.is_err());
-        }
-    }
-
-    #[test]
-    fn repeated_previews_reject_a_lost_device_and_its_clones() {
-        let (device, _queue) = device();
-        let reports = Arc::new(AtomicUsize::new(0));
-        let callback_reports = reports.clone();
-        let health = GpuDeviceHealth::track(&device, move |_, _| {
-            callback_reports.fetch_add(1, Ordering::Relaxed);
-        });
-        let editor_device = device.clone();
-        let editor_health = health.clone();
-        let _retained_pipeline = preview_pipeline(&editor_health, &editor_device).unwrap();
-
-        device.destroy();
-        device.poll(wgpu::PollType::Poll).unwrap();
-
-        for _ in 0..9 {
-            assert_eq!(
-                preview_pipeline(&editor_health, &editor_device).unwrap_err(),
-                "The graphics device was lost. Restart Cap to generate an export preview."
-            );
-        }
-        assert_eq!(reports.load(Ordering::Relaxed), 1);
-    }
-
-    #[test]
-    fn loss_does_not_disable_an_independent_device() {
-        let (lost_device, _lost_queue) = device();
-        let health = GpuDeviceHealth::track(&lost_device, |_, _| {});
-        lost_device.destroy();
-        lost_device.poll(wgpu::PollType::Poll).unwrap();
-
-        let (independent_device, _queue) = device();
-        let independent_health = GpuDeviceHealth::track(&independent_device, |_, _| {});
-        preview_pipeline(&independent_health, &independent_device).unwrap();
-        assert!(preview_pipeline(&health, &lost_device).is_err());
-    }
-
-    #[test]
-    fn healthy_device_validation_errors_still_panic() {
-        let (device, _queue) = device();
-        let health = GpuDeviceHealth::track(&device, |_, _| {});
-        health.ensure_available().unwrap();
-
-        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
-            device.create_shader_module(wgpu::ShaderModuleDescriptor {
-                label: Some("invalid synthetic shader"),
-                source: wgpu::ShaderSource::Wgsl("invalid wgsl".into()),
-            })
-        }));
-        assert!(result.is_err());
-        health.ensure_available().unwrap();
-    }
-}
diff --git a/apps/desktop/src-tauri/src/gpui_app.rs b/apps/desktop/src-tauri/src/gpui_app.rs
deleted file mode 100644
index 89cba6c70af..00000000000
--- a/apps/desktop/src-tauri/src/gpui_app.rs
+++ /dev/null
@@ -1,1545 +0,0 @@
-//! Handing this app off to the experimental gpui-native app (`cap-gpui`).
-//!
-//! The two apps already share one settings store and recordings library
-//! (`apps/desktop-gpui/src/store.rs` reads this app's), so the `enable_gpui_app`
-//! setting is not "run both": whichever app is enabled owns the session. Turning
-//! it on spawns `cap-gpui` and exits this app; turning it off inside `cap-gpui`
-//! reopens this one. Startup honours the same flag, so the handoff survives a
-//! relaunch.
-//!
-//! The binary is discovered in order: `CAP_GPUI_BIN` (explicit override), the
-//! installed executable directory (where Tauri bundles and signs sidecars), the
-//! legacy `gpui/` resource dir, and -- in debug builds only -- the sibling
-//! `apps/desktop-gpui` target dir, so the toggle works from a source checkout.
-//!
-//! ## The handoff marker
-//!
-//! A handoff that spawns a `cap-gpui` which then dies immediately would leave
-//! the user with no app at all, and with a setting that keeps redirecting away
-//! from the app that does work. So this side writes `cap-gpui.handoff` next to
-//! the shared store before spawning, and `cap-gpui` deletes it only on clean
-//! shutdown. With no live GPUI process, a surviving marker means the previous
-//! session exited unexpectedly: clear the flag, tell the user, and start normally.
-
-use std::path::PathBuf;
-
-use tauri::{AppHandle, Manager};
-use tauri_plugin_dialog::DialogExt;
-use tracing::{info, warn};
-
-use crate::general_settings::GeneralSettingsStore;
-
-#[cfg(windows)]
-const BINARY_NAME: &str = "cap-gpui.exe";
-#[cfg(not(windows))]
-const BINARY_NAME: &str = "cap-gpui";
-
-#[cfg(any(target_os = "macos", windows, test))]
-const MAX_FORWARDED_DEEP_LINK_BYTES: usize = 1024 * 1024;
-
-#[cfg(any(target_os = "macos", windows, test))]
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-struct GpuiForwardingEndpoint {
-    pid: u32,
-    port: u16,
-    secret: u64,
-}
-
-#[cfg(any(target_os = "macos", test))]
-#[derive(Default)]
-pub(crate) struct StartupRedirectState {
-    phase: std::sync::atomic::AtomicU8,
-    reopen_pid: Option,
-}
-
-#[cfg(any(target_os = "macos", test))]
-impl StartupRedirectState {
-    fn with_reopen(pid: u32) -> Self {
-        Self {
-            reopen_pid: Some(pid),
-            ..Self::default()
-        }
-    }
-
-    pub(crate) fn begin_forwarding(&self) -> bool {
-        self.transition(0, 1)
-    }
-
-    pub(crate) fn exit_if_pending(&self) -> Option> {
-        self.transition(0, 2).then_some(self.reopen_pid)
-    }
-
-    pub(crate) fn exit_after_forwarding(&self) -> bool {
-        self.transition(1, 2)
-    }
-
-    fn transition(&self, from: u8, to: u8) -> bool {
-        self.phase
-            .compare_exchange(
-                from,
-                to,
-                std::sync::atomic::Ordering::AcqRel,
-                std::sync::atomic::Ordering::Acquire,
-            )
-            .is_ok()
-    }
-}
-
-fn existing_file(path: PathBuf) -> Option {
-    path.is_file().then_some(path)
-}
-
-fn binary_path(app: &AppHandle) -> Option {
-    if let Some(path) = std::env::var_os("CAP_GPUI_BIN").map(PathBuf::from)
-        && path.is_file()
-    {
-        return Some(path);
-    }
-
-    if let Ok(executable) = std::env::current_exe()
-        && let Some(parent) = executable.parent()
-        && let Some(path) = existing_file(parent.join(BINARY_NAME))
-    {
-        return Some(path);
-    }
-
-    if let Ok(resources) = app.path().resource_dir()
-        && let Some(path) = existing_file(resources.join("gpui").join(BINARY_NAME))
-    {
-        return Some(path);
-    }
-
-    #[cfg(debug_assertions)]
-    {
-        // Whichever profile was built most recently: a fixed preference here
-        // hands off to a days-old binary the moment the other profile is the
-        // one being actively rebuilt.
-        let target =
-            std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../../desktop-gpui/target");
-        let newest = ["release", "debug"]
-            .into_iter()
-            .filter_map(|profile| {
-                let path = target.join(profile).join(BINARY_NAME);
-                let modified = std::fs::metadata(&path).ok()?.modified().ok()?;
-                Some((modified, path))
-            })
-            .max_by_key(|(modified, _)| *modified)
-            .map(|(_, path)| path);
-        if newest.is_some() {
-            return newest;
-        }
-    }
-
-    None
-}
-
-/// Mirror of `store::app_data_dir` in `apps/desktop-gpui`: the pidfile and the
-/// handoff marker live under the shared production identifier
-/// (`so.cap.desktop`), not this app's possibly-`.dev` one.
-fn shared_data_dir() -> PathBuf {
-    #[cfg(target_os = "macos")]
-    let base = PathBuf::from(std::env::var("HOME").unwrap_or_else(|_| ".".into()))
-        .join("Library/Application Support/so.cap.desktop");
-    #[cfg(target_os = "windows")]
-    let base = std::env::var_os("APPDATA")
-        .map(PathBuf::from)
-        .unwrap_or_else(|| PathBuf::from("."))
-        .join("so.cap.desktop");
-    #[cfg(all(not(target_os = "macos"), not(target_os = "windows")))]
-    let base = std::env::var_os("XDG_DATA_HOME")
-        .map(PathBuf::from)
-        .unwrap_or_else(|| {
-            PathBuf::from(std::env::var_os("HOME").unwrap_or_else(|| ".".into()))
-                .join(".local/share")
-        })
-        .join("so.cap.desktop");
-    base
-}
-
-fn gpui_pidfile() -> PathBuf {
-    shared_data_dir().join("cap-gpui.pid")
-}
-
-/// Whether this app's own store IS the shared one. It is for the production
-/// bundle (`so.cap.desktop`), but a dev build stores under a `.dev` identifier
-/// while `cap-gpui` always reads and writes the shared file -- two stores that
-/// silently disagree. The handoff flag therefore lives in the shared store,
-/// and this app's own copy of the setting is just what its settings page
-/// displays.
-fn own_store_is_shared(app: &AppHandle) -> bool {
-    app.path()
-        .app_data_dir()
-        .is_ok_and(|dir| dir == shared_data_dir())
-}
-
-fn shared_store_path() -> PathBuf {
-    // The store plugin's file for the production identifier -- the same file
-    // `store::set_store_setting` in apps/desktop-gpui operates on.
-    shared_data_dir().join("store")
-}
-
-fn shared_store_flag() -> Option {
-    let raw = std::fs::read_to_string(shared_store_path()).ok()?;
-    let doc: serde_json::Value = serde_json::from_str(&raw).ok()?;
-    doc.get("general_settings")?.get("enableGpuiApp")?.as_bool()
-}
-
-/// Single-key replace with everything else preserved, temp+rename atomic --
-/// the same contract as the gpui app's `set_store_setting`. A missing file is
-/// created with just this key; an unparseable one is refused rather than
-/// replaced. Only ever called when the shared store is NOT this app's own
-/// (`own_store_is_shared` false): writing the file directly under the store
-/// plugin's feet would race its in-memory copy.
-fn write_shared_store_flag(value: bool) {
-    let path = shared_store_path();
-    let mut doc = match std::fs::read_to_string(&path) {
-        Ok(raw) => match serde_json::from_str::(&raw) {
-            Ok(doc) => doc,
-            Err(error) => {
-                warn!(%error, "shared store is unparseable; leaving it untouched");
-                return;
-            }
-        },
-        Err(error) if error.kind() == std::io::ErrorKind::NotFound => serde_json::json!({}),
-        Err(error) => {
-            warn!(%error, "could not read the shared store");
-            return;
-        }
-    };
-    let Some(root) = doc.as_object_mut() else {
-        warn!("shared store is not a JSON object; leaving it untouched");
-        return;
-    };
-    root.entry("general_settings")
-        .or_insert_with(|| serde_json::json!({}))
-        .as_object_mut()
-        .map(|section| section.insert("enableGpuiApp".into(), serde_json::Value::Bool(value)));
-    let pretty = serde_json::to_string_pretty(&doc).unwrap_or_else(|_| doc.to_string());
-    let tmp = path.with_extension("tmp");
-    let write = std::fs::create_dir_all(path.parent().unwrap_or(&path))
-        .and_then(|()| std::fs::write(&tmp, pretty))
-        .and_then(|()| std::fs::rename(&tmp, &path));
-    if let Err(error) = write {
-        warn!(%error, "could not write the shared store flag");
-    }
-}
-
-fn handoff_marker() -> PathBuf {
-    shared_data_dir().join("cap-gpui.handoff")
-}
-
-fn update_handoff_marker() -> PathBuf {
-    shared_data_dir().join("cap-gpui.update-handoff")
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-struct UpdateHandoff {
-    pid: u32,
-    simulated: bool,
-}
-
-fn parse_update_handoff(contents: &str) -> Option {
-    let contents = contents.trim();
-    let (pid, simulated) = match contents.strip_prefix("simulate:") {
-        Some(pid) if cfg!(debug_assertions) => (pid, true),
-        Some(_) => return None,
-        None => (contents, false),
-    };
-    let pid = pid.parse().ok()?;
-    (pid != 0).then_some(UpdateHandoff { pid, simulated })
-}
-
-fn take_update_handoff() -> Option {
-    let marker = update_handoff_marker();
-    let contents = match std::fs::read_to_string(&marker) {
-        Ok(contents) => contents,
-        Err(error) if error.kind() == std::io::ErrorKind::NotFound => return None,
-        Err(error) => {
-            warn!(%error, "could not read the Cap GPUI update hand-off");
-            return None;
-        }
-    };
-
-    let Some(handoff) = parse_update_handoff(&contents) else {
-        warn!("discarding an invalid Cap GPUI update hand-off");
-        let _ = std::fs::remove_file(&marker);
-        return None;
-    };
-
-    let expected_pid = std::fs::read_to_string(gpui_pidfile())
-        .ok()
-        .and_then(|contents| contents.trim().parse::().ok());
-    let stale = marker
-        .metadata()
-        .ok()
-        .and_then(|metadata| metadata.modified().ok())
-        .and_then(|modified| modified.elapsed().ok())
-        .is_some_and(|age| age > std::time::Duration::from_secs(15 * 60));
-    if expected_pid.is_some_and(|pid| pid != handoff.pid) || stale {
-        warn!(
-            pid = handoff.pid,
-            "discarding a stale Cap GPUI update hand-off"
-        );
-        let _ = std::fs::remove_file(&marker);
-        return None;
-    }
-
-    match std::fs::remove_file(&marker) {
-        Ok(()) => {
-            info!(
-                pid = handoff.pid,
-                "taking ownership from Cap GPUI for an update check"
-            );
-            Some(handoff.simulated)
-        }
-        Err(error) if error.kind() == std::io::ErrorKind::NotFound => None,
-        Err(error) => {
-            warn!(%error, "could not consume the Cap GPUI update hand-off");
-            None
-        }
-    }
-}
-
-fn show_update_page_when_ready(app: AppHandle, simulated: bool) {
-    tauri::async_runtime::spawn(async move {
-        for _ in 0..300 {
-            if let Some(window) = app
-                .get_webview_window("main")
-                .or_else(|| app.get_webview_window("onboarding"))
-            {
-                match window.url() {
-                    Ok(mut url) => {
-                        url.set_path("/update");
-                        url.set_query(Some(if simulated {
-                            "source=gpui&simulateUpdate=1"
-                        } else {
-                            "source=gpui"
-                        }));
-                        if let Err(error) = window.navigate(url) {
-                            warn!(%error, "could not open the updater after the GPUI hand-off");
-                        } else {
-                            let _ = window.show();
-                            let _ = window.set_focus();
-                        }
-                    }
-                    Err(error) => {
-                        warn!(%error, "could not read the window URL for the GPUI updater");
-                    }
-                }
-                return;
-            }
-            tokio::time::sleep(std::time::Duration::from_millis(100)).await;
-        }
-        warn!("no window became ready for the GPUI update hand-off");
-    });
-}
-
-pub(crate) fn handle_update_handoff(app: &AppHandle) -> bool {
-    let Some(simulated) = take_update_handoff() else {
-        return false;
-    };
-    show_update_page_when_ready(app.clone(), simulated);
-    true
-}
-
-fn classic_pending() -> PathBuf {
-    shared_data_dir().join("cap-classic.pending")
-}
-
-/// The pid of the live `cap-gpui` that owns the pidfile, if there is one.
-fn running_instance_pid() -> Option {
-    let pid = std::fs::read_to_string(gpui_pidfile())
-        .ok()?
-        .trim()
-        .parse::()
-        .ok()?;
-
-    #[cfg(target_os = "linux")]
-    {
-        linux_gpui_process_is_running(pid).then_some(pid)
-    }
-
-    #[cfg(all(unix, not(target_os = "linux")))]
-    {
-        let alive = std::process::Command::new("ps")
-            .args(["-p", &pid.to_string(), "-o", "comm="])
-            .output()
-            .is_ok_and(|output| {
-                output.status.success()
-                    && is_gpui_process_image(std::path::Path::new(
-                        String::from_utf8_lossy(&output.stdout).trim(),
-                    ))
-            });
-        alive.then_some(pid)
-    }
-
-    #[cfg(windows)]
-    {
-        let process_id = sysinfo::Pid::from_u32(pid);
-        let mut system = sysinfo::System::new();
-        system.refresh_processes(sysinfo::ProcessesToUpdate::Some(&[process_id]), true);
-        system
-            .process(process_id)
-            .and_then(sysinfo::Process::exe)
-            .is_some_and(is_gpui_process_image)
-            .then_some(pid)
-    }
-}
-
-#[cfg(target_os = "linux")]
-fn linux_gpui_process_is_running(pid: u32) -> bool {
-    std::fs::read_link(format!("/proc/{pid}/exe")).is_ok_and(|path| is_gpui_process_image(&path))
-}
-
-fn is_gpui_process_image(path: &std::path::Path) -> bool {
-    let Some(name) = path.file_name().and_then(std::ffi::OsStr::to_str) else {
-        return false;
-    };
-    #[cfg(target_os = "linux")]
-    let name = name.strip_suffix(" (deleted)").unwrap_or(name);
-    name.eq_ignore_ascii_case(BINARY_NAME)
-}
-
-#[cfg(any(target_os = "macos", windows, test))]
-fn parse_gpui_forwarding_endpoint(contents: &str) -> Option {
-    let mut parts = contents.trim().split(':');
-    let pid = parts.next()?.parse().ok()?;
-    let port = parts.next()?.parse().ok()?;
-    let secret = u64::from_str_radix(parts.next()?, 16).ok()?;
-    (pid != 0 && port != 0 && parts.next().is_none()).then_some(GpuiForwardingEndpoint {
-        pid,
-        port,
-        secret,
-    })
-}
-
-#[cfg(any(target_os = "macos", windows, test))]
-fn is_forwardable_gpui_deep_link(url: &str) -> bool {
-    !url.is_empty()
-        && url.len() <= MAX_FORWARDED_DEEP_LINK_BYTES
-        && reqwest::Url::parse(url)
-            .is_ok_and(|parsed| matches!(parsed.scheme(), "cap-desktop" | "cap"))
-}
-
-#[cfg(any(target_os = "macos", windows, test))]
-fn forwarded_gpui_argument(argument: &str) -> Option {
-    if is_forwardable_gpui_deep_link(argument) {
-        return Some(argument.to_string());
-    }
-
-    let path = match reqwest::Url::parse(argument) {
-        Ok(url) if url.scheme() == "file" => url.to_file_path().ok()?,
-        _ => PathBuf::from(argument),
-    };
-    if !path
-        .extension()
-        .and_then(std::ffi::OsStr::to_str)
-        .is_some_and(|extension| extension.eq_ignore_ascii_case("cap"))
-    {
-        return None;
-    }
-
-    let metadata = std::fs::symlink_metadata(&path).ok()?;
-    if metadata.file_type().is_symlink() || !metadata.is_dir() {
-        return None;
-    }
-    let path = path.canonicalize().ok()?;
-    let value = serde_json::json!({ "open_editor": { "project_path": path } }).to_string();
-    let mut url = reqwest::Url::parse("cap-desktop://action").ok()?;
-    url.query_pairs_mut().append_pair("value", &value);
-    let url = url.to_string();
-    is_forwardable_gpui_deep_link(&url).then_some(url)
-}
-
-#[cfg(target_os = "macos")]
-fn read_macos_gpui_metadata(path: &std::path::Path, private: bool) -> std::io::Result {
-    use nix::libc;
-    use std::{
-        io::Read,
-        os::unix::fs::{MetadataExt, OpenOptionsExt},
-    };
-
-    let file = std::fs::OpenOptions::new()
-        .read(true)
-        .custom_flags(libc::O_NOFOLLOW | libc::O_NONBLOCK | libc::O_CLOEXEC)
-        .open(path)?;
-    let metadata = file.metadata()?;
-    let forbidden_permissions = if private { 0o077 } else { 0o022 };
-    if !metadata.is_file()
-        || metadata.len() > 128
-        || metadata.nlink() != 1
-        || metadata.uid() != unsafe { libc::geteuid() }
-        || metadata.mode() & forbidden_permissions != 0
-    {
-        return Err(std::io::Error::new(
-            std::io::ErrorKind::PermissionDenied,
-            "Cap GPUI instance metadata is not owner controlled",
-        ));
-    }
-    let mut contents = String::new();
-    file.take(129).read_to_string(&mut contents)?;
-    if contents.len() > 128 {
-        return Err(std::io::Error::new(
-            std::io::ErrorKind::InvalidData,
-            "Cap GPUI instance metadata changed",
-        ));
-    }
-    Ok(contents)
-}
-
-#[cfg(target_os = "macos")]
-fn macos_reopen_incumbent(path: &std::path::Path, pid: u32) -> std::io::Result {
-    use nix::libc;
-    use std::os::unix::ffi::OsStrExt;
-
-    if pid == 0
-        || pid > i32::MAX as u32
-        || pid == std::process::id()
-        || read_macos_gpui_metadata(path, false)?
-            .trim()
-            .parse::()
-            .ok()
-            != Some(pid)
-    {
-        return Ok(false);
-    }
-    let mut buffer = [0_u8; libc::PROC_PIDPATHINFO_MAXSIZE as usize];
-    let length =
-        unsafe { libc::proc_pidpath(pid as i32, buffer.as_mut_ptr().cast(), buffer.len() as u32) };
-    Ok(length > 0
-        && buffer.split(|byte| *byte == 0).next().is_some_and(|bytes| {
-            is_gpui_process_image(std::path::Path::new(std::ffi::OsStr::from_bytes(bytes)))
-        }))
-}
-
-#[cfg(any(target_os = "macos", windows))]
-fn reopen_time_remaining(
-    started: std::time::Instant,
-    timeout: std::time::Duration,
-) -> std::io::Result {
-    timeout
-        .checked_sub(started.elapsed())
-        .filter(|remaining| !remaining.is_zero())
-        .ok_or_else(|| {
-            std::io::Error::new(
-                std::io::ErrorKind::TimedOut,
-                "Cap GPUI reopen request timed out",
-            )
-        })
-}
-
-#[cfg(any(target_os = "macos", windows))]
-fn send_gpui_reopen(
-    endpoint: GpuiForwardingEndpoint,
-    started: std::time::Instant,
-    timeout: std::time::Duration,
-) -> std::io::Result<()> {
-    use std::io::{Read, Write};
-
-    let address = std::net::SocketAddr::from((std::net::Ipv4Addr::LOCALHOST, endpoint.port));
-    let mut stream =
-        std::net::TcpStream::connect_timeout(&address, reopen_time_remaining(started, timeout)?)?;
-    stream.set_nonblocking(true)?;
-    let mut payload = [0_u8; 12];
-    payload[..8].copy_from_slice(&endpoint.secret.to_be_bytes());
-    let mut pending = payload.as_slice();
-    while !pending.is_empty() {
-        let remaining = reopen_time_remaining(started, timeout)?;
-        match stream.write(pending) {
-            Ok(0) => {
-                return Err(std::io::Error::new(
-                    std::io::ErrorKind::WriteZero,
-                    "Cap GPUI closed its forwarding connection",
-                ));
-            }
-            Ok(written) => pending = &pending[written..],
-            Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => {
-                std::thread::sleep(remaining.min(std::time::Duration::from_millis(5)))
-            }
-            Err(error) if error.kind() == std::io::ErrorKind::Interrupted => {}
-            Err(error) => return Err(error),
-        }
-    }
-    let mut acknowledgment = [0_u8; 1];
-    loop {
-        let remaining = reopen_time_remaining(started, timeout)?;
-        match stream.read(&mut acknowledgment) {
-            Ok(1) if acknowledgment[0] == 1 => return Ok(()),
-            Ok(_) => {
-                return Err(std::io::Error::new(
-                    std::io::ErrorKind::InvalidData,
-                    "Cap GPUI did not acknowledge the reopen request",
-                ));
-            }
-            Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => {
-                std::thread::sleep(remaining.min(std::time::Duration::from_millis(5)))
-            }
-            Err(error) if error.kind() == std::io::ErrorKind::Interrupted => {}
-            Err(error) => return Err(error),
-        }
-    }
-}
-
-#[cfg(target_os = "macos")]
-pub(crate) fn request_gpui_reopen(pid: u32) -> Result<(), String> {
-    let request = || -> std::io::Result<()> {
-        let started = std::time::Instant::now();
-        let timeout = std::time::Duration::from_secs(2);
-        let path = gpui_pidfile();
-        loop {
-            reopen_time_remaining(started, timeout)?;
-            if !macos_reopen_incumbent(&path, pid)? {
-                return Err(std::io::Error::new(
-                    std::io::ErrorKind::NotConnected,
-                    "The Cap GPUI instance changed before reopening",
-                ));
-            }
-            match read_macos_gpui_metadata(&path.with_extension("ipc"), true) {
-                Ok(contents) => {
-                    if let Some(endpoint) = parse_gpui_forwarding_endpoint(&contents)
-                        .filter(|endpoint| endpoint.pid == pid)
-                    {
-                        return send_gpui_reopen(endpoint, started, timeout);
-                    }
-                }
-                Err(error) if error.kind() == std::io::ErrorKind::NotFound => {}
-                Err(error) => return Err(error),
-            }
-            std::thread::sleep(
-                reopen_time_remaining(started, timeout)?.min(std::time::Duration::from_millis(50)),
-            );
-        }
-    };
-    request().map_err(|error| format!("Could not confirm reopening the running Cap GPUI: {error}"))
-}
-
-#[cfg(windows)]
-fn request_gpui_reopen(pid: u32) -> Result<(), String> {
-    use windows::Win32::UI::WindowsAndMessaging::AllowSetForegroundWindow;
-
-    let request = || -> std::io::Result<()> {
-        let started = std::time::Instant::now();
-        let timeout = std::time::Duration::from_secs(2);
-        let endpoint_path = gpui_pidfile().with_extension("ipc");
-        loop {
-            if let Some(endpoint) = std::fs::read_to_string(&endpoint_path)
-                .ok()
-                .and_then(|contents| parse_gpui_forwarding_endpoint(&contents))
-                .filter(|endpoint| endpoint.pid == pid)
-            {
-                let _ = unsafe { AllowSetForegroundWindow(pid) };
-                return send_gpui_reopen(endpoint, started, timeout);
-            }
-            std::thread::sleep(
-                reopen_time_remaining(started, timeout)?.min(std::time::Duration::from_millis(50)),
-            );
-        }
-    };
-    request().map_err(|error| format!("Could not confirm reopening the running Cap GPUI: {error}"))
-}
-
-#[cfg(any(target_os = "macos", test))]
-fn gpui_launch_needs_reopen(args: &[String]) -> bool {
-    !args
-        .iter()
-        .any(|argument| forwarded_gpui_argument(argument).is_some())
-}
-
-#[cfg(any(target_os = "macos", windows))]
-fn forward_deep_links_to_gpui(pid: u32, args: &[String]) -> bool {
-    use std::io::Write;
-
-    let urls = args
-        .iter()
-        .filter_map(|argument| forwarded_gpui_argument(argument))
-        .collect::>();
-    if urls.is_empty() {
-        return false;
-    }
-
-    let endpoint_path = gpui_pidfile().with_extension("ipc");
-    let endpoint = (0..40).find_map(|attempt| {
-        let endpoint = std::fs::read_to_string(&endpoint_path)
-            .ok()
-            .and_then(|contents| parse_gpui_forwarding_endpoint(&contents))
-            .filter(|endpoint| endpoint.pid == pid);
-        if endpoint.is_none() && attempt < 39 {
-            std::thread::sleep(std::time::Duration::from_millis(50));
-        }
-        endpoint
-    });
-    let Some(endpoint) = endpoint else {
-        warn!(pid, "could not find the Cap GPUI deep-link endpoint");
-        return false;
-    };
-
-    let mut forwarded = false;
-    for url in urls {
-        let result = std::net::TcpStream::connect((std::net::Ipv4Addr::LOCALHOST, endpoint.port))
-            .and_then(|mut stream| {
-                stream.set_write_timeout(Some(std::time::Duration::from_secs(2)))?;
-                stream.write_all(&endpoint.secret.to_be_bytes())?;
-                stream.write_all(&(url.len() as u32).to_be_bytes())?;
-                stream.write_all(url.as_bytes())
-            });
-        match result {
-            Ok(()) => forwarded = true,
-            Err(error) => warn!(%error, "could not forward a deep link to Cap GPUI"),
-        }
-    }
-
-    forwarded
-}
-
-#[cfg(any(target_os = "macos", windows))]
-pub(crate) fn forward_deep_links_to_active_gpui(app: &AppHandle, args: &[String]) -> bool {
-    let own = GeneralSettingsStore::get(app)
-        .ok()
-        .flatten()
-        .is_some_and(|settings| settings.enable_gpui_app);
-    let enabled = if own_store_is_shared(app) {
-        own
-    } else {
-        shared_store_flag().unwrap_or(false)
-    };
-    if !enabled {
-        return false;
-    }
-
-    let Some(pid) = running_instance_pid() else {
-        return false;
-    };
-    if !forward_deep_links_to_gpui(pid, args) {
-        return false;
-    }
-
-    activate_instance(pid);
-    true
-}
-
-#[cfg(target_os = "macos")]
-pub(crate) fn forward_deep_links_to_gpui_when_ready(args: &[String]) -> Option {
-    if !args
-        .iter()
-        .any(|argument| forwarded_gpui_argument(argument).is_some())
-    {
-        return None;
-    }
-
-    let pid = (0..40).find_map(|attempt| {
-        let pid = running_instance_pid();
-        if pid.is_none() && attempt < 39 {
-            std::thread::sleep(std::time::Duration::from_millis(50));
-        }
-        pid
-    })?;
-
-    forward_deep_links_to_gpui(pid, args).then_some(pid)
-}
-
-#[cfg(target_os = "macos")]
-pub(crate) fn activate_instance(pid: u32) {
-    use objc2_app_kit::{NSApplicationActivationOptions, NSRunningApplication};
-
-    if let Some(instance) =
-        unsafe { NSRunningApplication::runningApplicationWithProcessIdentifier(pid as _) }
-    {
-        unsafe {
-            instance.activateWithOptions(NSApplicationActivationOptions::ActivateIgnoringOtherApps);
-        }
-    }
-}
-
-#[cfg(windows)]
-fn activate_instance(pid: u32) {
-    use windows::{
-        Win32::{
-            Foundation::{HWND, LPARAM, TRUE},
-            UI::WindowsAndMessaging::{
-                EnumWindows, GetWindowThreadProcessId, IsWindowVisible, SW_RESTORE,
-                SetForegroundWindow, ShowWindow,
-            },
-        },
-        core::BOOL,
-    };
-
-    struct Activation {
-        pid: u32,
-        visible: Option,
-        fallback: Option,
-    }
-
-    unsafe extern "system" fn find_window(window: HWND, data: LPARAM) -> BOOL {
-        let activation = unsafe { &mut *(data.0 as *mut Activation) };
-        let mut owner = 0;
-        unsafe { GetWindowThreadProcessId(window, Some(&mut owner)) };
-        if owner == activation.pid {
-            if activation.fallback.is_none() {
-                activation.fallback = Some(window);
-            }
-            if activation.visible.is_none() && unsafe { IsWindowVisible(window) }.as_bool() {
-                activation.visible = Some(window);
-            }
-        }
-        TRUE
-    }
-
-    let mut activation = Activation {
-        pid,
-        visible: None,
-        fallback: None,
-    };
-    let _ = unsafe {
-        EnumWindows(
-            Some(find_window),
-            LPARAM(std::ptr::addr_of_mut!(activation) as isize),
-        )
-    };
-
-    if let Some(window) = activation.visible.or(activation.fallback) {
-        unsafe {
-            let _ = ShowWindow(window, SW_RESTORE);
-            let _ = SetForegroundWindow(window);
-        }
-    }
-}
-
-#[cfg(not(any(target_os = "macos", target_os = "linux", windows)))]
-fn activate_instance(_pid: u32) {}
-
-#[cfg(any(target_os = "linux", test))]
-fn launch_linux_activation(
-    path: Option<&std::path::Path>,
-    launch: impl FnOnce(&std::path::Path, &[String]) -> Result<(), String>,
-) -> Result<(), String> {
-    let path = path.ok_or_else(|| "Cap GPUI isn't included in this build".to_string())?;
-    launch(path, &[])
-}
-
-fn write_handoff_marker() {
-    let path = handoff_marker();
-    if let Some(parent) = path.parent() {
-        let _ = std::fs::create_dir_all(parent);
-    }
-    let stamp = std::time::SystemTime::now()
-        .duration_since(std::time::UNIX_EPOCH)
-        .map(|since| since.as_secs())
-        .unwrap_or_default();
-    if let Err(error) = std::fs::write(&path, stamp.to_string()) {
-        warn!(%error, "could not write the Cap GPUI handoff marker");
-    }
-}
-
-/// The child must never inherit this process's stdio. The handoff exits this
-/// app, and whatever was reading those pipes (`bun run tauri dev`'s tooling chain)
-/// goes with it; `cap-gpui`'s next log line then hits EPIPE, the write panics
-/// inside an ObjC run-loop callback, and the process aborts about a tenth of a
-/// second after launch. Its output goes to a file instead of `/dev/null`
-/// because a handoff launch has no terminal, and a startup failure there is
-/// only ever diagnosable from that file.
-fn spawn_detached(path: &std::path::Path, args: &[String]) -> Result<(), String> {
-    use std::process::Stdio;
-
-    let log_path = shared_data_dir().join("cap-gpui.log");
-    if let Some(parent) = log_path.parent() {
-        let _ = std::fs::create_dir_all(parent);
-    }
-    let (stdout, stderr) = match std::fs::OpenOptions::new()
-        .create(true)
-        .append(true)
-        .open(&log_path)
-    {
-        Ok(file) => match file.try_clone() {
-            Ok(clone) => (Stdio::from(file), Stdio::from(clone)),
-            Err(_) => (Stdio::from(file), Stdio::null()),
-        },
-        Err(error) => {
-            warn!(%error, "could not open the Cap GPUI log; discarding its output");
-            (Stdio::null(), Stdio::null())
-        }
-    };
-
-    let mut command = std::process::Command::new(path);
-    command
-        .args(args)
-        .stdin(Stdio::null())
-        .stdout(stdout)
-        .stderr(stderr);
-    // Its own process group, so signals aimed at the terminal this app was
-    // started from never reach the app that outlives it.
-    #[cfg(unix)]
-    {
-        use std::os::unix::process::CommandExt;
-        command.process_group(0);
-    }
-
-    let mut child = command
-        .spawn()
-        .map_err(|error| format!("Failed to launch Cap GPUI: {error}"))?;
-    // Reap the child when it exits so it never lingers as a zombie.
-    std::thread::spawn(move || {
-        let _ = child.wait();
-    });
-    Ok(())
-}
-
-#[cfg(target_os = "macos")]
-pub(crate) fn retire_foreground_parent_for_handoff(app: &AppHandle) {
-    if app
-        .webview_windows()
-        .values()
-        .any(|window| !window.is_fullscreen().is_ok_and(|fullscreen| !fullscreen))
-    {
-        warn!(
-            "Keeping the handoff parent's activation policy because fullscreen state is active or unavailable"
-        );
-        return;
-    }
-
-    // A foreground parent exiting with a surviving child leaves a macOS background Dock tile.
-    match app.set_activation_policy(tauri::ActivationPolicy::Accessory) {
-        Ok(()) => info!("Requested retirement of Tauri's Dock presence for the GPUI handoff"),
-        Err(error) => warn!(%error, "Could not retire Tauri's Dock presence for the GPUI handoff"),
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn gpui_app_available(app: AppHandle) -> bool {
-    binary_path(&app).is_some()
-}
-
-/// Close this app and open the native one. The setting has already been written
-/// by the caller, so a failure here has to be reported rather than swallowed:
-/// the page reverts it.
-#[tauri::command]
-#[specta::specta]
-pub async fn switch_to_gpui_app(app: AppHandle) -> Result<(), String> {
-    let path =
-        binary_path(&app).ok_or_else(|| "Cap GPUI isn't included in this build".to_string())?;
-    crate::prepare_app_exit(&app, || {
-        let uses_shared_store = own_store_is_shared(&app);
-        let previous_shared_flag = if uses_shared_store {
-            None
-        } else {
-            let previous = shared_store_flag();
-            write_shared_store_flag(true);
-            previous
-        };
-        match running_instance_pid() {
-            Some(pid) => {
-                #[cfg(target_os = "linux")]
-                if let Err(error) = launch_linux_activation(Some(&path), spawn_detached) {
-                    if !uses_shared_store {
-                        write_shared_store_flag(previous_shared_flag.unwrap_or(false));
-                    }
-                    return Err(error);
-                }
-                #[cfg(target_os = "macos")]
-                if let Err(error) = request_gpui_reopen(pid) {
-                    if !uses_shared_store {
-                        write_shared_store_flag(previous_shared_flag.unwrap_or(false));
-                    }
-                    return Err(error);
-                }
-                #[cfg(not(target_os = "linux"))]
-                activate_instance(pid);
-                info!(pid, "Cap GPUI is already running; requested its controls");
-            }
-            None => {
-                write_handoff_marker();
-                info!(path = %path.display(), "handing off to Cap GPUI");
-                if let Err(error) = spawn_detached(&path, &[]) {
-                    let _ = std::fs::remove_file(handoff_marker());
-                    if !uses_shared_store {
-                        write_shared_store_flag(previous_shared_flag.unwrap_or(false));
-                    }
-                    return Err(error);
-                }
-            }
-        }
-        Ok(())
-    })?;
-    #[cfg(target_os = "macos")]
-    {
-        let handle = app.clone();
-        let (sender, receiver) = tokio::sync::oneshot::channel();
-        match app.run_on_main_thread(move || {
-            retire_foreground_parent_for_handoff(&handle);
-            let _ = sender.send(());
-        }) {
-            Ok(()) => {
-                if !matches!(
-                    tokio::time::timeout(std::time::Duration::from_secs(2), receiver).await,
-                    Ok(Ok(()))
-                ) {
-                    warn!(
-                        "The GPUI handoff's Dock transition was not acknowledged before shutdown"
-                    );
-                }
-            }
-            Err(error) => warn!(%error, "Could not schedule the GPUI handoff's Dock transition"),
-        }
-    }
-    crate::complete_admitted_app_exit(app).await;
-    Ok(())
-}
-
-/// Whether this app should hand over to `cap-gpui` instead of starting.
-///
-/// `true` means the caller must exit before any window is created.
-pub fn redirect_at_startup_if_enabled(app: &AppHandle) -> Result {
-    #[cfg(debug_assertions)]
-    if crate::stop_editor_benchmark::enabled() {
-        return Ok(false);
-    }
-    let update_handoff = handle_update_handoff(app);
-    let redirect = !update_handoff && redirect_decision(app)?;
-    if !redirect {
-        let app = app.clone();
-        tauri::async_runtime::spawn(async move {
-            loop {
-                handle_update_handoff(&app);
-                if classic_pending().try_exists().unwrap_or(false) {
-                    let handle = app.clone();
-                    let (sender, receiver) = tokio::sync::oneshot::channel();
-                    if app
-                        .run_on_main_thread(move || {
-                            acknowledge_classic_window(&handle);
-                            let _ = sender.send(());
-                        })
-                        .is_ok()
-                    {
-                        let _ =
-                            tokio::time::timeout(std::time::Duration::from_secs(1), receiver).await;
-                    }
-                }
-                tokio::time::sleep(std::time::Duration::from_millis(250)).await;
-            }
-        });
-    }
-    Ok(redirect)
-}
-
-fn acknowledge_classic_window(app: &AppHandle) {
-    if crate::app_is_exiting(app) {
-        return;
-    }
-    let ready = app
-        .get_webview_window("main")
-        .or_else(|| app.get_webview_window("onboarding"))
-        .is_some_and(|window| {
-            let frontend_ready = window.label() == "onboarding"
-                || window.url().is_ok_and(|url| url.path() == "/update")
-                || app
-                    .try_state::()
-                    .is_some_and(|state| state.is_ready());
-            frontend_ready && window.is_visible().unwrap_or(false)
-        });
-    if ready {
-        match std::fs::remove_file(classic_pending()) {
-            Ok(()) => info!("Acknowledged visible classic window for GPUI handoff"),
-            Err(error) if error.kind() == std::io::ErrorKind::NotFound => {}
-            Err(error) => warn!(%error, "Could not acknowledge the classic app handoff"),
-        }
-    }
-}
-
-fn redirect_decision(app: &AppHandle) -> Result {
-    let own = GeneralSettingsStore::get(app)
-        .ok()
-        .flatten()
-        .is_some_and(|settings| settings.enable_gpui_app);
-    // In a dev build the shared store is the authority: `cap-gpui`'s
-    // switch-back writes false THERE, and honouring this app's own `.dev`
-    // copy instead would bounce the user straight back after every
-    // switch-back (the loop this replaced).
-    let enabled = if own_store_is_shared(app) {
-        own
-    } else {
-        shared_store_flag().unwrap_or(false)
-    };
-    if !enabled {
-        if own {
-            // The stale display copy: without this the Experimental page
-            // shows the toggle on while the classic app owns the session.
-            if let Err(error) = GeneralSettingsStore::update(app, |settings| {
-                settings.enable_gpui_app = false;
-            }) {
-                warn!(%error, "could not reconcile the Cap GPUI setting");
-            }
-        }
-        return Ok(false);
-    }
-
-    // The marker exists throughout a live session. Check the process first so
-    // reopening Cap does not mistake a running native app for a crashed one.
-    if let Some(pid) = running_instance_pid() {
-        #[cfg(any(target_os = "macos", windows))]
-        {
-            let args = std::env::args().skip(1).collect::>();
-            #[cfg(target_os = "macos")]
-            if gpui_launch_needs_reopen(&args) {
-                app.manage(StartupRedirectState::with_reopen(pid));
-            } else {
-                forward_deep_links_to_gpui(pid, &args);
-            }
-            #[cfg(windows)]
-            if !forward_deep_links_to_gpui(pid, &args) {
-                match request_gpui_reopen(pid) {
-                    Ok(()) => {
-                        info!(pid, "Cap GPUI is already running; reopened its main window");
-                        return Ok(true);
-                    }
-                    Err(error) => warn!(%error, "could not reopen the running Cap GPUI"),
-                }
-            }
-        }
-        #[cfg(target_os = "linux")]
-        launch_linux_activation(binary_path(app).as_deref(), spawn_detached)?;
-        #[cfg(not(target_os = "linux"))]
-        activate_instance(pid);
-        info!(
-            pid,
-            "Cap GPUI is already running; preserving the existing instance"
-        );
-        return Ok(true);
-    }
-
-    let marker = handoff_marker();
-    if marker.exists() {
-        warn!("the last Cap GPUI session exited unexpectedly; taking back over");
-        let _ = std::fs::remove_file(&marker);
-        if let Err(error) = GeneralSettingsStore::update(app, |settings| {
-            settings.enable_gpui_app = false;
-        }) {
-            warn!(%error, "could not clear the Cap GPUI setting");
-        }
-        if !own_store_is_shared(app) {
-            write_shared_store_flag(false);
-        }
-        app.dialog()
-            .message(
-                "The native Cap app exited unexpectedly last time, so the classic app has been restored.",
-            )
-            .show(|_| {});
-        return Ok(false);
-    }
-
-    let Some(path) = binary_path(app) else {
-        warn!("Cap GPUI is enabled but its binary was not found; starting this app instead");
-        return Ok(false);
-    };
-
-    write_handoff_marker();
-    info!(path = %path.display(), "handing off to Cap GPUI at startup");
-    #[cfg(any(target_os = "macos", windows))]
-    let args = std::env::args()
-        .skip(1)
-        .filter_map(|argument| forwarded_gpui_argument(&argument))
-        .collect::>();
-    #[cfg(not(any(target_os = "macos", windows)))]
-    let args = Vec::new();
-    if let Err(error) = spawn_detached(&path, &args) {
-        warn!("{error}");
-        let _ = std::fs::remove_file(handoff_marker());
-        return Ok(false);
-    }
-    Ok(true)
-}
-
-#[cfg(test)]
-mod tests {
-    use super::{
-        BINARY_NAME, GpuiForwardingEndpoint, MAX_FORWARDED_DEEP_LINK_BYTES, StartupRedirectState,
-        UpdateHandoff, forwarded_gpui_argument, is_forwardable_gpui_deep_link,
-        is_gpui_process_image, parse_gpui_forwarding_endpoint, parse_update_handoff,
-    };
-
-    #[test]
-    fn linux_activation_launches_the_resolved_binary_once_without_arguments() {
-        let path = std::path::Path::new("/opt/cap/cap-gpui");
-        let mut launches = 0;
-        super::launch_linux_activation(Some(path), |selected, args| {
-            launches += 1;
-            assert_eq!(selected, path);
-            assert!(args.is_empty());
-            Ok(())
-        })
-        .unwrap();
-        assert_eq!(launches, 1);
-    }
-
-    #[test]
-    fn linux_activation_requires_a_resolved_binary_before_launch() {
-        let result = super::launch_linux_activation(None, |_, _| {
-            panic!("a missing GPUI binary must not be launched")
-        });
-        assert_eq!(result.unwrap_err(), "Cap GPUI isn't included in this build");
-    }
-
-    #[test]
-    fn linux_activation_preserves_launch_failure() {
-        let path = std::path::Path::new("/opt/cap/cap-gpui");
-        let result = super::launch_linux_activation(Some(path), |_, _| {
-            Err("Failed to launch Cap GPUI: permission denied".into())
-        });
-        assert_eq!(
-            result.unwrap_err(),
-            "Failed to launch Cap GPUI: permission denied"
-        );
-    }
-
-    #[test]
-    fn startup_redirect_exits_once_when_no_open_event_arrives() {
-        let state = StartupRedirectState::default();
-
-        assert_eq!(state.exit_if_pending(), Some(None));
-        assert!(state.exit_if_pending().is_none());
-        assert!(!state.begin_forwarding());
-        assert!(!state.exit_after_forwarding());
-    }
-
-    #[test]
-    fn startup_redirect_waits_for_forwarding_before_exiting_once() {
-        let state = StartupRedirectState::default();
-
-        assert!(state.begin_forwarding());
-        assert!(!state.begin_forwarding());
-        assert!(state.exit_if_pending().is_none());
-        assert!(state.exit_after_forwarding());
-        assert!(!state.exit_after_forwarding());
-    }
-
-    #[test]
-    fn startup_plain_launch_returns_its_reopen_intent_only_once() {
-        let state = StartupRedirectState::with_reopen(123);
-
-        assert_eq!(state.exit_if_pending(), Some(Some(123)));
-        assert!(state.exit_if_pending().is_none());
-        assert!(!state.begin_forwarding());
-        assert!(!state.exit_after_forwarding());
-    }
-
-    #[test]
-    fn startup_open_event_suppresses_pending_plain_reopen() {
-        let state = StartupRedirectState::with_reopen(123);
-
-        assert!(state.begin_forwarding());
-        assert!(state.exit_if_pending().is_none());
-        assert!(!state.begin_forwarding());
-        assert!(state.exit_after_forwarding());
-        assert!(state.exit_if_pending().is_none());
-        assert!(!state.exit_after_forwarding());
-    }
-
-    #[test]
-    fn update_handoff_requires_a_valid_process_id() {
-        assert_eq!(
-            parse_update_handoff("1234"),
-            Some(UpdateHandoff {
-                pid: 1234,
-                simulated: false,
-            })
-        );
-        assert_eq!(parse_update_handoff("0"), None);
-        assert_eq!(parse_update_handoff("cap-gpui"), None);
-        assert_eq!(parse_update_handoff("simulate:0"), None);
-    }
-
-    #[test]
-    fn simulated_update_handoffs_are_debug_only() {
-        let parsed = parse_update_handoff("simulate:4321");
-        if cfg!(debug_assertions) {
-            assert_eq!(
-                parsed,
-                Some(UpdateHandoff {
-                    pid: 4321,
-                    simulated: true,
-                })
-            );
-        } else {
-            assert_eq!(parsed, None);
-        }
-    }
-
-    #[test]
-    fn gpui_process_image_must_match_exactly() {
-        assert!(is_gpui_process_image(std::path::Path::new(BINARY_NAME)));
-        assert!(is_gpui_process_image(std::path::Path::new(
-            &BINARY_NAME.to_ascii_uppercase()
-        )));
-        assert!(!is_gpui_process_image(std::path::Path::new("not-cap-gpui")));
-        assert!(!is_gpui_process_image(std::path::Path::new(
-            "cap-gpui-helper"
-        )));
-    }
-
-    #[cfg(target_os = "linux")]
-    #[test]
-    fn linux_process_check_distinguishes_live_unlinked_and_exited_processes() {
-        let directory = tempfile::tempdir().unwrap();
-        let binary = directory.path().join(BINARY_NAME);
-        std::fs::copy("/bin/sleep", &binary).unwrap();
-        let mut child = std::process::Command::new(&binary)
-            .arg("30")
-            .spawn()
-            .unwrap();
-        let pid = child.id();
-        let started = std::time::Instant::now();
-        // spawn can return before /proc stops exposing the child's pre-exec image.
-        while !std::fs::read_link(format!("/proc/{pid}/exe")).is_ok_and(|path| path == binary)
-            && started.elapsed() < std::time::Duration::from_secs(5)
-        {
-            std::thread::sleep(std::time::Duration::from_millis(1));
-        }
-        let live = super::linux_gpui_process_is_running(pid);
-        std::fs::remove_file(&binary).unwrap();
-        let unlinked = super::linux_gpui_process_is_running(pid);
-        child.kill().unwrap();
-        let started = std::time::Instant::now();
-        let mut zombie = false;
-        while started.elapsed() < std::time::Duration::from_secs(5) {
-            zombie = std::fs::read_to_string(format!("/proc/{pid}/stat")).is_ok_and(|stat| {
-                stat.rsplit_once(") ")
-                    .is_some_and(|(_, state)| state.starts_with('Z'))
-            });
-            if zombie {
-                break;
-            }
-            std::thread::sleep(std::time::Duration::from_millis(1));
-        }
-        let exited = super::linux_gpui_process_is_running(pid);
-        child.wait().unwrap();
-
-        assert!(live);
-        assert!(unlinked);
-        assert!(zombie);
-        assert!(!exited);
-        assert!(!super::linux_gpui_process_is_running(pid));
-        assert!(!super::linux_gpui_process_is_running(std::process::id()));
-    }
-
-    #[test]
-    fn gpui_forwarding_endpoint_requires_the_owner_identity() {
-        assert_eq!(
-            parse_gpui_forwarding_endpoint("4321:49152:0123456789abcdef"),
-            Some(GpuiForwardingEndpoint {
-                pid: 4321,
-                port: 49152,
-                secret: 0x0123_4567_89ab_cdef,
-            })
-        );
-        assert_eq!(parse_gpui_forwarding_endpoint("0:49152:1234"), None);
-        assert_eq!(parse_gpui_forwarding_endpoint("4321:0:1234"), None);
-        assert_eq!(parse_gpui_forwarding_endpoint("4321:49152:xyz"), None);
-        assert_eq!(
-            parse_gpui_forwarding_endpoint("4321:49152:1234:extra"),
-            None
-        );
-    }
-
-    #[test]
-    fn forwarded_gpui_deep_links_are_scheme_and_size_limited() {
-        assert!(is_forwardable_gpui_deep_link(
-            "cap-desktop://signin?token=test"
-        ));
-        assert!(is_forwardable_gpui_deep_link(
-            "cap://action?value=%22stop_recording%22"
-        ));
-        assert!(!is_forwardable_gpui_deep_link("https://cap.so/signin"));
-        assert!(!is_forwardable_gpui_deep_link("cap-desktop-other://signin"));
-        assert!(!is_forwardable_gpui_deep_link(&format!(
-            "cap://action?value={}",
-            "x".repeat(MAX_FORWARDED_DEEP_LINK_BYTES)
-        )));
-    }
-
-    #[test]
-    fn project_arguments_become_encoded_open_editor_actions() {
-        let directory = tempfile::tempdir().unwrap();
-        let project = directory.path().join("Recording #1 & draft.cap");
-        std::fs::create_dir(&project).unwrap();
-
-        let forwarded = forwarded_gpui_argument(project.to_str().unwrap()).unwrap();
-        let url = reqwest::Url::parse(&forwarded).unwrap();
-        let value = url
-            .query_pairs()
-            .find_map(|(key, value)| (key == "value").then_some(value.into_owned()))
-            .unwrap();
-        let action: serde_json::Value = serde_json::from_str(&value).unwrap();
-
-        assert_eq!(url.scheme(), "cap-desktop");
-        assert_eq!(url.host_str(), Some("action"));
-        assert_eq!(
-            action["open_editor"]["project_path"],
-            project.canonicalize().unwrap().to_string_lossy().as_ref()
-        );
-    }
-
-    #[test]
-    fn forwarded_project_arguments_reject_missing_and_non_project_paths() {
-        let directory = tempfile::tempdir().unwrap();
-        let ordinary = directory.path().join("notes.txt");
-        std::fs::write(&ordinary, "notes").unwrap();
-
-        assert!(forwarded_gpui_argument(ordinary.to_str().unwrap()).is_none());
-        assert!(
-            forwarded_gpui_argument(directory.path().join("missing.cap").to_str().unwrap())
-                .is_none()
-        );
-        assert_eq!(
-            forwarded_gpui_argument("cap-desktop://signin?token=secret"),
-            Some("cap-desktop://signin?token=secret".to_string())
-        );
-    }
-
-    #[cfg(unix)]
-    #[test]
-    fn forwarded_project_arguments_reject_symlinks() {
-        let directory = tempfile::tempdir().unwrap();
-        let project = directory.path().join("Recording.cap");
-        let symlink = directory.path().join("Shortcut.cap");
-        std::fs::create_dir(&project).unwrap();
-        std::os::unix::fs::symlink(&project, &symlink).unwrap();
-
-        assert!(forwarded_gpui_argument(symlink.to_str().unwrap()).is_none());
-    }
-
-    #[test]
-    fn file_urls_become_open_editor_actions() {
-        let directory = tempfile::tempdir().unwrap();
-        let project = directory.path().join("Recording.cap");
-        std::fs::create_dir(&project).unwrap();
-        let file_url = reqwest::Url::from_file_path(&project).unwrap();
-
-        assert!(forwarded_gpui_argument(file_url.as_str()).is_some());
-    }
-
-    #[test]
-    fn only_launches_without_forwardable_actions_request_reopening() {
-        assert!(super::gpui_launch_needs_reopen(&[]));
-        let directory = tempfile::tempdir().unwrap();
-        let project = directory.path().join("Recording.cap");
-        std::fs::create_dir(&project).unwrap();
-        for argument in [
-            "cap-desktop://auth?token=fixture".to_string(),
-            "cap://action?value=%22stop_recording%22".to_string(),
-            project.to_str().unwrap().to_string(),
-            reqwest::Url::from_file_path(&project).unwrap().to_string(),
-        ] {
-            assert!(!super::gpui_launch_needs_reopen(&[argument]));
-        }
-    }
-
-    #[cfg(target_os = "macos")]
-    #[test]
-    fn macos_reopen_sends_private_packet_and_requires_acknowledgment() {
-        use std::{
-            io::{Read, Write},
-            time::{Duration, Instant},
-        };
-
-        for reply in [0_u8, 1] {
-            let listener = std::net::TcpListener::bind((std::net::Ipv4Addr::LOCALHOST, 0)).unwrap();
-            listener.set_nonblocking(true).unwrap();
-            let endpoint = GpuiForwardingEndpoint {
-                pid: 123,
-                port: listener.local_addr().unwrap().port(),
-                secret: 456,
-            };
-            let server = std::thread::spawn(move || {
-                let started = Instant::now();
-                let mut stream = loop {
-                    match listener.accept() {
-                        Ok((stream, _)) => break stream,
-                        Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => {
-                            assert!(started.elapsed() < Duration::from_secs(5));
-                            std::thread::sleep(Duration::from_millis(5));
-                        }
-                        Err(error) => panic!("Reopen listener failed: {error}"),
-                    }
-                };
-                stream.set_nonblocking(false).unwrap();
-                stream
-                    .set_read_timeout(Some(Duration::from_secs(2)))
-                    .unwrap();
-                stream
-                    .set_write_timeout(Some(Duration::from_secs(2)))
-                    .unwrap();
-                let mut packet = [0_u8; 12];
-                stream.read_exact(&mut packet).unwrap();
-                assert_eq!(&packet[..8], &endpoint.secret.to_be_bytes());
-                assert_eq!(&packet[8..], &0_u32.to_be_bytes());
-                stream.write_all(&[reply]).unwrap();
-            });
-            let result = super::send_gpui_reopen(endpoint, Instant::now(), Duration::from_secs(2));
-            server.join().unwrap();
-            if reply == 1 {
-                result.unwrap();
-            } else {
-                assert_eq!(result.unwrap_err().kind(), std::io::ErrorKind::InvalidData);
-            }
-        }
-    }
-
-    #[cfg(target_os = "macos")]
-    #[test]
-    fn macos_reopen_deadline_also_bounds_missing_acknowledgment() {
-        use std::time::{Duration, Instant};
-
-        let listener = std::net::TcpListener::bind((std::net::Ipv4Addr::LOCALHOST, 0)).unwrap();
-        let endpoint = GpuiForwardingEndpoint {
-            pid: 123,
-            port: listener.local_addr().unwrap().port(),
-            secret: 456,
-        };
-        assert_eq!(
-            super::send_gpui_reopen(endpoint, Instant::now(), Duration::from_millis(100))
-                .unwrap_err()
-                .kind(),
-            std::io::ErrorKind::TimedOut
-        );
-        let expired = Instant::now().checked_sub(Duration::from_secs(2)).unwrap();
-        assert_eq!(
-            super::send_gpui_reopen(endpoint, expired, Duration::from_secs(2))
-                .unwrap_err()
-                .kind(),
-            std::io::ErrorKind::TimedOut
-        );
-    }
-
-    #[cfg(target_os = "macos")]
-    #[test]
-    fn macos_reopen_rejects_shared_or_linked_endpoint_and_changed_pid() {
-        use std::os::unix::fs::{PermissionsExt, symlink};
-
-        let directory = tempfile::tempdir().unwrap();
-        let path = directory.path().join("cap-gpui.ipc");
-        std::fs::write(&path, "123:456:789").unwrap();
-        std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o600)).unwrap();
-        assert_eq!(
-            super::read_macos_gpui_metadata(&path, true).unwrap(),
-            "123:456:789"
-        );
-        std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o644)).unwrap();
-        assert_eq!(
-            super::read_macos_gpui_metadata(&path, true)
-                .unwrap_err()
-                .kind(),
-            std::io::ErrorKind::PermissionDenied
-        );
-        std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o600)).unwrap();
-        let linked = directory.path().join("linked.ipc");
-        symlink(&path, &linked).unwrap();
-        assert!(super::read_macos_gpui_metadata(&linked, true).is_err());
-        std::fs::remove_file(&linked).unwrap();
-        std::fs::hard_link(&path, &linked).unwrap();
-        assert!(super::read_macos_gpui_metadata(&path, true).is_err());
-        let pidfile = directory.path().join("cap-gpui.pid");
-        std::fs::write(&pidfile, "123").unwrap();
-        assert!(!super::macos_reopen_incumbent(&pidfile, 456).unwrap());
-        assert_eq!(std::fs::read_to_string(&path).unwrap(), "123:456:789");
-        assert_eq!(std::fs::read_to_string(&pidfile).unwrap(), "123");
-    }
-}
diff --git a/apps/desktop/src-tauri/src/hotkeys.rs b/apps/desktop/src-tauri/src/hotkeys.rs
deleted file mode 100644
index 257a8f59b49..00000000000
--- a/apps/desktop/src-tauri/src/hotkeys.rs
+++ /dev/null
@@ -1,854 +0,0 @@
-use crate::{
-    App, ArcLock, RequestOpenRecordingPicker, RequestStartRecording, recording,
-    recording_settings::{RecordingSettingsStore, RecordingTargetMode},
-    tray,
-    windows::ShowCapWindow,
-};
-use cap_recording::feeds::microphone::MicrophoneFeed;
-use cap_recording::screen_capture::ScreenCaptureTarget;
-use global_hotkey::HotKeyState;
-use serde::{Deserialize, Serialize};
-use specta::Type;
-use std::collections::HashMap;
-use std::future::Future;
-use std::sync::Mutex;
-use tauri::{AppHandle, Manager};
-use tauri_plugin_dialog::{DialogExt, MessageDialogButtons, MessageDialogKind};
-use tauri_plugin_global_shortcut::{Code, GlobalShortcutExt, Modifiers, Shortcut};
-use tauri_plugin_store::StoreExt;
-use tauri_specta::Event;
-use tracing::instrument;
-
-#[derive(Serialize, Deserialize, Type, PartialEq, Clone, Copy, Debug)]
-pub struct Hotkey {
-    #[specta(type = String)]
-    code: Code,
-    meta: bool,
-    ctrl: bool,
-    alt: bool,
-    shift: bool,
-}
-
-impl From for Shortcut {
-    fn from(hotkey: Hotkey) -> Self {
-        let mut modifiers = Modifiers::empty();
-
-        if hotkey.meta {
-            modifiers |= Modifiers::META;
-        }
-        if hotkey.ctrl {
-            modifiers |= Modifiers::CONTROL;
-        }
-        if hotkey.alt {
-            modifiers |= Modifiers::ALT;
-        }
-        if hotkey.shift {
-            modifiers |= Modifiers::SHIFT;
-        }
-
-        Shortcut::new(Some(modifiers), hotkey.code)
-    }
-}
-
-#[derive(Serialize, Deserialize, Type, PartialEq, Eq, Hash, Clone, Copy, Debug)]
-#[serde(rename_all = "camelCase")]
-#[allow(clippy::enum_variant_names)]
-pub enum HotkeyAction {
-    StartStudioRecording,
-    StartInstantRecording,
-    StopRecording,
-    RestartRecording,
-    TogglePauseRecording,
-    CycleRecordingMode,
-    OpenRecordingPicker,
-    OpenRecordingPickerDisplay,
-    OpenRecordingPickerWindow,
-    OpenRecordingPickerArea,
-    ScreenshotDisplay,
-    ScreenshotWindow,
-    ScreenshotArea,
-    #[serde(other)]
-    Other,
-}
-
-#[derive(Serialize, Deserialize, Type, Default)]
-pub struct HotkeysStore {
-    hotkeys: HashMap,
-}
-
-impl HotkeysStore {
-    pub fn get(app: &AppHandle) -> Result, String> {
-        let Ok(Some(store)) = app.store("store").map(|s| s.get("hotkeys")) else {
-            return Ok(None);
-        };
-
-        serde_json::from_value(store).map_err(|e| e.to_string())
-    }
-}
-
-#[derive(Serialize, Type, tauri_specta::Event, Debug, Clone)]
-pub struct OnEscapePress;
-
-pub type HotkeysState = Mutex;
-
-fn clean_capture_shortcut() -> Shortcut {
-    Shortcut::new(Some(Modifiers::CONTROL | Modifiers::SHIFT), Code::F9)
-}
-
-#[cfg(any(target_os = "linux", test))]
-fn existing_clean_capture_stop(store: &HotkeysStore) -> Result {
-    let shortcut = clean_capture_shortcut();
-    let mut existing_stop = false;
-    for (action, hotkey) in &store.hotkeys {
-        if Shortcut::from(*hotkey) == shortcut {
-            if !matches!(action, HotkeyAction::StopRecording) {
-                return Err("Ctrl+Shift+F9 is assigned to another Cap action. Change that shortcut before starting clean Studio capture.".into());
-            }
-            existing_stop = true;
-        }
-    }
-    Ok(existing_stop)
-}
-
-#[cfg(target_os = "linux")]
-pub(crate) fn reserve_clean_capture_stop(app: &AppHandle) -> Result {
-    let shortcut = clean_capture_shortcut();
-    let state = app.state::();
-    let store = state.lock().unwrap();
-    let existing_stop = existing_clean_capture_stop(&store)?;
-    let shortcuts = app.global_shortcut();
-    if shortcuts.is_registered(shortcut) {
-        return if existing_stop {
-            Ok(false)
-        } else {
-            Err("Ctrl+Shift+F9 is already reserved. Release it before starting clean Studio capture.".into())
-        };
-    }
-    shortcuts.register(shortcut).map_err(|error| {
-        format!("Cannot reserve Ctrl+Shift+F9 to stop recording: {error}. Change the conflicting system shortcut and try again.")
-    })?;
-    Ok(true)
-}
-
-pub(crate) fn release_clean_capture_stop(app: &AppHandle, owned: bool) {
-    if owned && let Err(error) = app.global_shortcut().unregister(clean_capture_shortcut()) {
-        tracing::warn!(%error, "Could not release temporary recording shortcut");
-    }
-}
-
-const RECORDING_START_SAFETY_STORE_KEY: &str = "recording_start_safety";
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase", default)]
-struct RecordingStartSafetySettings {
-    confirm_before_recording_without_microphone: bool,
-}
-
-impl Default for RecordingStartSafetySettings {
-    fn default() -> Self {
-        Self {
-            confirm_before_recording_without_microphone: true,
-        }
-    }
-}
-
-fn should_confirm_without_microphone(enabled: bool, microphone_available: bool) -> bool {
-    enabled && !microphone_available
-}
-
-#[cfg(any(target_os = "macos", test))]
-fn microphone_available_for_confirmation(
-    name: Option<&str>,
-    permission: impl FnOnce() -> Result<(), String>,
-    contains: impl FnOnce(&str) -> bool,
-) -> Result {
-    let Some(name) = name else {
-        return Ok(false);
-    };
-    permission().map_err(|error| {
-        format!("{error} To record without a microphone, turn the microphone Off in Cap.")
-    })?;
-    if !contains(name) {
-        return Err(format!(
-            "Selected microphone '{name}' is no longer available. Reconnect it, select another microphone, or turn the microphone Off to record without it."
-        ));
-    }
-    Ok(true)
-}
-
-fn should_confirm_direct_recording(app: &AppHandle) -> Result {
-    let enabled = app
-        .store("store")
-        .ok()
-        .and_then(|store| store.get(RECORDING_START_SAFETY_STORE_KEY))
-        .and_then(|value| serde_json::from_value::(value).ok())
-        .unwrap_or_default()
-        .confirm_before_recording_without_microphone;
-
-    #[cfg(not(target_os = "macos"))]
-    if !enabled {
-        return Ok(false);
-    }
-
-    let microphone_name = RecordingSettingsStore::get(app)
-        .ok()
-        .flatten()
-        .and_then(|settings| settings.mic_name);
-    #[cfg(target_os = "macos")]
-    let microphone_available = microphone_available_for_confirmation(
-        microphone_name.as_deref(),
-        crate::permissions::check_microphone_access,
-        |name| {
-            MicrophoneFeed::list_names()
-                .iter()
-                .any(|device| device == name)
-        },
-    )?;
-    #[cfg(not(target_os = "macos"))]
-    let microphone_available = microphone_name
-        .as_deref()
-        .is_some_and(|name| MicrophoneFeed::list().contains_key(name));
-
-    Ok(should_confirm_without_microphone(
-        enabled,
-        microphone_available,
-    ))
-}
-
-async fn confirm_direct_recording_without_microphone(app: &AppHandle) -> bool {
-    match should_confirm_direct_recording(app) {
-        Ok(false) => return true,
-        Ok(true) => {}
-        Err(message) => {
-            app.dialog()
-                .message(message)
-                .title("Microphone unavailable")
-                .kind(MessageDialogKind::Warning)
-                .buttons(MessageDialogButtons::Ok)
-                .show(|_| {});
-            return false;
-        }
-    }
-
-    let (sender, receiver) = tokio::sync::oneshot::channel();
-    app.dialog()
-        .message("This recording will not include your voice.")
-        .title("No microphone detected")
-        .kind(MessageDialogKind::Warning)
-        .buttons(MessageDialogButtons::OkCancelCustom(
-            "Record without microphone".to_string(),
-            "Cancel".to_string(),
-        ))
-        .show(move |confirmed| {
-            let _ = sender.send(confirmed);
-        });
-
-    receiver.await.unwrap_or(false)
-}
-
-async fn start_recording_from_hotkey(
-    app: AppHandle,
-    mode: cap_recording::RecordingMode,
-) -> Result<(), String> {
-    if app
-        .state::>()
-        .read()
-        .await
-        .is_recording_active_or_pending()
-    {
-        let _ = RequestStartRecording { mode }.emit(&app);
-        return Ok(());
-    }
-
-    if confirm_direct_recording_without_microphone(&app).await {
-        let _ = RequestStartRecording { mode }.emit(&app);
-    }
-
-    Ok(())
-}
-
-fn spawn_shortcut_task(task: F)
-where
-    F: Future + Send + 'static,
-    F::Output: Send + 'static,
-{
-    drop(tauri::async_runtime::spawn(task));
-}
-
-pub fn init(app: &AppHandle) {
-    app.plugin(
-        tauri_plugin_global_shortcut::Builder::new()
-            .with_handler(|app, shortcut, event| {
-                if *shortcut == clean_capture_shortcut()
-                    && crate::clean_capture::handle_shortcut(
-                        app,
-                        event.state() == HotKeyState::Pressed,
-                    )
-                {
-                    return;
-                }
-                if !matches!(event.state(), HotKeyState::Pressed) {
-                    return;
-                }
-
-                if shortcut.key == Code::Escape {
-                    // This handler runs on the main thread while the plugin
-                    // holds its shortcut registry lock. Dismissing the picker
-                    // ends the picker session, which unregisters Escape through
-                    // that same lock, so doing it inline deadlocks the main
-                    // thread (overlay stuck on screen, app frozen). Defer it.
-                    let dismiss_app = app.clone();
-                    spawn_shortcut_task(async move {
-                        crate::target_select_overlay::dismiss_picker_from_escape(&dismiss_app);
-                    });
-                    OnEscapePress.emit(app).ok();
-                }
-
-                if shortcut.key == Code::Comma && shortcut.mods == Modifiers::META {
-                    let app = app.clone();
-                    spawn_shortcut_task(async move {
-                        let _ = ShowCapWindow::Settings { page: None }.show(&app).await;
-                    });
-                }
-
-                let state = app.state::();
-                let store = state.lock().unwrap();
-
-                for (action, hotkey) in &store.hotkeys {
-                    if &Shortcut::from(*hotkey) == shortcut {
-                        spawn_shortcut_task(handle_hotkey(app.clone(), *action));
-                    }
-                }
-            })
-            .build(),
-    )
-    .unwrap();
-
-    let store = match HotkeysStore::get(app) {
-        Ok(Some(s)) => s,
-        Ok(None) => HotkeysStore::default(),
-        Err(e) => {
-            tracing::error!("Failed to load hotkeys store: {e}");
-            HotkeysStore::default()
-        }
-    };
-
-    let global_shortcut = app.global_shortcut();
-    for hotkey in store.hotkeys.values() {
-        global_shortcut.register(Shortcut::from(*hotkey)).ok();
-    }
-
-    app.manage(Mutex::new(store));
-}
-
-async fn handle_hotkey(app: AppHandle, action: HotkeyAction) -> Result<(), String> {
-    match action {
-        HotkeyAction::StartStudioRecording => {
-            start_recording_from_hotkey(app, cap_recording::RecordingMode::Studio).await
-        }
-        HotkeyAction::StartInstantRecording => {
-            start_recording_from_hotkey(app, cap_recording::RecordingMode::Instant).await
-        }
-        HotkeyAction::StopRecording => recording::stop_recording(app.clone(), app.state()).await,
-        HotkeyAction::RestartRecording => recording::restart_recording(app.clone(), app.state())
-            .await
-            .map(|_| ()),
-        HotkeyAction::TogglePauseRecording => {
-            recording::toggle_pause_recording(app.clone(), app.state()).await
-        }
-        HotkeyAction::CycleRecordingMode => {
-            let current = RecordingSettingsStore::get(&app)
-                .ok()
-                .flatten()
-                .and_then(|s| s.mode)
-                .unwrap_or_default();
-
-            let next = match current {
-                cap_recording::RecordingMode::Studio => cap_recording::RecordingMode::Instant,
-                cap_recording::RecordingMode::Instant => cap_recording::RecordingMode::Screenshot,
-                cap_recording::RecordingMode::Screenshot => cap_recording::RecordingMode::Studio,
-            };
-
-            RecordingSettingsStore::set_mode(&app, next)
-                .map_err(|e| format!("Failed to cycle mode: {e}"))?;
-
-            tray::update_tray_icon_for_mode(&app, next);
-
-            Ok(())
-        }
-        HotkeyAction::OpenRecordingPicker => {
-            let _ = RequestOpenRecordingPicker { target_mode: None }.emit(&app);
-            Ok(())
-        }
-        HotkeyAction::OpenRecordingPickerDisplay => {
-            let _ = RequestOpenRecordingPicker {
-                target_mode: Some(RecordingTargetMode::Display),
-            }
-            .emit(&app);
-            Ok(())
-        }
-        HotkeyAction::OpenRecordingPickerWindow => {
-            let _ = RequestOpenRecordingPicker {
-                target_mode: Some(RecordingTargetMode::Window),
-            }
-            .emit(&app);
-            Ok(())
-        }
-        HotkeyAction::OpenRecordingPickerArea => {
-            let _ = RequestOpenRecordingPicker {
-                target_mode: Some(RecordingTargetMode::Area),
-            }
-            .emit(&app);
-            Ok(())
-        }
-        HotkeyAction::ScreenshotDisplay => {
-            use scap_targets::Display;
-
-            let display = Display::get_containing_cursor().unwrap_or_else(Display::primary);
-            let target = ScreenCaptureTarget::Display { id: display.id() };
-
-            match recording::take_screenshot(app.clone(), target.clone()).await {
-                Ok(path) => {
-                    if crate::automation::should_open_screenshot_editor(&app, &target) {
-                        let _ = ShowCapWindow::ScreenshotEditor { path }.show(&app).await;
-                    }
-                    Ok(())
-                }
-                Err(e) => Err(format!("Failed to take screenshot: {e}")),
-            }
-        }
-        HotkeyAction::ScreenshotWindow => {
-            use scap_targets::Window;
-
-            let target = {
-                let window = Window::get_topmost_at_cursor()
-                    .ok_or_else(|| "No window found under cursor".to_string())?;
-                ScreenCaptureTarget::Window { id: window.id() }
-            };
-
-            match recording::take_screenshot(app.clone(), target.clone()).await {
-                Ok(path) => {
-                    if crate::automation::should_open_screenshot_editor(&app, &target) {
-                        let _ = ShowCapWindow::ScreenshotEditor { path }.show(&app).await;
-                    }
-                    Ok(())
-                }
-                Err(e) => Err(format!("Failed to take screenshot: {e}")),
-            }
-        }
-        HotkeyAction::ScreenshotArea => {
-            RecordingSettingsStore::set_mode(&app, cap_recording::RecordingMode::Screenshot)
-                .map_err(|e| format!("Failed to set screenshot mode: {e}"))?;
-
-            tray::update_tray_icon_for_mode(&app, cap_recording::RecordingMode::Screenshot);
-
-            let _ = RequestOpenRecordingPicker {
-                target_mode: Some(RecordingTargetMode::Area),
-            }
-            .emit(&app);
-            Ok(())
-        }
-        HotkeyAction::Other => Ok(()),
-    }
-}
-
-#[tauri::command(async)]
-#[specta::specta]
-#[instrument(skip(app))]
-pub fn set_hotkey(app: AppHandle, action: HotkeyAction, hotkey: Option) -> Result<(), ()> {
-    let global_shortcut = app.global_shortcut();
-    let state = app.state::();
-    let mut store = state.lock().unwrap();
-    if crate::clean_capture::phase(&app).is_some() {
-        return Err(());
-    }
-
-    let prev = store.hotkeys.get(&action).cloned();
-
-    if let Some(hotkey) = hotkey {
-        store.hotkeys.insert(action, hotkey);
-    } else {
-        store.hotkeys.remove(&action);
-    }
-
-    if let Some(prev) = prev
-        && !store.hotkeys.values().any(|h| h == &prev)
-    {
-        global_shortcut.unregister(Shortcut::from(prev)).ok();
-    }
-
-    if let Some(hotkey) = hotkey {
-        global_shortcut.register(Shortcut::from(hotkey)).ok();
-    }
-
-    Ok(())
-}
-
-#[cfg(target_os = "linux")]
-pub(crate) struct WaylandStop {
-    generation: u32,
-    cancel: tokio::sync::watch::Sender,
-    task: Option>>,
-    completed: Option>,
-}
-
-#[cfg(target_os = "linux")]
-pub(crate) async fn reserve_wayland_stop(app: &AppHandle, generation: u32) -> Result<(), String> {
-    let state = app.state::();
-    let mut owned = state.portal_stop.lock().await;
-    if owned.is_some() {
-        return Err("Previous Wayland Stop session has not closed".into());
-    }
-    let (cancel, receiver) = tokio::sync::watch::channel(false);
-    let handle = app.clone();
-    let task = tauri::async_runtime::spawn(async move {
-        if run_wayland_tray(&handle, generation, receiver.clone()).await? {
-            Ok(())
-        } else {
-            run_wayland_stop(&handle, generation, receiver).await
-        }
-    });
-    *owned = Some(WaylandStop {
-        generation,
-        cancel,
-        task: Some(task),
-        completed: None,
-    });
-    Ok(())
-}
-
-#[cfg(target_os = "linux")]
-async fn run_wayland_stop(
-    app: &AppHandle,
-    generation: u32,
-    mut cancel: tokio::sync::watch::Receiver,
-) -> Result<(), String> {
-    use ashpd::desktop::global_shortcuts::{GlobalShortcuts, NewShortcut};
-    use futures::StreamExt;
-    let portal = tokio::select! {
-        _ = cancel.changed() => return Ok(()),
-        result = GlobalShortcuts::new() => match result {
-            Ok(portal) => portal,
-            Err(error) => { report_wayland_stop_loss(app, generation, &error.to_string()); return Ok(()); }
-        },
-    };
-    if *cancel.borrow() {
-        return Ok(());
-    }
-    // Keep session creation owned even if Stop arrives while the portal replies;
-    // dropping CreateSession could lose the only handle needed to close it.
-    let session = match portal.create_session().await {
-        Ok(session) => session,
-        Err(error) => {
-            report_wayland_stop_loss(app, generation, &error.to_string());
-            return Ok(());
-        }
-    };
-    let result = async {
-        let session_path = serde_json::to_value(&session).map_err(|error| error.to_string())?;
-        let session_path = session_path
-            .as_str()
-            .ok_or("Invalid Stop session identity")?;
-        let id = format!("cap-clean-stop-{generation}");
-        let mut activated = portal
-            .receive_activated()
-            .await
-            .map_err(|error| error.to_string())?;
-        let mut deactivated = portal
-            .receive_deactivated()
-            .await
-            .map_err(|error| error.to_string())?;
-        let mut closed = session
-            .receive_closed()
-            .await
-            .map_err(|error| error.to_string())?;
-        let bound = portal
-            .bind_shortcuts(
-                &session,
-                &[NewShortcut::new(&id, "Start or stop Cap clean recording")
-                    .preferred_trigger(Some("CTRL+SHIFT+F9"))],
-                None,
-            )
-            .await
-            .map_err(|error| error.to_string())?
-            .response()
-            .map_err(|error| error.to_string())?;
-        let shortcut = bound
-            .shortcuts()
-            .iter()
-            .find(|shortcut| shortcut.id() == id)
-            .ok_or("Stop shortcut was not granted")?;
-        crate::clean_capture::describe_wayland_stop(
-            app,
-            generation,
-            format!("{} (desktop shortcut)", shortcut.trigger_description()),
-        );
-        loop {
-            tokio::select! {
-                event = activated.next() => match event {
-                    Some(event) if event.session_handle().as_str() == session_path && event.shortcut_id() == id => {
-                        crate::clean_capture::handle_wayland_stop(app, generation, crate::clean_capture::StopRoute::Portal, true);
-                    }
-                    Some(_) => {}
-                    None => return Err("Stop shortcut event stream closed".into()),
-                },
-                event = deactivated.next() => match event {
-                    Some(event) if event.session_handle().as_str() == session_path && event.shortcut_id() == id => {
-                        crate::clean_capture::handle_wayland_stop(app, generation, crate::clean_capture::StopRoute::Portal, false);
-                    }
-                    Some(_) => {}
-                    None => return Err("Stop shortcut event stream closed".into()),
-                },
-                _ = closed.next() => return Err("Stop shortcut session was revoked".into()),
-            }
-        }
-    };
-    let result: Result<(), String> = if *cancel.borrow() {
-        Ok(())
-    } else {
-        tokio::select! {
-            _ = cancel.changed() => Ok(()),
-            result = result => result,
-        }
-    };
-    if let Err(error) = &result {
-        report_wayland_stop_loss(app, generation, error);
-    }
-    tokio::time::timeout(std::time::Duration::from_secs(2), session.close())
-        .await
-        .map_err(|_| "Stop session close timed out".to_string())?
-        .map_err(|error| error.to_string())?;
-    Ok(())
-}
-
-#[cfg(target_os = "linux")]
-fn report_wayland_stop_loss(app: &AppHandle, generation: u32, error: &str) {
-    crate::clean_capture::wayland_stop_lost(
-        app,
-        generation,
-        crate::clean_capture::StopRoute::Portal,
-        error.to_string(),
-    );
-}
-
-#[cfg(target_os = "linux")]
-pub(crate) async fn release_wayland_stop(app: &AppHandle, generation: u32) -> Result<(), String> {
-    let state = app.state::();
-    let mut owned = state.portal_stop.lock().await;
-    let Some(stop) = owned.as_mut().filter(|stop| stop.generation == generation) else {
-        return Ok(());
-    };
-    if let Some(result) = &stop.completed {
-        return result.clone();
-    }
-    let _ = stop.cancel.send(true);
-    let task = stop
-        .task
-        .as_mut()
-        .ok_or("Stop session worker ownership was lost")?;
-    let joined = tokio::time::timeout(std::time::Duration::from_secs(3), task)
-        .await
-        .map_err(|_| "Stop session worker has not joined".to_string())?;
-    let _finished = stop.task.take();
-    let result = joined
-        .map_err(|error| error.to_string())
-        .and_then(|result| result);
-    stop.completed = Some(result.clone());
-    if result.is_ok() {
-        let _released = owned.take();
-    }
-    result
-}
-
-#[cfg(target_os = "linux")]
-async fn run_wayland_tray(
-    app: &AppHandle,
-    generation: u32,
-    mut cancel: tokio::sync::watch::Receiver,
-) -> Result {
-    use cap_utils::linux_recording_stop::{StopTray, StopTrayEvent};
-    let icon = match crate::tray::clean_stop_icon() {
-        Ok(icon) => icon,
-        Err(error) => {
-            crate::clean_capture::wayland_stop_lost(
-                app,
-                generation,
-                crate::clean_capture::StopRoute::Tray,
-                error,
-            );
-            return Ok(false);
-        }
-    };
-    let tray = match StopTray::open(u64::from(generation), icon).await {
-        Ok(tray) => tray,
-        Err(error) => {
-            let can_fallback = error.can_fallback();
-            let message = error.to_string();
-            crate::clean_capture::wayland_stop_lost(
-                app,
-                generation,
-                crate::clean_capture::StopRoute::Tray,
-                message.clone(),
-            );
-            if !can_fallback {
-                crate::clean_capture::wayland_stop_lost(
-                    app,
-                    generation,
-                    crate::clean_capture::StopRoute::Portal,
-                    message.clone(),
-                );
-                return Err(message);
-            }
-            return Ok(false);
-        }
-    };
-    let events = tray.events();
-    let mut used = false;
-    let mut cancelled = false;
-    loop {
-        tokio::select! {
-            _ = cancel.changed() => { cancelled = true; break; },
-            event = events.recv_async() => match event {
-                Ok(StopTrayEvent::Activated { generation: received }) if received == u64::from(generation) => {
-                    used = true;
-                    crate::clean_capture::handle_wayland_stop(app, generation, crate::clean_capture::StopRoute::Tray, true);
-                    crate::clean_capture::handle_wayland_stop(app, generation, crate::clean_capture::StopRoute::Tray, false);
-                }
-                Ok(StopTrayEvent::Unavailable { generation: received }) if received == u64::from(generation) => {
-                    crate::clean_capture::wayland_stop_lost(app, generation, crate::clean_capture::StopRoute::Tray, "The Stop tray host is unavailable".into());
-                    break;
-                }
-                Ok(_) => {}
-                Err(_) => {
-                    crate::clean_capture::wayland_stop_lost(app, generation, crate::clean_capture::StopRoute::Tray, "The Stop tray event stream closed".into());
-                    break;
-                }
-            }
-        }
-    }
-    tray.close().await?;
-    Ok(used || cancelled)
-}
-
-#[cfg(test)]
-mod tests {
-    use super::{
-        microphone_available_for_confirmation, should_confirm_without_microphone,
-        spawn_shortcut_task,
-    };
-    use std::time::Duration;
-
-    #[test]
-    fn microphone_confirmation_does_not_probe_without_permission_or_selection() {
-        assert!(
-            microphone_available_for_confirmation(
-                Some("Saved microphone"),
-                || Err("Permission denied".into()),
-                |_| panic!("denied microphone must not be enumerated"),
-            )
-            .unwrap_err()
-            .contains("turn the microphone Off")
-        );
-        assert!(
-            !microphone_available_for_confirmation(
-                None,
-                || panic!("disabled microphone does not need permission"),
-                |_| panic!("disabled microphone must not be enumerated"),
-            )
-            .unwrap()
-        );
-    }
-
-    #[test]
-    fn microphone_confirmation_checks_only_the_requested_name_after_grant() {
-        assert!(
-            microphone_available_for_confirmation(
-                Some("Saved microphone"),
-                || Ok(()),
-                |name| name == "Saved microphone",
-            )
-            .unwrap()
-        );
-        let error = microphone_available_for_confirmation(
-            Some("Disconnected microphone"),
-            || Ok(()),
-            |_| false,
-        )
-        .unwrap_err();
-        assert!(error.contains("Reconnect it"));
-        assert!(error.contains("turn the microphone Off"));
-    }
-
-    #[test]
-    fn clean_capture_reuses_only_an_existing_stop_binding() {
-        let hotkey = super::Hotkey {
-            code: super::Code::F9,
-            meta: false,
-            ctrl: true,
-            alt: false,
-            shift: true,
-        };
-        let mut store = super::HotkeysStore::default();
-        assert!(!super::existing_clean_capture_stop(&store).unwrap());
-        store
-            .hotkeys
-            .insert(super::HotkeyAction::StopRecording, hotkey);
-        assert!(super::existing_clean_capture_stop(&store).unwrap());
-        store
-            .hotkeys
-            .insert(super::HotkeyAction::StartStudioRecording, hotkey);
-        assert!(super::existing_clean_capture_stop(&store).is_err());
-    }
-
-    #[test]
-    fn shortcut_dispatch_runs_from_thread_without_tokio_runtime() {
-        let (sent, received) = std::sync::mpsc::channel();
-        let caller = std::thread::spawn(move || {
-            assert!(tokio::runtime::Handle::try_current().is_err());
-            let caller_id = std::thread::current().id();
-            spawn_shortcut_task(async move {
-                assert!(tokio::runtime::Handle::try_current().is_ok());
-                tokio::time::sleep(Duration::from_millis(1)).await;
-                sent.send((caller_id, std::thread::current().id())).unwrap();
-                Ok::<(), String>(())
-            });
-        });
-        caller.join().expect("OS callback thread must not panic");
-        let (caller_id, task_id) = received
-            .recv_timeout(Duration::from_secs(2))
-            .expect("Shortcut action must run on the application runtime");
-        assert_ne!(caller_id, task_id);
-    }
-
-    #[test]
-    fn shortcut_dispatch_keeps_detached_settings_task_alive() {
-        let (sent, received) = std::sync::mpsc::channel();
-        std::thread::spawn(move || {
-            assert!(tokio::runtime::Handle::try_current().is_err());
-            spawn_shortcut_task(async move {
-                tokio::time::sleep(Duration::from_millis(1)).await;
-                sent.send(()).unwrap();
-            });
-        })
-        .join()
-        .expect("OS callback thread must not panic");
-        received
-            .recv_timeout(Duration::from_secs(2))
-            .expect("Detached settings task must complete");
-    }
-
-    #[test]
-    fn confirms_when_enabled_without_microphone() {
-        assert!(should_confirm_without_microphone(true, false));
-    }
-
-    #[test]
-    fn skips_confirmation_with_selected_microphone() {
-        assert!(!should_confirm_without_microphone(true, true));
-    }
-
-    #[test]
-    fn skips_confirmation_when_disabled() {
-        assert!(!should_confirm_without_microphone(false, false));
-    }
-}
diff --git a/apps/desktop/src-tauri/src/http_client.rs b/apps/desktop/src-tauri/src/http_client.rs
deleted file mode 100644
index bebaf889669..00000000000
--- a/apps/desktop/src-tauri/src/http_client.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-//! We reuse clients so we get connection pooling and also so the retry policy can handle backing off across requests.
-
-use std::ops::Deref;
-
-use reqwest::StatusCode;
-
-pub struct HttpClient(reqwest::Client);
-
-impl Default for HttpClient {
-    fn default() -> Self {
-        Self(
-            reqwest::Client::builder()
-                .connect_timeout(std::time::Duration::from_secs(10))
-                .timeout(std::time::Duration::from_secs(30))
-                .build()
-                .expect("Failed to build HTTP client"),
-        )
-    }
-}
-
-impl Deref for HttpClient {
-    type Target = reqwest::Client;
-
-    fn deref(&self) -> &Self::Target {
-        &self.0
-    }
-}
-
-pub struct RetryableHttpClient(reqwest::Result);
-
-impl Default for RetryableHttpClient {
-    fn default() -> Self {
-        Self(
-            reqwest::Client::builder()
-                .connect_timeout(std::time::Duration::from_secs(10))
-                .retry(
-                    reqwest::retry::always()
-                        .classify_fn(|req_rep| match req_rep.status() {
-                            Some(s)
-                                if s.is_server_error() || s == StatusCode::TOO_MANY_REQUESTS =>
-                            {
-                                req_rep.retryable()
-                            }
-                            None => req_rep.retryable(),
-                            _ => req_rep.success(),
-                        })
-                        .max_retries_per_request(5)
-                        .max_extra_load(5.0),
-                )
-                .build(),
-        )
-    }
-}
-
-impl Deref for RetryableHttpClient {
-    type Target = reqwest::Result;
-
-    fn deref(&self) -> &Self::Target {
-        &self.0
-    }
-}
diff --git a/apps/desktop/src-tauri/src/import.rs b/apps/desktop/src-tauri/src/import.rs
deleted file mode 100644
index 3b517fcd546..00000000000
--- a/apps/desktop/src-tauri/src/import.rs
+++ /dev/null
@@ -1,2268 +0,0 @@
-use cap_enc_ffmpeg::{
-    AudioEncoder,
-    h264::{H264EncoderBuilder, H264Preset},
-    opus::OpusEncoder,
-    remux::{get_media_duration, probe_video_can_decode},
-};
-use cap_media_info::{AudioInfo, FFRational, Pixel, VideoInfo, ensure_even};
-use cap_project::{
-    AudioMeta, ClipConfiguration, CursorEvents, CursorMeta, Cursors, InstantRecordingMeta,
-    MultipleSegment, MultipleSegments, Platform, ProjectConfiguration, RecordingMeta,
-    RecordingMetaInner, SingleSegment, StudioRecordingMeta, StudioRecordingStatus,
-    TimelineConfiguration, TimelineSegment, VideoMeta, XY,
-};
-use ffmpeg::{
-    ChannelLayout,
-    codec::{self as avcodec},
-    format::{self as avformat},
-};
-use image::ImageEncoder;
-use relative_path::{Component as RelativeComponent, RelativePathBuf};
-use serde::{Deserialize, Serialize};
-use specta::Type;
-use std::{
-    collections::HashMap,
-    path::{Path, PathBuf},
-    str::FromStr,
-};
-use tauri::{AppHandle, Manager, Window};
-use tauri_specta::Event;
-use tracing::{debug, error, info};
-
-use crate::{
-    create_screenshot,
-    editor_window::EditorInstances,
-    windows::{CapWindowId, EditorWindowIds},
-};
-
-const VIDEO_IMPORT_EXTENSIONS: &[&str] = &["mp4", "mov", "avi", "mkv", "webm", "wmv", "m4v", "flv"];
-const IMAGE_IMPORT_EXTENSIONS: &[&str] =
-    &["png", "jpg", "jpeg", "webp", "gif", "bmp", "tif", "tiff"];
-const AUDIO_IMPORT_EXTENSIONS: &[&str] = &["ogg", "m4a", "mp3", "wav", "aac", "flac"];
-const KEYBOARD_IMPORT_EXTENSIONS: &[&str] = &["bin", "json"];
-const CURSOR_EVENTS_IMPORT_EXTENSIONS: &[&str] = &["json"];
-const MAX_IMAGE_DIMENSION: u32 = 16_384;
-
-#[derive(Serialize, Deserialize, Type, Clone, Debug)]
-pub enum ImportStage {
-    Probing,
-    Converting,
-    Finalizing,
-    Complete,
-    Failed,
-}
-
-#[derive(Serialize, Deserialize, Type, tauri_specta::Event, Clone, Debug)]
-pub struct VideoImportProgress {
-    pub project_path: String,
-    pub stage: ImportStage,
-    pub progress: f64,
-    pub message: String,
-}
-
-#[derive(Debug, thiserror::Error)]
-pub enum ImportError {
-    #[error("Failed to open video file: {0}")]
-    OpenFailed(String),
-    #[error("No video stream found in file")]
-    NoVideoStream,
-    #[error("Failed to create decoder: {0}")]
-    DecoderFailed(String),
-    #[error("Failed to create encoder: {0}")]
-    EncoderFailed(String),
-    #[error("Failed to create project directory: {0}")]
-    DirectoryFailed(std::io::Error),
-    #[error("FFmpeg error: {0}")]
-    Ffmpeg(#[from] ffmpeg::Error),
-    #[error("Transcoding failed: {0}")]
-    TranscodeFailed(String),
-}
-
-fn emit_progress(
-    app: &AppHandle,
-    project_path: &str,
-    stage: ImportStage,
-    progress: f64,
-    message: &str,
-) {
-    let _ = VideoImportProgress {
-        project_path: project_path.to_string(),
-        stage,
-        progress,
-        message: message.to_string(),
-    }
-    .emit(app);
-}
-
-fn check_project_exists(project_path: &Path) -> bool {
-    project_path.exists() && project_path.join("recording-meta.json").exists()
-}
-
-fn generate_project_name(source_path: &Path) -> String {
-    let stem = source_path
-        .file_stem()
-        .and_then(|s| s.to_str())
-        .unwrap_or("Imported Video");
-
-    let now = chrono::Local::now();
-    let date_str = now.format("%Y-%m-%d at %H.%M.%S").to_string();
-
-    format!("{stem} {date_str}")
-}
-
-fn generate_image_project_name(source_path: &Path) -> String {
-    let stem = source_path
-        .file_stem()
-        .and_then(|s| s.to_str())
-        .unwrap_or("Imported Image");
-
-    let now = chrono::Local::now();
-    let date_str = now.format("%Y-%m-%d at %H.%M.%S").to_string();
-
-    format!("{stem} {date_str}")
-}
-
-fn sanitize_filename(name: &str) -> String {
-    name.chars()
-        .map(|c| match c {
-            '/' | '\\' | ':' | '*' | '?' | '"' | '<' | '>' | '|' => '_',
-            _ => c,
-        })
-        .collect()
-}
-
-fn has_supported_extension(path: &Path, extensions: &[&str]) -> bool {
-    path.extension()
-        .and_then(|s| s.to_str())
-        .is_some_and(|ext| {
-            extensions
-                .iter()
-                .any(|candidate| ext.eq_ignore_ascii_case(candidate))
-        })
-}
-
-pub fn is_supported_video_import_path(path: &Path) -> bool {
-    path.is_file() && has_supported_extension(path, VIDEO_IMPORT_EXTENSIONS)
-}
-
-pub fn is_supported_image_import_path(path: &Path) -> bool {
-    path.is_file() && has_supported_extension(path, IMAGE_IMPORT_EXTENSIONS)
-}
-
-fn is_mp4_import_path(path: &Path) -> bool {
-    path.is_file()
-        && path
-            .extension()
-            .and_then(|s| s.to_str())
-            .is_some_and(|ext| ext.eq_ignore_ascii_case("mp4"))
-}
-
-fn is_cap_project_path(path: &Path) -> bool {
-    path.is_dir() && path.join("recording-meta.json").is_file()
-}
-
-fn normalized_metadata_relative_path(
-    path: &RelativePathBuf,
-    asset_kind: &str,
-) -> Result {
-    let normalized = path.as_str().replace('\\', "/");
-    let path = RelativePathBuf::from(normalized);
-    let raw = path.as_str();
-    if raw.is_empty()
-        || raw.starts_with('/')
-        || raw.contains(':')
-        || path
-            .components()
-            .any(|component| matches!(component, RelativeComponent::ParentDir))
-    {
-        return Err(format!(
-            "Invalid {asset_kind} path in recording metadata: {raw}"
-        ));
-    }
-
-    Ok(path)
-}
-
-fn source_asset_path(
-    source_project_path: &Path,
-    source_relative_path: &RelativePathBuf,
-    asset_kind: &str,
-    allowed_extensions: &[&str],
-) -> Result, String> {
-    let source_relative_path = normalized_metadata_relative_path(source_relative_path, asset_kind)?;
-
-    if !has_supported_extension(Path::new(source_relative_path.as_str()), allowed_extensions) {
-        return Err(format!(
-            "Unsupported {asset_kind} file type: {}",
-            source_relative_path.as_str()
-        ));
-    }
-
-    let source_path = source_relative_path.to_path(source_project_path);
-    if !source_path.is_file() {
-        return Ok(None);
-    }
-
-    let source_root = source_project_path
-        .canonicalize()
-        .map_err(|e| format!("Failed to resolve source project path: {e}"))?;
-    let canonical_source_path = source_path
-        .canonicalize()
-        .map_err(|e| format!("Failed to resolve {asset_kind} path: {e}"))?;
-
-    if !canonical_source_path.starts_with(&source_root) {
-        return Err(format!(
-            "{asset_kind} path escapes source project: {}",
-            source_relative_path.as_str()
-        ));
-    }
-
-    Ok(Some(canonical_source_path))
-}
-
-fn required_source_asset_path(
-    source_project_path: &Path,
-    source_relative_path: &RelativePathBuf,
-    asset_kind: &str,
-    allowed_extensions: &[&str],
-) -> Result {
-    source_asset_path(
-        source_project_path,
-        source_relative_path,
-        asset_kind,
-        allowed_extensions,
-    )?
-    .ok_or_else(|| {
-        format!(
-            "Missing {asset_kind} file: {}",
-            source_relative_path.to_path(source_project_path).display()
-        )
-    })
-}
-
-fn legacy_cursor_relative_path(path: &str) -> Result {
-    normalized_metadata_relative_path(&RelativePathBuf::from(path), "cursor image")
-}
-
-fn editor_project_path_from_window(window: &Window) -> Result {
-    let CapWindowId::Editor { id } =
-        CapWindowId::from_str(window.label()).map_err(|e| e.to_string())?
-    else {
-        return Err("Import can only be started from an editor window".to_string());
-    };
-
-    let window_ids = EditorWindowIds::get(window.app_handle());
-    let window_ids = window_ids
-        .ids
-        .lock()
-        .map_err(|_| "Editor window registry unavailable".to_string())?;
-
-    window_ids
-        .iter()
-        .find(|(_, window_id)| *window_id == id)
-        .map(|(path, _)| path.clone())
-        .ok_or_else(|| "Editor project path not found".to_string())
-}
-
-fn same_project_path(a: &Path, b: &Path) -> bool {
-    let a = a.canonicalize().unwrap_or_else(|_| a.to_path_buf());
-    let b = b.canonicalize().unwrap_or_else(|_| b.to_path_buf());
-    a == b
-}
-
-fn ensure_multiple_segments(meta: &mut RecordingMeta) -> Result<&mut MultipleSegments, String> {
-    let RecordingMetaInner::Studio(studio_meta) = &mut meta.inner else {
-        return Err("Instant mode recordings cannot be edited".to_string());
-    };
-
-    if let StudioRecordingMeta::SingleSegment { segment } = studio_meta.as_ref() {
-        let segment = segment.clone();
-        **studio_meta = StudioRecordingMeta::MultipleSegments {
-            inner: MultipleSegments {
-                segments: vec![MultipleSegment {
-                    display: segment.display,
-                    camera: segment.camera,
-                    mic: segment.audio,
-                    system_audio: None,
-                    cursor: segment.cursor,
-                    keyboard: None,
-                    display_notch: None,
-                }],
-                cursors: Cursors::default(),
-                status: Some(StudioRecordingStatus::Complete),
-            },
-        };
-    }
-
-    match studio_meta.as_mut() {
-        StudioRecordingMeta::MultipleSegments { inner } => Ok(inner),
-        StudioRecordingMeta::SingleSegment { .. } => {
-            Err("Failed to normalize project recording segments".to_string())
-        }
-    }
-}
-
-fn get_video_duration_secs(path: &Path) -> Result {
-    get_media_duration(path)
-        .map(|duration| duration.as_secs_f64())
-        .ok_or_else(|| format!("Could not determine video duration: {}", path.display()))
-}
-
-fn full_timeline_for_segments(
-    project_path: &Path,
-    segments: &[MultipleSegment],
-) -> Result, String> {
-    segments
-        .iter()
-        .enumerate()
-        .map(|(index, segment)| {
-            let duration = get_video_duration_secs(&segment.display.path.to_path(project_path))?;
-            Ok(TimelineSegment {
-                recording_clip: index as u32,
-                timescale: 1.0,
-                start: 0.0,
-                end: duration,
-                name: None,
-                speed_audio_mode: None,
-                hide_cursor: None,
-                volume: None,
-            })
-        })
-        .collect()
-}
-
-fn get_source_video_duration_secs(
-    source_meta: &RecordingMeta,
-    video: &VideoMeta,
-) -> Result {
-    let source_path = required_source_asset_path(
-        &source_meta.project_path,
-        &video.path,
-        "video",
-        VIDEO_IMPORT_EXTENSIONS,
-    )?;
-    get_video_duration_secs(&source_path)
-}
-
-fn full_timeline_for_source_segments(
-    source_meta: &RecordingMeta,
-    segments: &[MultipleSegment],
-) -> Result, String> {
-    segments
-        .iter()
-        .enumerate()
-        .map(|(index, segment)| {
-            let duration = get_source_video_duration_secs(source_meta, &segment.display)?;
-            Ok(TimelineSegment {
-                recording_clip: index as u32,
-                timescale: 1.0,
-                start: 0.0,
-                end: duration,
-                name: None,
-                speed_audio_mode: None,
-                hide_cursor: None,
-                volume: None,
-            })
-        })
-        .collect()
-}
-
-fn ensure_project_timeline<'a>(
-    config: &'a mut ProjectConfiguration,
-    project_path: &Path,
-    segments: &[MultipleSegment],
-) -> Result<&'a mut TimelineConfiguration, String> {
-    if config.timeline.is_none() {
-        config.timeline = Some(TimelineConfiguration {
-            segments: full_timeline_for_segments(project_path, segments)?,
-            transitions: Vec::new(),
-            zoom_segments: Vec::new(),
-            scene_segments: Vec::new(),
-            style_segments: Vec::new(),
-            image_segments: Vec::new(),
-            mask_segments: Vec::new(),
-            text_segments: Vec::new(),
-            caption_segments: Vec::new(),
-            keyboard_segments: Vec::new(),
-            audio_segments: Vec::new(),
-            camera3d_segments: Vec::new(),
-        });
-    }
-
-    config
-        .timeline
-        .as_mut()
-        .ok_or_else(|| "Failed to prepare project timeline".to_string())
-}
-
-fn add_clip_configs(
-    config: &mut ProjectConfiguration,
-    base_index: u32,
-    segments: &[MultipleSegment],
-) {
-    for (offset, segment) in segments.iter().enumerate() {
-        let index = base_index + offset as u32;
-        let offsets = segment.calculate_audio_offsets();
-
-        if let Some(existing) = config.clips.iter_mut().find(|clip| clip.index == index) {
-            existing.offsets = offsets;
-            existing.offsets_auto_calculated = true;
-        } else {
-            config.clips.push(ClipConfiguration {
-                index,
-                offsets,
-                offsets_auto_calculated: true,
-            });
-        }
-    }
-}
-
-fn unique_segment_dir(
-    project_path: &Path,
-    index: u32,
-) -> Result<(PathBuf, String), std::io::Error> {
-    let segments_root = project_path.join("content").join("segments");
-    std::fs::create_dir_all(&segments_root)?;
-
-    let mut counter = 0;
-    loop {
-        let name = if counter == 0 {
-            format!("segment-{index}")
-        } else {
-            format!("segment-{index}-import-{counter}")
-        };
-        let path = segments_root.join(&name);
-        if !path.exists() {
-            std::fs::create_dir_all(&path)?;
-            return Ok((path, format!("content/segments/{name}")));
-        }
-        counter += 1;
-    }
-}
-
-fn relative_file_extension(path: &RelativePathBuf, fallback: &str) -> String {
-    Path::new(path.as_str())
-        .extension()
-        .and_then(|ext| ext.to_str())
-        .filter(|ext| !ext.is_empty())
-        .unwrap_or(fallback)
-        .to_string()
-}
-
-fn relative_file_name(path: &RelativePathBuf, fallback: &str) -> String {
-    Path::new(path.as_str())
-        .file_name()
-        .and_then(|name| name.to_str())
-        .filter(|name| !name.is_empty())
-        .unwrap_or(fallback)
-        .to_string()
-}
-
-fn unique_file_name(dir: &Path, preferred: &str) -> String {
-    let sanitized = sanitize_filename(preferred);
-    let sanitized = if sanitized.is_empty() {
-        "file".to_string()
-    } else {
-        sanitized
-    };
-
-    let path = Path::new(&sanitized);
-    let stem = path
-        .file_stem()
-        .and_then(|value| value.to_str())
-        .filter(|value| !value.is_empty())
-        .unwrap_or("file")
-        .to_string();
-    let extension = path
-        .extension()
-        .and_then(|value| value.to_str())
-        .filter(|value| !value.is_empty())
-        .map(|value| value.to_string());
-
-    let mut counter = 0;
-    loop {
-        let candidate = if counter == 0 {
-            sanitized.clone()
-        } else if let Some(extension) = &extension {
-            format!("{stem}-{counter}.{extension}")
-        } else {
-            format!("{stem}-{counter}")
-        };
-
-        if !dir.join(&candidate).exists() {
-            return candidate;
-        }
-
-        counter += 1;
-    }
-}
-
-fn copy_file_to_relative_path(
-    source_path: &Path,
-    target_project_path: &Path,
-    target_relative_path: &RelativePathBuf,
-) -> Result<(), String> {
-    let target_path = target_relative_path.to_path(target_project_path);
-
-    if let Some(parent) = target_path.parent() {
-        std::fs::create_dir_all(parent)
-            .map_err(|e| format!("Failed to create import directory: {e}"))?;
-    }
-
-    std::fs::copy(source_path, &target_path)
-        .map(|_| ())
-        .map_err(|e| format!("Failed to copy {}: {e}", source_path.display()))
-}
-
-fn copy_video_meta(
-    source_project_path: &Path,
-    target_project_path: &Path,
-    source: &VideoMeta,
-    target_relative_dir: &str,
-    name: &str,
-    required: bool,
-) -> Result, String> {
-    let Some(source_path) = source_asset_path(
-        source_project_path,
-        &source.path,
-        "video",
-        VIDEO_IMPORT_EXTENSIONS,
-    )?
-    else {
-        if required {
-            return Err(format!(
-                "Missing video file: {}",
-                source.path.to_path(source_project_path).display()
-            ));
-        }
-        return Ok(None);
-    };
-
-    let can_decode = probe_video_can_decode(&source_path)
-        .map_err(|e| format!("Cannot decode video {}: {e}", source_path.display()))?;
-    if !can_decode {
-        if required {
-            return Err(format!("Unsupported video file: {}", source_path.display()));
-        }
-        return Ok(None);
-    }
-
-    let extension = relative_file_extension(&source.path, "mp4");
-    let target_relative_path =
-        RelativePathBuf::from(format!("{target_relative_dir}/{name}.{extension}"));
-    copy_file_to_relative_path(&source_path, target_project_path, &target_relative_path)?;
-
-    let mut copied = source.clone();
-    copied.path = target_relative_path;
-    Ok(Some(copied))
-}
-
-fn copy_audio_meta(
-    source_project_path: &Path,
-    target_project_path: &Path,
-    source: &AudioMeta,
-    target_relative_dir: &str,
-    name: &str,
-) -> Result, String> {
-    let Some(source_path) = source_asset_path(
-        source_project_path,
-        &source.path,
-        "audio",
-        AUDIO_IMPORT_EXTENSIONS,
-    )?
-    else {
-        return Ok(None);
-    };
-
-    let extension = relative_file_extension(&source.path, "ogg");
-    let target_relative_path =
-        RelativePathBuf::from(format!("{target_relative_dir}/{name}.{extension}"));
-    copy_file_to_relative_path(&source_path, target_project_path, &target_relative_path)?;
-
-    let mut copied = source.clone();
-    copied.path = target_relative_path;
-    Ok(Some(copied))
-}
-
-fn copy_keyboard_path(
-    source_meta: &RecordingMeta,
-    source_segment: &MultipleSegment,
-    target_project_path: &Path,
-    target_relative_dir: &str,
-) -> Result, String> {
-    if let Some(source_relative_path) = &source_segment.keyboard {
-        let file_name =
-            relative_file_name(source_relative_path, cap_project::KEYBOARD_EVENTS_FILE_NAME);
-        let Some(source_path) = source_asset_path(
-            &source_meta.project_path,
-            source_relative_path,
-            "keyboard events",
-            KEYBOARD_IMPORT_EXTENSIONS,
-        )?
-        else {
-            return Ok(None);
-        };
-
-        let target_relative_path = RelativePathBuf::from(format!(
-            "{target_relative_dir}/{}",
-            sanitize_filename(&file_name)
-        ));
-        copy_file_to_relative_path(&source_path, target_project_path, &target_relative_path)?;
-
-        return Ok(Some(target_relative_path));
-    };
-
-    let Some(display_dir) = source_segment.display.path.parent() else {
-        return Ok(None);
-    };
-
-    for file_name in [
-        cap_project::KEYBOARD_EVENTS_FILE_NAME,
-        cap_project::LEGACY_KEYBOARD_EVENTS_FILE_NAME,
-    ] {
-        let source_relative_path = display_dir.join(file_name);
-        let Some(source_path) = source_asset_path(
-            &source_meta.project_path,
-            &source_relative_path,
-            "keyboard events",
-            KEYBOARD_IMPORT_EXTENSIONS,
-        )?
-        else {
-            continue;
-        };
-
-        let target_relative_path = RelativePathBuf::from(format!(
-            "{target_relative_dir}/{}",
-            sanitize_filename(file_name)
-        ));
-        copy_file_to_relative_path(&source_path, target_project_path, &target_relative_path)?;
-
-        return Ok(Some(target_relative_path));
-    }
-
-    Ok(None)
-}
-
-fn normalize_cursors_to_correct(cursors: &mut Cursors) -> &mut HashMap {
-    if let Cursors::Old(old) = cursors {
-        let converted = old
-            .iter()
-            .map(|(id, path)| {
-                (
-                    id.clone(),
-                    CursorMeta {
-                        image_path: RelativePathBuf::from(path.as_str()),
-                        hotspot: XY::new(0.0, 0.0),
-                        shape: None,
-                    },
-                )
-            })
-            .collect();
-        *cursors = Cursors::Correct(converted);
-    }
-
-    match cursors {
-        Cursors::Correct(map) => map,
-        Cursors::Old(_) => unreachable!(),
-    }
-}
-
-fn unique_cursor_id(
-    cursors: &HashMap,
-    import_token: &str,
-    source_id: &str,
-) -> String {
-    let source_id = if source_id.is_empty() {
-        "cursor"
-    } else {
-        source_id
-    };
-    let base = format!("{import_token}-{source_id}");
-    if !cursors.contains_key(&base) {
-        return base;
-    }
-
-    let mut counter = 1;
-    loop {
-        let candidate = format!("{base}-{counter}");
-        if !cursors.contains_key(&candidate) {
-            return candidate;
-        }
-        counter += 1;
-    }
-}
-
-fn copy_source_cursor_images(
-    source_meta: &RecordingMeta,
-    source_cursors: &Cursors,
-    target_project_path: &Path,
-    target_cursors: &mut Cursors,
-    import_token: &str,
-) -> Result, String> {
-    let target_cursor_dir = target_project_path.join("content").join("cursors");
-    std::fs::create_dir_all(&target_cursor_dir)
-        .map_err(|e| format!("Failed to create cursor directory: {e}"))?;
-
-    let target_cursors = normalize_cursors_to_correct(target_cursors);
-    let mut id_map = HashMap::new();
-
-    match source_cursors {
-        Cursors::Correct(source_map) => {
-            for (source_id, cursor) in source_map {
-                let Some(source_path) = source_asset_path(
-                    &source_meta.project_path,
-                    &cursor.image_path,
-                    "cursor image",
-                    IMAGE_IMPORT_EXTENSIONS,
-                )?
-                else {
-                    continue;
-                };
-
-                let new_id = unique_cursor_id(target_cursors, import_token, source_id);
-                let source_file_name = relative_file_name(&cursor.image_path, "cursor.png");
-                let target_file_name =
-                    unique_file_name(&target_cursor_dir, &format!("{new_id}-{source_file_name}"));
-                let target_relative_path =
-                    RelativePathBuf::from(format!("content/cursors/{target_file_name}"));
-
-                copy_file_to_relative_path(
-                    &source_path,
-                    target_project_path,
-                    &target_relative_path,
-                )?;
-
-                target_cursors.insert(
-                    new_id.clone(),
-                    CursorMeta {
-                        image_path: target_relative_path,
-                        hotspot: cursor.hotspot,
-                        shape: cursor.shape,
-                    },
-                );
-                id_map.insert(source_id.clone(), new_id);
-            }
-        }
-        Cursors::Old(source_map) => {
-            for (source_id, source_path) in source_map {
-                let source_relative_path = legacy_cursor_relative_path(source_path)?;
-                let Some(source_path) = source_asset_path(
-                    &source_meta.project_path,
-                    &source_relative_path,
-                    "cursor image",
-                    IMAGE_IMPORT_EXTENSIONS,
-                )?
-                else {
-                    continue;
-                };
-
-                let new_id = unique_cursor_id(target_cursors, import_token, source_id);
-                let source_file_name = relative_file_name(&source_relative_path, "cursor.png");
-                let target_file_name =
-                    unique_file_name(&target_cursor_dir, &format!("{new_id}-{source_file_name}"));
-                let target_relative_path =
-                    RelativePathBuf::from(format!("content/cursors/{target_file_name}"));
-
-                copy_file_to_relative_path(
-                    &source_path,
-                    target_project_path,
-                    &target_relative_path,
-                )?;
-
-                target_cursors.insert(
-                    new_id.clone(),
-                    CursorMeta {
-                        image_path: target_relative_path,
-                        hotspot: XY::new(0.0, 0.0),
-                        shape: None,
-                    },
-                );
-                id_map.insert(source_id.clone(), new_id);
-            }
-        }
-    }
-
-    Ok(id_map)
-}
-
-fn copy_cursor_events_path(
-    source_meta: &RecordingMeta,
-    source_relative_path: &RelativePathBuf,
-    target_project_path: &Path,
-    target_relative_dir: &str,
-    cursor_id_map: &HashMap,
-) -> Result, String> {
-    let Some(source_path) = source_asset_path(
-        &source_meta.project_path,
-        source_relative_path,
-        "cursor events",
-        CURSOR_EVENTS_IMPORT_EXTENSIONS,
-    )?
-    else {
-        return Ok(None);
-    };
-
-    let target_relative_path = RelativePathBuf::from(format!("{target_relative_dir}/cursor.json"));
-    let target_path = target_relative_path.to_path(target_project_path);
-    if let Some(parent) = target_path.parent() {
-        std::fs::create_dir_all(parent)
-            .map_err(|e| format!("Failed to create cursor event directory: {e}"))?;
-    }
-
-    if cursor_id_map.is_empty() {
-        std::fs::copy(&source_path, &target_path)
-            .map(|_| ())
-            .map_err(|e| format!("Failed to copy cursor events: {e}"))?;
-        return Ok(Some(target_relative_path));
-    }
-
-    match CursorEvents::load_from_file(&source_path) {
-        Ok(mut events) => {
-            for event in &mut events.moves {
-                if let Some(new_id) = cursor_id_map.get(&event.cursor_id) {
-                    event.cursor_id = new_id.clone();
-                }
-            }
-            for event in &mut events.clicks {
-                if let Some(new_id) = cursor_id_map.get(&event.cursor_id) {
-                    event.cursor_id = new_id.clone();
-                }
-            }
-
-            let file = std::fs::File::create(&target_path)
-                .map_err(|e| format!("Failed to create cursor event file: {e}"))?;
-            serde_json::to_writer_pretty(file, &events)
-                .map_err(|e| format!("Failed to write cursor event file: {e}"))?;
-        }
-        Err(_) => {
-            std::fs::copy(&source_path, &target_path)
-                .map(|_| ())
-                .map_err(|e| format!("Failed to copy cursor events: {e}"))?;
-        }
-    }
-
-    Ok(Some(target_relative_path))
-}
-
-fn single_segment_to_multiple(segment: &SingleSegment) -> MultipleSegment {
-    MultipleSegment {
-        display: segment.display.clone(),
-        camera: segment.camera.clone(),
-        mic: segment.audio.clone(),
-        system_audio: None,
-        cursor: segment.cursor.clone(),
-        keyboard: None,
-        display_notch: None,
-    }
-}
-
-fn studio_segments_for_import(studio_meta: &StudioRecordingMeta) -> Vec {
-    match studio_meta {
-        StudioRecordingMeta::SingleSegment { segment } => {
-            vec![single_segment_to_multiple(segment)]
-        }
-        StudioRecordingMeta::MultipleSegments { inner } => inner.segments.clone(),
-    }
-}
-
-fn source_timeline_segments_for_import(
-    source_meta: &RecordingMeta,
-    source_segments: &[MultipleSegment],
-) -> Result, String> {
-    let source_config = ProjectConfiguration::load(&source_meta.project_path).unwrap_or_default();
-    let Some(timeline) = source_config.timeline else {
-        return full_timeline_for_source_segments(source_meta, source_segments);
-    };
-
-    if timeline.segments.is_empty() {
-        return full_timeline_for_source_segments(source_meta, source_segments);
-    }
-
-    let mut duration_cache = HashMap::new();
-    let mut imported_segments = Vec::new();
-
-    for segment in timeline.segments {
-        let source_index = segment.recording_clip;
-        let Some(source_segment) = source_segments.get(source_index as usize) else {
-            continue;
-        };
-
-        let max_duration = if let Some(duration) = duration_cache.get(&source_index) {
-            *duration
-        } else {
-            let duration = get_source_video_duration_secs(source_meta, &source_segment.display)?;
-            duration_cache.insert(source_index, duration);
-            duration
-        };
-
-        if max_duration <= 0.0 {
-            continue;
-        }
-
-        let raw_start = if segment.start.is_finite() {
-            segment.start
-        } else {
-            0.0
-        };
-        let raw_end = if segment.end.is_finite() {
-            segment.end
-        } else {
-            max_duration
-        };
-        let start = raw_start.clamp(0.0, max_duration);
-        let end = raw_end.clamp(start, max_duration);
-        if end <= start {
-            continue;
-        }
-
-        imported_segments.push(TimelineSegment {
-            recording_clip: source_index,
-            timescale: if segment.timescale.is_finite() && segment.timescale > 0.0 {
-                segment.timescale
-            } else {
-                1.0
-            },
-            start,
-            end,
-            name: None,
-            speed_audio_mode: segment.speed_audio_mode,
-            hide_cursor: segment.hide_cursor,
-            volume: segment.volume,
-        });
-    }
-
-    if imported_segments.is_empty() {
-        full_timeline_for_source_segments(source_meta, source_segments)
-    } else {
-        Ok(imported_segments)
-    }
-}
-
-fn copy_source_segment(
-    source_meta: &RecordingMeta,
-    source_segment: &MultipleSegment,
-    target_project_path: &Path,
-    target_relative_dir: &str,
-    cursor_id_map: &HashMap,
-) -> Result {
-    let display = copy_video_meta(
-        &source_meta.project_path,
-        target_project_path,
-        &source_segment.display,
-        target_relative_dir,
-        "display",
-        true,
-    )?
-    .ok_or_else(|| "Missing display video".to_string())?;
-
-    let camera = source_segment
-        .camera
-        .as_ref()
-        .map(|camera| {
-            copy_video_meta(
-                &source_meta.project_path,
-                target_project_path,
-                camera,
-                target_relative_dir,
-                "camera",
-                false,
-            )
-        })
-        .transpose()?
-        .flatten();
-
-    let mic = source_segment
-        .mic
-        .as_ref()
-        .map(|mic| {
-            copy_audio_meta(
-                &source_meta.project_path,
-                target_project_path,
-                mic,
-                target_relative_dir,
-                "mic",
-            )
-        })
-        .transpose()?
-        .flatten();
-
-    let system_audio = source_segment
-        .system_audio
-        .as_ref()
-        .map(|system_audio| {
-            copy_audio_meta(
-                &source_meta.project_path,
-                target_project_path,
-                system_audio,
-                target_relative_dir,
-                "system-audio",
-            )
-        })
-        .transpose()?
-        .flatten();
-
-    let cursor = source_segment
-        .cursor
-        .as_ref()
-        .map(|cursor| {
-            copy_cursor_events_path(
-                source_meta,
-                cursor,
-                target_project_path,
-                target_relative_dir,
-                cursor_id_map,
-            )
-        })
-        .transpose()?
-        .flatten();
-
-    let keyboard = copy_keyboard_path(
-        source_meta,
-        source_segment,
-        target_project_path,
-        target_relative_dir,
-    )?;
-
-    Ok(MultipleSegment {
-        display,
-        camera,
-        mic,
-        system_audio,
-        cursor,
-        keyboard,
-        display_notch: source_segment.display_notch,
-    })
-}
-
-fn get_video_stream_info(
-    input: &avformat::context::Input,
-) -> Result<(usize, VideoInfo), ImportError> {
-    let stream = input
-        .streams()
-        .best(ffmpeg::media::Type::Video)
-        .ok_or(ImportError::NoVideoStream)?;
-
-    let stream_index = stream.index();
-    let decoder_ctx = avcodec::Context::from_parameters(stream.parameters())
-        .map_err(|e| ImportError::DecoderFailed(e.to_string()))?;
-    let decoder = decoder_ctx
-        .decoder()
-        .video()
-        .map_err(|e| ImportError::DecoderFailed(e.to_string()))?;
-
-    let rate = stream.avg_frame_rate();
-    let time_base = stream.time_base();
-
-    let pixel_format = match decoder.format() {
-        ffmpeg::format::Pixel::YUV420P => Pixel::YUV420P,
-        ffmpeg::format::Pixel::NV12 => Pixel::NV12,
-        ffmpeg::format::Pixel::BGRA => Pixel::BGRA,
-        ffmpeg::format::Pixel::RGBA => Pixel::RGBA,
-        ffmpeg::format::Pixel::RGB24 => Pixel::RGB24,
-        ffmpeg::format::Pixel::BGR24 => Pixel::BGR24,
-        _ => Pixel::YUV420P,
-    };
-
-    Ok((
-        stream_index,
-        VideoInfo {
-            pixel_format,
-            width: decoder.width(),
-            height: decoder.height(),
-            time_base: FFRational(time_base.numerator(), time_base.denominator()),
-            frame_rate: FFRational(rate.numerator(), rate.denominator()),
-        },
-    ))
-}
-
-fn get_audio_stream_info(input: &avformat::context::Input) -> Option<(usize, AudioInfo)> {
-    let stream = input.streams().best(ffmpeg::media::Type::Audio)?;
-    let stream_index = stream.index();
-
-    let decoder_ctx = avcodec::Context::from_parameters(stream.parameters()).ok()?;
-    let decoder = decoder_ctx.decoder().audio().ok()?;
-
-    let audio_info = AudioInfo::from_decoder(&decoder).ok()?;
-
-    Some((stream_index, audio_info))
-}
-
-fn reference_video_frame(frame: &ffmpeg::frame::Video) -> ffmpeg::frame::Video {
-    let mut referenced = ffmpeg::frame::Video::empty();
-    let status = unsafe { ffmpeg::ffi::av_frame_ref(referenced.as_mut_ptr(), frame.as_ptr()) };
-
-    if status < 0 {
-        frame.clone()
-    } else {
-        referenced
-    }
-}
-
-fn transcode_video(
-    app: &AppHandle,
-    source_path: &Path,
-    output_path: &Path,
-    audio_output_path: Option<&Path>,
-    project_path_str: &str,
-    project_path: &Path,
-) -> Result<(u32, Option), ImportError> {
-    use std::time::Duration as StdDuration;
-
-    let mut input =
-        avformat::input(source_path).map_err(|e| ImportError::OpenFailed(e.to_string()))?;
-
-    let (video_stream_index, video_info) = get_video_stream_info(&input)?;
-    let audio_stream_info = get_audio_stream_info(&input);
-
-    let output_width = ensure_even(video_info.width);
-    let output_height = ensure_even(video_info.height);
-    let fps = if video_info.frame_rate.1 > 0 {
-        ((video_info.frame_rate.0 as f64 / video_info.frame_rate.1 as f64).round() as u32)
-            .clamp(1, 120)
-    } else {
-        30
-    };
-
-    let duration = get_media_duration(source_path);
-    let total_frames = duration
-        .map(|d| (d.as_secs_f64() * fps as f64) as u64)
-        .unwrap_or(1000);
-
-    let video_decoder_ctx =
-        avcodec::Context::from_parameters(input.stream(video_stream_index).unwrap().parameters())
-            .map_err(|e| ImportError::DecoderFailed(e.to_string()))?;
-    let mut video_decoder = video_decoder_ctx
-        .decoder()
-        .video()
-        .map_err(|e| ImportError::DecoderFailed(e.to_string()))?;
-
-    let video_time_base = input.stream(video_stream_index).unwrap().time_base();
-
-    let mut audio_decoder = audio_stream_info.as_ref().and_then(|(idx, _)| {
-        let stream = input.stream(*idx)?;
-        let decoder_ctx = avcodec::Context::from_parameters(stream.parameters()).ok()?;
-        let mut decoder = decoder_ctx.decoder().audio().ok()?;
-        if decoder.channel_layout().is_empty() {
-            decoder.set_channel_layout(ChannelLayout::default(decoder.channels() as i32));
-        }
-        decoder.set_packet_time_base(stream.time_base());
-        Some((*idx, decoder, stream.time_base()))
-    });
-
-    if let Some(parent) = output_path.parent() {
-        std::fs::create_dir_all(parent).map_err(ImportError::DirectoryFailed)?;
-    }
-
-    let mut output =
-        avformat::output(output_path).map_err(|e| ImportError::EncoderFailed(e.to_string()))?;
-
-    let encoder_video_info = VideoInfo {
-        pixel_format: Pixel::YUV420P,
-        width: output_width,
-        height: output_height,
-        time_base: video_info.time_base,
-        frame_rate: FFRational(fps as i32, 1),
-    };
-
-    let mut video_encoder = H264EncoderBuilder::new(encoder_video_info)
-        .with_preset(H264Preset::Medium)
-        .with_output_size(output_width, output_height)
-        .map_err(|e| ImportError::EncoderFailed(e.to_string()))?
-        .build(&mut output)
-        .map_err(|e| ImportError::EncoderFailed(e.to_string()))?;
-
-    let mut audio_output: Option = None;
-    let mut audio_encoder: Option> = None;
-    let sample_rate = if let Some((_, audio_info)) = &audio_stream_info {
-        if let Some(audio_path) = audio_output_path {
-            let mut audio_out = avformat::output(audio_path).map_err(|e| {
-                ImportError::EncoderFailed(format!("Failed to create audio output: {e}"))
-            })?;
-
-            audio_encoder = Some(Box::new(
-                OpusEncoder::init(*audio_info, &mut audio_out)
-                    .map_err(|e| ImportError::EncoderFailed(e.to_string()))?,
-            ));
-            audio_out.write_header().map_err(|e| {
-                ImportError::EncoderFailed(format!("Failed to write audio header: {e}"))
-            })?;
-            audio_output = Some(audio_out);
-        }
-        Some(audio_info.sample_rate)
-    } else {
-        None
-    };
-
-    output
-        .write_header()
-        .map_err(|e| ImportError::EncoderFailed(format!("Failed to write header: {e}")))?;
-
-    let mut video_frame = ffmpeg::frame::Video::empty();
-    let mut audio_frame = ffmpeg::frame::Audio::empty();
-    let mut frames_processed = 0u64;
-    let mut last_progress = 0.0;
-
-    let mut scaler: Option = None;
-
-    for (stream, packet) in input.packets() {
-        let stream_index = stream.index();
-
-        if stream_index == video_stream_index {
-            video_decoder.send_packet(&packet)?;
-
-            while video_decoder.receive_frame(&mut video_frame).is_ok() {
-                let timestamp = video_frame.pts().unwrap_or(0);
-                let time_secs = timestamp as f64 * video_time_base.numerator() as f64
-                    / video_time_base.denominator().max(1) as f64;
-                let duration = StdDuration::from_secs_f64(time_secs.max(0.0));
-
-                let frame_to_encode = if video_frame.format() != ffmpeg::format::Pixel::YUV420P
-                    || video_frame.width() != output_width
-                    || video_frame.height() != output_height
-                {
-                    if scaler.is_none() {
-                        scaler = Some(
-                            ffmpeg::software::scaling::Context::get(
-                                video_frame.format(),
-                                video_frame.width(),
-                                video_frame.height(),
-                                ffmpeg::format::Pixel::YUV420P,
-                                output_width,
-                                output_height,
-                                ffmpeg::software::scaling::Flags::BILINEAR,
-                            )
-                            .map_err(|e| {
-                                ImportError::TranscodeFailed(format!(
-                                    "Failed to create scaler: {e}"
-                                ))
-                            })?,
-                        );
-                    }
-                    let scaler = scaler.as_mut().unwrap();
-
-                    let mut scaled_frame = ffmpeg::frame::Video::empty();
-                    scaled_frame.set_format(ffmpeg::format::Pixel::YUV420P);
-                    scaled_frame.set_width(output_width);
-                    scaled_frame.set_height(output_height);
-                    let ret =
-                        unsafe { ffmpeg::ffi::av_frame_get_buffer(scaled_frame.as_mut_ptr(), 0) };
-                    if ret < 0 {
-                        return Err(ImportError::TranscodeFailed(
-                            "Failed to allocate frame buffer".to_string(),
-                        ));
-                    }
-
-                    scaler.run(&video_frame, &mut scaled_frame)?;
-                    scaled_frame.set_pts(video_frame.pts());
-                    scaled_frame
-                } else {
-                    reference_video_frame(&video_frame)
-                };
-
-                video_encoder
-                    .queue_frame(frame_to_encode, duration, &mut output)
-                    .map_err(|e| ImportError::TranscodeFailed(e.to_string()))?;
-
-                frames_processed += 1;
-
-                let progress = (frames_processed as f64 / total_frames as f64).min(0.99);
-                if progress - last_progress >= 0.01 {
-                    last_progress = progress;
-
-                    if !check_project_exists(project_path) {
-                        info!("Import cancelled: project directory was deleted");
-                        return Err(ImportError::TranscodeFailed("Import cancelled".to_string()));
-                    }
-
-                    emit_progress(
-                        app,
-                        project_path_str,
-                        ImportStage::Converting,
-                        progress,
-                        &format!("Converting video... {}%", (progress * 100.0) as u32),
-                    );
-                }
-            }
-        } else if let Some((audio_idx, decoder, _)) = audio_decoder.as_mut()
-            && stream_index == *audio_idx
-            && let (Some(encoder), Some(audio_out)) =
-                (audio_encoder.as_mut(), audio_output.as_mut())
-        {
-            decoder.send_packet(&packet)?;
-
-            while decoder.receive_frame(&mut audio_frame).is_ok() {
-                encoder.send_frame(audio_frame.clone(), audio_out);
-            }
-        }
-    }
-
-    video_decoder.send_eof()?;
-    while video_decoder.receive_frame(&mut video_frame).is_ok() {
-        let timestamp = video_frame.pts().unwrap_or(0);
-        let time_secs = timestamp as f64 * video_time_base.numerator() as f64
-            / video_time_base.denominator().max(1) as f64;
-        let duration = StdDuration::from_secs_f64(time_secs.max(0.0));
-
-        let frame_to_encode = if video_frame.format() != ffmpeg::format::Pixel::YUV420P
-            || video_frame.width() != output_width
-            || video_frame.height() != output_height
-        {
-            if let Some(scaler) = &mut scaler {
-                let mut scaled_frame = ffmpeg::frame::Video::empty();
-                scaled_frame.set_format(ffmpeg::format::Pixel::YUV420P);
-                scaled_frame.set_width(output_width);
-                scaled_frame.set_height(output_height);
-                let ret = unsafe { ffmpeg::ffi::av_frame_get_buffer(scaled_frame.as_mut_ptr(), 0) };
-                if ret < 0 {
-                    return Err(ImportError::TranscodeFailed(
-                        "Failed to allocate frame buffer".to_string(),
-                    ));
-                }
-                scaler.run(&video_frame, &mut scaled_frame)?;
-                scaled_frame.set_pts(video_frame.pts());
-                scaled_frame
-            } else {
-                reference_video_frame(&video_frame)
-            }
-        } else {
-            reference_video_frame(&video_frame)
-        };
-
-        video_encoder
-            .queue_frame(frame_to_encode, duration, &mut output)
-            .map_err(|e| ImportError::TranscodeFailed(e.to_string()))?;
-    }
-
-    if let Some((_, decoder, _)) = audio_decoder.as_mut() {
-        decoder.send_eof()?;
-        while decoder.receive_frame(&mut audio_frame).is_ok() {
-            if let (Some(encoder), Some(audio_out)) =
-                (audio_encoder.as_mut(), audio_output.as_mut())
-            {
-                encoder.send_frame(audio_frame.clone(), audio_out);
-            }
-        }
-    }
-
-    video_encoder
-        .flush(&mut output)
-        .map_err(|e| ImportError::TranscodeFailed(format!("Failed to flush video: {e}")))?;
-
-    if let (Some(encoder), Some(audio_out)) = (&mut audio_encoder, &mut audio_output) {
-        encoder
-            .flush(audio_out)
-            .map_err(|e| ImportError::TranscodeFailed(format!("Failed to flush audio: {e}")))?;
-        audio_out.write_trailer().map_err(|e| {
-            ImportError::TranscodeFailed(format!("Failed to write audio trailer: {e}"))
-        })?;
-    }
-
-    output
-        .write_trailer()
-        .map_err(|e| ImportError::TranscodeFailed(format!("Failed to write trailer: {e}")))?;
-
-    drop(output);
-
-    if let Ok(file) = std::fs::File::open(output_path) {
-        let _ = file.sync_all();
-    }
-    if let Some(audio_path) = audio_output_path
-        && let Ok(file) = std::fs::File::open(audio_path)
-    {
-        let _ = file.sync_all();
-    }
-
-    Ok((fps, sample_rate))
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn start_video_import(app: AppHandle, source_path: PathBuf) -> Result {
-    info!("Starting video import from: {:?}", source_path);
-
-    let recordings_dir = crate::general_settings::GeneralSettingsStore::recordings_dir(&app);
-
-    let project_name = generate_project_name(&source_path);
-    let sanitized_name = sanitize_filename(&project_name);
-    let project_dir_name = format!("{sanitized_name}.cap");
-
-    let mut project_path = recordings_dir.join(&project_dir_name);
-    let mut counter = 1;
-    while project_path.exists() {
-        let new_name = format!("{sanitized_name} ({counter}).cap");
-        project_path = recordings_dir.join(new_name);
-        counter += 1;
-    }
-
-    let project_path_str = project_path.to_string_lossy().to_string();
-
-    emit_progress(
-        &app,
-        &project_path_str,
-        ImportStage::Probing,
-        0.0,
-        "Analyzing video file...",
-    );
-
-    let can_decode =
-        probe_video_can_decode(&source_path).map_err(|e| format!("Cannot decode video: {e}"))?;
-
-    if !can_decode {
-        emit_progress(
-            &app,
-            &project_path_str,
-            ImportStage::Failed,
-            0.0,
-            "Video format not supported",
-        );
-        return Err("Video format not supported or file is corrupted".to_string());
-    }
-
-    std::fs::create_dir_all(&project_path).map_err(|e| e.to_string())?;
-
-    let segment_dir = project_path
-        .join("content")
-        .join("segments")
-        .join("segment-0");
-    std::fs::create_dir_all(&segment_dir).map_err(|e| e.to_string())?;
-
-    let output_video_path = segment_dir.join("display.mp4");
-    let output_audio_path = segment_dir.join("audio.ogg");
-
-    let initial_meta = RecordingMeta {
-        platform: Some(Platform::default()),
-        project_path: project_path.clone(),
-        pretty_name: project_name.clone(),
-        sharing: None,
-        inner: RecordingMetaInner::Studio(Box::new(StudioRecordingMeta::MultipleSegments {
-            inner: MultipleSegments {
-                segments: vec![MultipleSegment {
-                    display: VideoMeta {
-                        path: RelativePathBuf::from("content/segments/segment-0/display.mp4"),
-                        fps: 30,
-                        start_time: Some(0.0),
-                        device_id: None,
-                    },
-                    camera: None,
-                    mic: None,
-                    system_audio: None,
-                    cursor: None,
-                    keyboard: None,
-                    display_notch: None,
-                }],
-                cursors: Cursors::default(),
-                status: Some(StudioRecordingStatus::InProgress),
-            },
-        })),
-        upload: None,
-    };
-
-    initial_meta
-        .save_for_project()
-        .map_err(|e| format!("Failed to save initial metadata: {e:?}"))?;
-
-    emit_progress(
-        &app,
-        &project_path_str,
-        ImportStage::Converting,
-        0.0,
-        "Starting conversion...",
-    );
-
-    let return_path = project_path.clone();
-
-    tokio::spawn(async move {
-        let app_clone = app.clone();
-        let project_path_str_clone = project_path_str.clone();
-        let source_path_clone = source_path.clone();
-        let output_path_clone = output_video_path.clone();
-        let audio_path_clone = output_audio_path.clone();
-        let project_path_clone = project_path.clone();
-
-        if !check_project_exists(&project_path) {
-            info!("Import aborted before start: project directory missing");
-            return;
-        }
-
-        let result = tokio::task::spawn_blocking(move || {
-            transcode_video(
-                &app_clone,
-                &source_path_clone,
-                &output_path_clone,
-                Some(&audio_path_clone),
-                &project_path_str_clone,
-                &project_path_clone,
-            )
-        })
-        .await;
-
-        match result {
-            Ok(Ok((fps, sample_rate))) => {
-                emit_progress(
-                    &app,
-                    &project_path_str,
-                    ImportStage::Finalizing,
-                    0.95,
-                    "Creating project metadata...",
-                );
-
-                let audio_file_size = std::fs::metadata(&output_audio_path)
-                    .map(|m| m.len())
-                    .unwrap_or(0);
-                const MIN_VALID_AUDIO_SIZE: u64 = 1000;
-                let system_audio =
-                    if sample_rate.is_some() && audio_file_size > MIN_VALID_AUDIO_SIZE {
-                        Some(AudioMeta {
-                            path: RelativePathBuf::from("content/segments/segment-0/audio.ogg"),
-                            start_time: Some(0.0),
-                            device_id: None,
-                            gap_summary: None,
-                            digital_silence_ms: None,
-                        })
-                    } else {
-                        None
-                    };
-
-                let meta = RecordingMeta {
-                    platform: Some(Platform::default()),
-                    project_path: project_path.clone(),
-                    pretty_name: project_name,
-                    sharing: None,
-                    inner: RecordingMetaInner::Studio(Box::new(
-                        StudioRecordingMeta::MultipleSegments {
-                            inner: MultipleSegments {
-                                segments: vec![MultipleSegment {
-                                    display: VideoMeta {
-                                        path: RelativePathBuf::from(
-                                            "content/segments/segment-0/display.mp4",
-                                        ),
-                                        fps,
-                                        start_time: Some(0.0),
-                                        device_id: None,
-                                    },
-                                    camera: None,
-                                    mic: None,
-                                    system_audio,
-                                    cursor: None,
-                                    keyboard: None,
-                                    display_notch: None,
-                                }],
-                                cursors: Cursors::default(),
-                                status: Some(StudioRecordingStatus::Complete),
-                            },
-                        },
-                    )),
-                    upload: None,
-                };
-
-                if let Err(e) = meta.save_for_project() {
-                    error!("Failed to save metadata: {:?}", e);
-                    emit_progress(
-                        &app,
-                        &project_path_str,
-                        ImportStage::Failed,
-                        0.0,
-                        &format!("Failed to save metadata: {e:?}"),
-                    );
-                    return;
-                }
-
-                let screenshots_dir = project_path.join("screenshots");
-                if let Err(e) = std::fs::create_dir_all(&screenshots_dir) {
-                    error!("Failed to create screenshots directory: {:?}", e);
-                } else {
-                    let display_screenshot = screenshots_dir.join("display.jpg");
-                    let video_path = output_video_path.clone();
-                    tokio::spawn(async move {
-                        if let Err(e) =
-                            create_screenshot(video_path, display_screenshot, None).await
-                        {
-                            error!("Failed to create thumbnail for imported video: {}", e);
-                        }
-                    });
-                }
-
-                emit_progress(
-                    &app,
-                    &project_path_str,
-                    ImportStage::Complete,
-                    1.0,
-                    "Import complete!",
-                );
-
-                info!("Video import complete: {:?}", project_path);
-            }
-            Ok(Err(e)) => {
-                error!("Transcoding failed: {}", e);
-                emit_progress(
-                    &app,
-                    &project_path_str,
-                    ImportStage::Failed,
-                    0.0,
-                    &e.to_string(),
-                );
-            }
-            Err(e) => {
-                error!("Transcoding task panicked: {}", e);
-                emit_progress(
-                    &app,
-                    &project_path_str,
-                    ImportStage::Failed,
-                    0.0,
-                    &format!("Transcoding task failed: {e}"),
-                );
-            }
-        }
-    });
-
-    Ok(return_path)
-}
-
-async fn append_mp4_to_editor_project(
-    app: AppHandle,
-    target_project_path: PathBuf,
-    source_path: PathBuf,
-) -> Result {
-    if !is_mp4_import_path(&source_path) {
-        return Err("Select an MP4 video file to import".to_string());
-    }
-
-    let mut target_meta = RecordingMeta::load_for_project(&target_project_path)
-        .map_err(|e| format!("Failed to load target project metadata: {e}"))?;
-    let mut config = ProjectConfiguration::load(&target_project_path).unwrap_or_default();
-    let existing_segments = {
-        let inner = ensure_multiple_segments(&mut target_meta)?;
-        inner.status = Some(StudioRecordingStatus::Complete);
-        inner.segments.clone()
-    };
-    ensure_project_timeline(&mut config, &target_project_path, &existing_segments)?;
-
-    let new_index = existing_segments.len() as u32;
-    let (_, target_relative_dir) = unique_segment_dir(&target_project_path, new_index)
-        .map_err(|e| format!("Failed to create imported segment directory: {e}"))?;
-
-    let output_video_relative_path =
-        RelativePathBuf::from(format!("{target_relative_dir}/display.mp4"));
-    let output_audio_relative_path =
-        RelativePathBuf::from(format!("{target_relative_dir}/audio.ogg"));
-    let output_video_path = output_video_relative_path.to_path(&target_project_path);
-    let output_audio_path = output_audio_relative_path.to_path(&target_project_path);
-    let project_path_str = target_project_path.to_string_lossy().to_string();
-
-    emit_progress(
-        &app,
-        &project_path_str,
-        ImportStage::Probing,
-        0.0,
-        "Analyzing video file...",
-    );
-
-    let can_decode =
-        probe_video_can_decode(&source_path).map_err(|e| format!("Cannot decode video: {e}"))?;
-    if !can_decode {
-        return Err("Video format not supported or file is corrupted".to_string());
-    }
-
-    emit_progress(
-        &app,
-        &project_path_str,
-        ImportStage::Converting,
-        0.0,
-        "Starting conversion...",
-    );
-
-    let app_for_transcode = app.clone();
-    let source_path_for_transcode = source_path.clone();
-    let output_video_path_for_transcode = output_video_path.clone();
-    let output_audio_path_for_transcode = output_audio_path.clone();
-    let project_path_str_for_transcode = project_path_str.clone();
-    let target_project_path_for_transcode = target_project_path.clone();
-
-    let (fps, sample_rate) = tokio::task::spawn_blocking(move || {
-        transcode_video(
-            &app_for_transcode,
-            &source_path_for_transcode,
-            &output_video_path_for_transcode,
-            Some(&output_audio_path_for_transcode),
-            &project_path_str_for_transcode,
-            &target_project_path_for_transcode,
-        )
-    })
-    .await
-    .map_err(|e| format!("Video import task failed: {e}"))?
-    .map_err(|e| e.to_string())?;
-
-    let duration = get_video_duration_secs(&output_video_path)?;
-    let audio_file_size = std::fs::metadata(&output_audio_path)
-        .map(|metadata| metadata.len())
-        .unwrap_or(0);
-    const MIN_VALID_AUDIO_SIZE: u64 = 1000;
-    let system_audio = if sample_rate.is_some() && audio_file_size > MIN_VALID_AUDIO_SIZE {
-        Some(AudioMeta {
-            path: output_audio_relative_path,
-            start_time: Some(0.0),
-            device_id: None,
-            gap_summary: None,
-            digital_silence_ms: None,
-        })
-    } else {
-        None
-    };
-
-    let imported_segment = MultipleSegment {
-        display: VideoMeta {
-            path: output_video_relative_path,
-            fps,
-            start_time: Some(0.0),
-            device_id: None,
-        },
-        camera: None,
-        mic: None,
-        system_audio,
-        cursor: None,
-        keyboard: None,
-        display_notch: None,
-    };
-
-    {
-        let inner = ensure_multiple_segments(&mut target_meta)?;
-        inner.status = Some(StudioRecordingStatus::Complete);
-        inner.segments.push(imported_segment.clone());
-    }
-
-    ensure_project_timeline(&mut config, &target_project_path, &existing_segments)?
-        .segments
-        .push(TimelineSegment {
-            recording_clip: new_index,
-            timescale: 1.0,
-            start: 0.0,
-            end: duration,
-            name: None,
-            speed_audio_mode: None,
-            hide_cursor: None,
-            volume: None,
-        });
-    add_clip_configs(
-        &mut config,
-        new_index,
-        std::slice::from_ref(&imported_segment),
-    );
-
-    target_meta
-        .save_for_project()
-        .map_err(|e| format!("Failed to save project metadata: {e:?}"))?;
-    config
-        .write(&target_project_path)
-        .map_err(|e| format!("Failed to save project config: {e}"))?;
-
-    emit_progress(
-        &app,
-        &project_path_str,
-        ImportStage::Complete,
-        1.0,
-        "Import complete!",
-    );
-
-    Ok(1)
-}
-
-async fn append_cap_project_to_editor_project(
-    app: AppHandle,
-    target_project_path: PathBuf,
-    source_project_path: PathBuf,
-) -> Result {
-    let source_meta = RecordingMeta::load_for_project(&source_project_path)
-        .map_err(|e| format!("Failed to load source project metadata: {e}"))?;
-
-    let RecordingMetaInner::Studio(source_studio_meta) = &source_meta.inner else {
-        return match &source_meta.inner {
-            RecordingMetaInner::Instant(InstantRecordingMeta::Complete { .. }) => {
-                append_mp4_to_editor_project(app, target_project_path, source_meta.output_path())
-                    .await
-            }
-            RecordingMetaInner::Instant(InstantRecordingMeta::InProgress { .. }) => {
-                Err("Source Cap project is still recording".to_string())
-            }
-            RecordingMetaInner::Instant(InstantRecordingMeta::Failed { error }) => {
-                Err(format!("Source Cap project failed: {error}"))
-            }
-            RecordingMetaInner::Studio(_) => unreachable!(),
-        };
-    };
-
-    let source_segments = studio_segments_for_import(source_studio_meta);
-    if source_segments.is_empty() {
-        return Err("Source Cap project has no recording segments".to_string());
-    }
-
-    let source_timeline = source_timeline_segments_for_import(&source_meta, &source_segments)?;
-    let source_cursors = match source_studio_meta.as_ref() {
-        StudioRecordingMeta::MultipleSegments { inner } => Some(&inner.cursors),
-        StudioRecordingMeta::SingleSegment { .. } => None,
-    };
-
-    let mut target_meta = RecordingMeta::load_for_project(&target_project_path)
-        .map_err(|e| format!("Failed to load target project metadata: {e}"))?;
-    let mut config = ProjectConfiguration::load(&target_project_path).unwrap_or_default();
-    let existing_segments = {
-        let inner = ensure_multiple_segments(&mut target_meta)?;
-        inner.status = Some(StudioRecordingStatus::Complete);
-        inner.segments.clone()
-    };
-    ensure_project_timeline(&mut config, &target_project_path, &existing_segments)?;
-
-    let (base_index, copied_segments, source_to_target_index) = {
-        let inner = ensure_multiple_segments(&mut target_meta)?;
-        inner.status = Some(StudioRecordingStatus::Complete);
-        let base_index = inner.segments.len() as u32;
-        let import_token = format!("import-{}", uuid::Uuid::new_v4().simple());
-        let cursor_id_map = if let Some(source_cursors) = source_cursors {
-            copy_source_cursor_images(
-                &source_meta,
-                source_cursors,
-                &target_project_path,
-                &mut inner.cursors,
-                &import_token,
-            )?
-        } else {
-            HashMap::new()
-        };
-
-        let mut copied_segments = Vec::new();
-        let mut source_to_target_index = HashMap::new();
-
-        for (source_index, source_segment) in source_segments.iter().enumerate() {
-            let target_index = base_index + copied_segments.len() as u32;
-            let (_, target_relative_dir) =
-                unique_segment_dir(&target_project_path, target_index)
-                    .map_err(|e| format!("Failed to create imported segment directory: {e}"))?;
-            let copied_segment = copy_source_segment(
-                &source_meta,
-                source_segment,
-                &target_project_path,
-                &target_relative_dir,
-                &cursor_id_map,
-            )?;
-
-            inner.segments.push(copied_segment.clone());
-            copied_segments.push(copied_segment);
-            source_to_target_index.insert(source_index as u32, target_index);
-        }
-
-        (base_index, copied_segments, source_to_target_index)
-    };
-
-    if copied_segments.is_empty() {
-        return Err("Source Cap project has no importable recording segments".to_string());
-    }
-
-    {
-        let timeline =
-            ensure_project_timeline(&mut config, &target_project_path, &existing_segments)?;
-        for source_segment in source_timeline {
-            let Some(target_index) = source_to_target_index.get(&source_segment.recording_clip)
-            else {
-                continue;
-            };
-
-            timeline.segments.push(TimelineSegment {
-                recording_clip: *target_index,
-                timescale: source_segment.timescale,
-                start: source_segment.start,
-                end: source_segment.end,
-                name: None,
-                speed_audio_mode: source_segment.speed_audio_mode,
-                hide_cursor: source_segment.hide_cursor,
-                volume: source_segment.volume,
-            });
-        }
-    }
-
-    add_clip_configs(&mut config, base_index, &copied_segments);
-
-    target_meta
-        .save_for_project()
-        .map_err(|e| format!("Failed to save project metadata: {e:?}"))?;
-    config
-        .write(&target_project_path)
-        .map_err(|e| format!("Failed to save project config: {e}"))?;
-
-    Ok(copied_segments.len())
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn add_existing_recording_to_editor(
-    window: Window,
-    source_path: PathBuf,
-) -> Result {
-    let target_project_path = editor_project_path_from_window(&window)?;
-
-    if same_project_path(&target_project_path, &source_path) {
-        return Err("Cannot import a recording into itself".to_string());
-    }
-
-    let app = window.app_handle().clone();
-    let imported_count = if is_mp4_import_path(&source_path) {
-        append_mp4_to_editor_project(app, target_project_path, source_path).await?
-    } else if is_cap_project_path(&source_path) {
-        crate::wait_for_recording_ready(&app, &source_path).await?;
-        append_cap_project_to_editor_project(app, target_project_path, source_path).await?
-    } else {
-        return Err("Select an MP4 file or a Cap project folder".to_string());
-    };
-    let imported_count =
-        u32::try_from(imported_count).map_err(|_| "Too many recordings imported".to_string())?;
-
-    EditorInstances::remove(window).await;
-
-    Ok(imported_count)
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn start_image_import(app: AppHandle, source_path: PathBuf) -> Result {
-    info!("Starting image import from: {:?}", source_path);
-
-    if !source_path.is_file() {
-        return Err("Image file does not exist".to_string());
-    }
-
-    let source_path_for_decode = source_path.clone();
-    let (image_width, image_height, image_data) =
-        tokio::task::spawn_blocking(move || -> Result<(u32, u32, Vec), String> {
-            let image = image::ImageReader::open(&source_path_for_decode)
-                .map_err(|e| format!("Failed to open image: {e}"))?
-                .with_guessed_format()
-                .map_err(|e| format!("Failed to detect image format: {e}"))?
-                .decode()
-                .map_err(|e| format!("Failed to decode image: {e}"))?;
-
-            let width = image.width();
-            let height = image.height();
-
-            if width > MAX_IMAGE_DIMENSION || height > MAX_IMAGE_DIMENSION {
-                return Err(format!("Image dimensions exceed maximum: {width}x{height}"));
-            }
-
-            if width
-                .checked_mul(height)
-                .and_then(|p| p.checked_mul(4))
-                .is_none()
-            {
-                return Err(format!("Image dimensions overflow: {width}x{height}"));
-            }
-
-            let rgba = image.to_rgba8();
-
-            Ok((width, height, rgba.into_raw()))
-        })
-        .await
-        .map_err(|e| format!("Failed to import image: {e}"))??;
-
-    let screenshots_dir = app
-        .path()
-        .app_data_dir()
-        .map_err(|e| e.to_string())?
-        .join("screenshots");
-    std::fs::create_dir_all(&screenshots_dir)
-        .map_err(|e| format!("Failed to create screenshots directory: {e}"))?;
-
-    let project_name = generate_image_project_name(&source_path);
-    let filename = project_name.replace(":", ".");
-    let filename = format!("{}.cap", sanitize_filename::sanitize(&filename));
-    let project_path = screenshots_dir.join(cap_utils::ensure_unique_filename(
-        &filename,
-        &screenshots_dir,
-    )?);
-    std::fs::create_dir_all(&project_path)
-        .map_err(|e| format!("Failed to create screenshot project directory: {e}"))?;
-
-    let image_filename = "original.png";
-    let image_path = project_path.join(image_filename);
-    let image_path_for_write = image_path.clone();
-
-    tokio::task::spawn_blocking(move || -> Result<(), String> {
-        let file = std::fs::File::create(&image_path_for_write)
-            .map_err(|e| format!("Failed to create imported image file: {e}"))?;
-        let encoder = image::codecs::png::PngEncoder::new_with_quality(
-            std::io::BufWriter::new(file),
-            image::codecs::png::CompressionType::Default,
-            image::codecs::png::FilterType::Adaptive,
-        );
-
-        ImageEncoder::write_image(
-            encoder,
-            &image_data,
-            image_width,
-            image_height,
-            image::ColorType::Rgba8.into(),
-        )
-        .map_err(|e| format!("Failed to encode imported image: {e}"))
-    })
-    .await
-    .map_err(|e| format!("Failed to write imported image: {e}"))??;
-
-    let video_meta = VideoMeta {
-        path: RelativePathBuf::from(image_filename),
-        fps: 0,
-        start_time: Some(0.0),
-        device_id: None,
-    };
-
-    let segment = SingleSegment {
-        display: video_meta,
-        camera: None,
-        audio: None,
-        cursor: None,
-    };
-
-    let meta = RecordingMeta {
-        platform: Some(Platform::default()),
-        project_path: project_path.clone(),
-        pretty_name: project_name,
-        sharing: None,
-        inner: RecordingMetaInner::Studio(Box::new(StudioRecordingMeta::SingleSegment { segment })),
-        upload: None,
-    };
-
-    meta.save_for_project()
-        .map_err(|e| format!("Failed to save screenshot metadata: {e:?}"))?;
-
-    ProjectConfiguration::default()
-        .write(&project_path)
-        .map_err(|e| format!("Failed to save screenshot project config: {e}"))?;
-
-    let _ = crate::NewScreenshotAdded {
-        path: image_path.clone(),
-    }
-    .emit(&app);
-
-    Ok(image_path)
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn check_import_ready(project_path: PathBuf) -> Result {
-    debug!("check_import_ready called for: {:?}", project_path);
-
-    let meta = match RecordingMeta::load_for_project(&project_path) {
-        Ok(m) => m,
-        Err(e) => {
-            debug!("check_import_ready: meta load failed: {:?}", e);
-            return Ok(false);
-        }
-    };
-
-    let is_complete = match &meta.inner {
-        RecordingMetaInner::Studio(studio) => {
-            matches!(studio.status(), StudioRecordingStatus::Complete)
-        }
-        RecordingMetaInner::Instant(instant) => {
-            matches!(instant, InstantRecordingMeta::Complete { .. })
-        }
-    };
-
-    if !is_complete {
-        debug!("check_import_ready: not complete yet");
-        return Ok(false);
-    }
-
-    let video_path = project_path
-        .join("content")
-        .join("segments")
-        .join("segment-0")
-        .join("display.mp4");
-
-    if !video_path.exists() {
-        debug!(
-            "check_import_ready: video path doesn't exist: {:?}",
-            video_path
-        );
-        return Ok(false);
-    }
-
-    let can_decode = probe_video_can_decode(&video_path);
-    debug!(
-        "check_import_ready: probe_video_can_decode result: {:?}",
-        can_decode
-    );
-    if !can_decode.unwrap_or(false) {
-        return Ok(false);
-    }
-
-    let duration = get_media_duration(&video_path);
-    debug!(
-        "check_import_ready: get_media_duration result: {:?}",
-        duration
-    );
-    if duration.is_none() {
-        return Ok(false);
-    }
-
-    debug!("check_import_ready: all checks passed, returning true");
-    Ok(true)
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn imported_video_frames_share_reference_counted_pixel_storage() {
-        let mut source = ffmpeg::frame::Video::new(ffmpeg::format::Pixel::YUV420P, 16, 12);
-        source.set_pts(Some(417));
-        source.data_mut(0)[..4].copy_from_slice(&[11, 22, 33, 44]);
-        let original = source.data(0).as_ptr();
-
-        let referenced = reference_video_frame(&source);
-
-        assert_eq!(referenced.data(0).as_ptr(), original);
-        assert_eq!(referenced.format(), ffmpeg::format::Pixel::YUV420P);
-        assert_eq!((referenced.width(), referenced.height()), (16, 12));
-        assert_eq!(referenced.pts(), Some(417));
-        let buffer = unsafe { (*source.as_ptr()).buf[0] };
-        assert!(!buffer.is_null());
-        assert_eq!(unsafe { ffmpeg::ffi::av_buffer_get_ref_count(buffer) }, 2);
-
-        drop(source);
-
-        assert_eq!(&referenced.data(0)[..4], &[11, 22, 33, 44]);
-        let retained = unsafe { (*referenced.as_ptr()).buf[0] };
-        assert_eq!(unsafe { ffmpeg::ffi::av_buffer_get_ref_count(retained) }, 1);
-    }
-
-    #[test]
-    fn imported_video_frame_references_preserve_non_yuv_formats() {
-        let mut source = ffmpeg::frame::Video::new(ffmpeg::format::Pixel::BGRA, 12, 8);
-        source.set_pts(Some(93));
-
-        let referenced = reference_video_frame(&source);
-
-        assert_eq!(referenced.data(0).as_ptr(), source.data(0).as_ptr());
-        assert_eq!(referenced.format(), ffmpeg::format::Pixel::BGRA);
-        assert_eq!((referenced.width(), referenced.height()), (12, 8));
-        assert_eq!(referenced.pts(), Some(93));
-    }
-
-    #[test]
-    fn source_asset_path_allows_file_inside_source_project() {
-        let source_project = tempfile::tempdir().unwrap();
-        let source_relative_path = RelativePathBuf::from("content/segments/segment-0/display.mp4");
-        let source_path = source_relative_path.to_path(source_project.path());
-        std::fs::create_dir_all(source_path.parent().unwrap()).unwrap();
-        std::fs::write(&source_path, b"video").unwrap();
-
-        let resolved = source_asset_path(
-            source_project.path(),
-            &source_relative_path,
-            "video",
-            VIDEO_IMPORT_EXTENSIONS,
-        )
-        .unwrap()
-        .unwrap();
-
-        assert_eq!(resolved, source_path.canonicalize().unwrap());
-    }
-
-    #[test]
-    fn source_asset_path_allows_backslash_separators() {
-        let source_project = tempfile::tempdir().unwrap();
-        let source_relative_path =
-            RelativePathBuf::from("content\\segments\\segment-0\\display.mp4");
-        let source_path = RelativePathBuf::from("content/segments/segment-0/display.mp4")
-            .to_path(source_project.path());
-        std::fs::create_dir_all(source_path.parent().unwrap()).unwrap();
-        std::fs::write(&source_path, b"video").unwrap();
-
-        let resolved = source_asset_path(
-            source_project.path(),
-            &source_relative_path,
-            "video",
-            VIDEO_IMPORT_EXTENSIONS,
-        )
-        .unwrap()
-        .unwrap();
-
-        assert_eq!(resolved, source_path.canonicalize().unwrap());
-    }
-
-    #[test]
-    fn source_asset_path_rejects_parent_traversal() {
-        let source_project = tempfile::tempdir().unwrap();
-        let source_relative_path = RelativePathBuf::from("../secret.mp4");
-
-        let error = source_asset_path(
-            source_project.path(),
-            &source_relative_path,
-            "video",
-            VIDEO_IMPORT_EXTENSIONS,
-        )
-        .unwrap_err();
-
-        assert!(error.contains("Invalid video path"));
-    }
-
-    #[test]
-    fn source_asset_path_rejects_absolute_path() {
-        let source_project = tempfile::tempdir().unwrap();
-        let source_relative_path = RelativePathBuf::from("/tmp/secret.mp4");
-
-        let error = source_asset_path(
-            source_project.path(),
-            &source_relative_path,
-            "video",
-            VIDEO_IMPORT_EXTENSIONS,
-        )
-        .unwrap_err();
-
-        assert!(error.contains("Invalid video path"));
-    }
-
-    #[test]
-    fn legacy_cursor_relative_path_rejects_windows_absolute_path() {
-        let error = legacy_cursor_relative_path("C:\\Users\\me\\cursor.png").unwrap_err();
-
-        assert!(error.contains("Invalid cursor image path"));
-    }
-
-    #[test]
-    fn source_asset_path_rejects_unsupported_extension() {
-        let source_project = tempfile::tempdir().unwrap();
-        let source_relative_path = RelativePathBuf::from("content/segments/segment-0/display.txt");
-
-        let error = source_asset_path(
-            source_project.path(),
-            &source_relative_path,
-            "video",
-            VIDEO_IMPORT_EXTENSIONS,
-        )
-        .unwrap_err();
-
-        assert!(error.contains("Unsupported video file type"));
-    }
-
-    #[cfg(unix)]
-    #[test]
-    fn source_asset_path_rejects_symlink_escape() {
-        let source_project = tempfile::tempdir().unwrap();
-        let external_dir = tempfile::tempdir().unwrap();
-        let external_file = external_dir.path().join("cursor.png");
-        std::fs::write(&external_file, b"cursor").unwrap();
-
-        let source_relative_path = RelativePathBuf::from("content/cursors/cursor.png");
-        let source_path = source_relative_path.to_path(source_project.path());
-        std::fs::create_dir_all(source_path.parent().unwrap()).unwrap();
-        std::os::unix::fs::symlink(&external_file, &source_path).unwrap();
-
-        let error = source_asset_path(
-            source_project.path(),
-            &source_relative_path,
-            "cursor image",
-            IMAGE_IMPORT_EXTENSIONS,
-        )
-        .unwrap_err();
-
-        assert!(error.contains("cursor image path escapes source project"));
-    }
-}
diff --git a/apps/desktop/src-tauri/src/lib.rs b/apps/desktop/src-tauri/src/lib.rs
deleted file mode 100644
index 03eeb3a1776..00000000000
--- a/apps/desktop/src-tauri/src/lib.rs
+++ /dev/null
@@ -1,11117 +0,0 @@
-#![recursion_limit = "256"]
-
-mod api;
-mod audio;
-mod audio_library;
-mod audio_meter;
-mod auth;
-mod automation;
-mod camera;
-mod camera_legacy;
-#[cfg(target_os = "macos")]
-mod camera_native;
-mod captions;
-mod clean_capture;
-mod cli;
-mod clip_thumbnails;
-mod crash_sentinel;
-mod deeplink_actions;
-mod diagnostics;
-mod editor_preparing;
-mod editor_recording;
-mod editor_window;
-mod exit_shutdown;
-mod export;
-mod fake_window;
-mod flags;
-pub mod frame_ws;
-mod general_settings;
-mod gpui_app;
-mod hotkeys;
-mod http_client;
-mod import;
-pub mod linux_instant_camera;
-mod logging;
-#[cfg(target_os = "macos")]
-mod macos_save_panel;
-mod main_window_geometry;
-mod notifications;
-mod panel_manager;
-mod permissions;
-#[cfg(debug_assertions)]
-mod picker_benchmark;
-mod platform;
-mod power_observer;
-mod preparing_finalization;
-mod presets;
-mod recording;
-mod recording_settings;
-mod recording_telemetry;
-mod recordings_locations;
-mod recovery;
-mod render_frame_event;
-mod screenshot_editor;
-mod startup;
-#[cfg(debug_assertions)]
-mod stop_editor_benchmark;
-mod target_select_overlay;
-mod telemetry;
-mod thumbnails;
-mod tray;
-mod update_project_names;
-mod updates;
-mod upload;
-pub mod web_api;
-mod window_exclusion;
-mod window_position_persistence;
-mod windows;
-
-use audio::AppSounds;
-use auth::{AuthStore, Plan};
-use camera::{CameraPreviewManager, CameraPreviewSender, CameraPreviewState};
-use cap_editor::{EditorInstance, EditorState};
-use cap_project::{
-    InstantRecordingMeta, ProjectConfiguration, RecordingMeta, RecordingMetaInner, SharingMeta,
-    StudioRecordingMeta, StudioRecordingStatus, UploadMeta, VideoUploadInfo, XY, ZoomSegment,
-};
-use cap_recording::{
-    RecordingMode,
-    feeds::{
-        self,
-        camera::{CameraFeed, DeviceOrModelID},
-        microphone::{self, MicrophoneFeed},
-    },
-    sources::screen_capture::ScreenCaptureTarget,
-};
-use cap_rendering::ProjectRecordingsMeta;
-use clipboard_rs::Clipboard;
-#[cfg(not(target_os = "linux"))]
-use clipboard_rs::ClipboardContext;
-#[cfg(target_os = "linux")]
-use clipboard_rs::ClipboardContext as PlatformClipboardContext;
-use clipboard_rs::common::RustImage;
-use cpal::StreamError;
-use editor_window::{EditorInstances, PendingEditorInstances, WindowEditorInstance};
-use ffmpeg::ffi::AV_TIME_BASE;
-use general_settings::GeneralSettingsStore;
-use kameo::{Actor, actor::ActorRef};
-use notifications::NotificationType;
-use recording::{InProgressRecording, RecordingEvent, RecordingInputKind};
-use scap_targets::{Display, DisplayId, WindowId, bounds::LogicalBounds};
-use screenshot_editor::{
-    PendingScreenshotEditorInstances, ScreenshotEditorInstances, WindowScreenshotEditorInstance,
-    create_screenshot_editor_instance, prewarm_screenshot_background, recognize_screenshot_text,
-    render_screenshot_for_export, render_screenshot_png, render_screenshot_project_for_export,
-    update_screenshot_config,
-};
-
-mod gpu_context;
-mod gpu_device_health;
-pub use gpu_context::{PendingScreenshot, PendingScreenshots};
-use serde::{Deserialize, Serialize};
-use serde_json::json;
-use specta::Type;
-use std::{
-    collections::{BTreeMap, HashSet},
-    future::Future,
-    marker::PhantomData,
-    path::{Path, PathBuf},
-    process::Command,
-    str::FromStr,
-    sync::{
-        Arc,
-        atomic::{AtomicBool, AtomicU64, Ordering},
-    },
-    time::{Duration, Instant, SystemTime, UNIX_EPOCH},
-};
-use tauri::Listener;
-use tauri::{AppHandle, Emitter, Manager, State, Window, WindowEvent, ipc::Channel};
-#[cfg(target_os = "linux")]
-use tauri_plugin_clipboard_manager::ClipboardExt;
-use tauri_plugin_deep_link::DeepLinkExt;
-use tauri_plugin_dialog::DialogExt;
-use tauri_plugin_global_shortcut::GlobalShortcutExt;
-use tauri_plugin_notification::{NotificationExt, PermissionState};
-use tauri_plugin_opener::OpenerExt;
-use tauri_plugin_shell::ShellExt;
-use tauri_specta::Event;
-use tokio::sync::{Mutex, RwLock, oneshot, watch};
-use tracing::*;
-use upload::{create_or_get_video, upload_screenshot_bytes, upload_screenshot_file, upload_video};
-use web_api::AuthedApiError;
-use web_api::ManagerExt as WebManagerExt;
-#[cfg(target_os = "macos")]
-use windows::hide_overlay;
-use windows::{
-    CapWindowId, EditorRecordingTarget, EditorWindowIds, ScreenshotEditorWindowIds, ShowCapWindow,
-    set_window_transparent, show_overlay,
-};
-
-use crate::recording_settings::{RecordingSettingsStore, RecordingTargetMode};
-use crate::{recording::start_recording, upload::build_video_meta};
-use exit_shutdown::{
-    AppExitAction, ExitBlocked, ExitRequestDecision, app_exit_action, collect_device_inventory,
-    handle_exit_requested, prepare_then_begin_exit, recording_start_allowed, run_while_active,
-    with_idle_recording_state,
-};
-use futures::FutureExt;
-use std::panic::AssertUnwindSafe;
-#[cfg(target_os = "macos")]
-use tauri::menu::{
-    AboutMetadata, HELP_SUBMENU_ID, Menu, MenuItem, PredefinedMenuItem, Submenu, WINDOW_SUBMENU_ID,
-};
-
-type FinalizationResult = Option>;
-const MAX_SETTLED_FINALIZATIONS: usize = 32;
-
-#[derive(Default)]
-struct FinalizingRecordingsMap {
-    attempts: std::collections::HashMap>,
-    settled: std::collections::VecDeque<(ProjectObjectId, String)>,
-    last_preparing_generation: u64,
-}
-
-#[derive(Clone, Copy, PartialEq, Eq)]
-enum FinalizationOrigin {
-    Recording,
-    Recovery,
-}
-
-struct FinalizationAttempt {
-    id: String,
-    origin: FinalizationOrigin,
-    project: Arc,
-    result: watch::Sender,
-    preparing_generation: Option,
-    preparing_presentation:
-        watch::Sender, String>>>,
-    preparing: watch::Sender,
-}
-
-pub(crate) struct FinalizationToken {
-    recordings: Arc>,
-    attempt: Arc,
-}
-
-enum FinalizationRequest {
-    Started(FinalizationToken),
-    Existing(watch::Receiver),
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-enum ProjectObjectId {
-    #[cfg(unix)]
-    Unix { device: u64, inode: u64 },
-    #[cfg(windows)]
-    Windows { volume: u64, file: [u8; 16] },
-}
-
-#[derive(Clone, Copy, PartialEq, Eq)]
-enum FinalizationAccess {
-    Observe,
-    Write,
-}
-
-pub(crate) struct FinalizationProject {
-    display_path: PathBuf,
-    work_path: PathBuf,
-    identity: ProjectObjectId,
-    access: FinalizationAccess,
-    _directory: std::fs::File,
-}
-
-fn open_finalization_directory(path: &Path) -> std::io::Result {
-    fn validate(metadata: &std::fs::Metadata) -> std::io::Result<()> {
-        #[cfg(windows)]
-        {
-            use std::os::windows::fs::MetadataExt;
-            if metadata.file_attributes() & 0x400 != 0 {
-                return Err(std::io::Error::other(
-                    "Recording directory is a reparse point",
-                ));
-            }
-        }
-        if metadata.file_type().is_symlink() || !metadata.is_dir() {
-            return Err(std::io::Error::other(
-                "Recording path is not an ordinary directory",
-            ));
-        }
-        Ok(())
-    }
-
-    validate(&path.symlink_metadata()?)?;
-    let mut options = std::fs::OpenOptions::new();
-    options.read(true);
-    #[cfg(unix)]
-    {
-        use std::os::unix::fs::OpenOptionsExt;
-        options.custom_flags(nix::libc::O_DIRECTORY | nix::libc::O_NOFOLLOW | nix::libc::O_CLOEXEC);
-    }
-    #[cfg(windows)]
-    {
-        use std::os::windows::fs::OpenOptionsExt;
-        options
-            .custom_flags(0x0200_0000 | 0x0020_0000)
-            .share_mode(0x1 | 0x2 | 0x4);
-    }
-    let directory = options.open(path)?;
-    validate(&directory.metadata()?)?;
-    Ok(directory)
-}
-
-fn finalization_directory_identity(directory: &std::fs::File) -> std::io::Result {
-    #[cfg(unix)]
-    {
-        use std::os::unix::fs::MetadataExt;
-        let metadata = directory.metadata()?;
-        Ok(ProjectObjectId::Unix {
-            device: metadata.dev(),
-            inode: metadata.ino(),
-        })
-    }
-    #[cfg(windows)]
-    {
-        use ::windows::Win32::{
-            Foundation::HANDLE,
-            Storage::FileSystem::{FILE_ID_INFO, FileIdInfo, GetFileInformationByHandleEx},
-        };
-        use std::os::windows::io::AsRawHandle;
-        let mut information = FILE_ID_INFO::default();
-        unsafe {
-            GetFileInformationByHandleEx(
-                HANDLE(directory.as_raw_handle()),
-                FileIdInfo,
-                (&mut information as *mut FILE_ID_INFO).cast(),
-                std::mem::size_of::() as u32,
-            )
-        }
-        .map_err(|error| std::io::Error::other(error.to_string()))?;
-        Ok(ProjectObjectId::Windows {
-            volume: information.VolumeSerialNumber,
-            file: information.FileId.Identifier,
-        })
-    }
-}
-
-impl FinalizationProject {
-    fn capture(display_path: PathBuf, access: FinalizationAccess) -> Result, String> {
-        let capture = || -> std::io::Result {
-            let directory = match access {
-                FinalizationAccess::Observe => {
-                    open_finalization_directory(&display_path.canonicalize()?)?
-                }
-                FinalizationAccess::Write => open_finalization_directory(&display_path)?,
-            };
-            let identity = finalization_directory_identity(&directory)?;
-            let work_path = display_path.canonicalize()?;
-            let project = Self {
-                display_path: display_path.clone(),
-                work_path,
-                identity,
-                access,
-                _directory: directory,
-            };
-            project.validate_identity()?;
-            Ok(project)
-        };
-        capture()
-            .map(Arc::new)
-            .map_err(|error| Self::identity_error(&display_path, error))
-    }
-
-    pub(crate) async fn admit(display_path: PathBuf) -> Result, String> {
-        Self::capture_async(display_path, FinalizationAccess::Write).await
-    }
-
-    pub(crate) async fn observe(display_path: PathBuf) -> Result, String> {
-        Self::capture_async(display_path, FinalizationAccess::Observe).await
-    }
-
-    async fn capture_async(
-        display_path: PathBuf,
-        access: FinalizationAccess,
-    ) -> Result, String> {
-        let error_path = display_path.clone();
-        tokio::task::spawn_blocking(move || Self::capture(display_path, access))
-            .await
-            .map_err(|error| Self::identity_error(&error_path, error))?
-    }
-
-    fn identity_error(path: &Path, error: impl std::fmt::Display) -> String {
-        recoverable_finalization_error(
-            path,
-            format!("Could not verify the recording directory: {error}"),
-        )
-    }
-
-    fn validate_identity(&self) -> std::io::Result<()> {
-        let observed_path = match self.access {
-            FinalizationAccess::Observe => self.display_path.canonicalize()?,
-            FinalizationAccess::Write => self.display_path.clone(),
-        };
-        for path in [&observed_path, &self.work_path] {
-            let directory = open_finalization_directory(path)?;
-            if finalization_directory_identity(&directory)? != self.identity {
-                return Err(std::io::Error::other(format!(
-                    "Recording directory changed at {}",
-                    path.display()
-                )));
-            }
-        }
-        Ok(())
-    }
-
-    pub(crate) fn validate(&self) -> Result<(), String> {
-        self.validate_identity()
-            .map_err(|error| Self::identity_error(&self.display_path, error))
-    }
-
-    pub(crate) async fn validate_async(self: &Arc) -> Result<(), String> {
-        let project = self.clone();
-        tokio::task::spawn_blocking(move || project.validate())
-            .await
-            .map_err(|error| Self::identity_error(&self.display_path, error))?
-    }
-
-    pub(crate) fn work_path(&self) -> &Path {
-        &self.work_path
-    }
-
-    pub(crate) fn display_path(&self) -> &Path {
-        &self.display_path
-    }
-}
-
-const EDITOR_PREVIEW_FPS: u32 = 60;
-const EDITOR_OUTPUT_SIZE: XY = XY::new(1920, 1080);
-const DEFAULT_EDITOR_PREVIEW_SCALE_NUMERATOR: u32 = 65;
-const DEFAULT_EDITOR_PREVIEW_SCALE_DENOMINATOR: u32 = 100;
-
-fn default_editor_preview_resolution() -> XY {
-    scaled_editor_preview_resolution(
-        EDITOR_OUTPUT_SIZE,
-        DEFAULT_EDITOR_PREVIEW_SCALE_NUMERATOR,
-        DEFAULT_EDITOR_PREVIEW_SCALE_DENOMINATOR,
-    )
-}
-
-fn scaled_editor_preview_resolution(
-    output_size: XY,
-    numerator: u32,
-    denominator: u32,
-) -> XY {
-    XY::new(
-        scaled_editor_preview_dimension(output_size.x, numerator, denominator, 4, 4),
-        scaled_editor_preview_dimension(output_size.y, numerator, denominator, 2, 2),
-    )
-}
-
-fn scaled_editor_preview_dimension(
-    value: u32,
-    numerator: u32,
-    denominator: u32,
-    minimum: u32,
-    alignment: u32,
-) -> u32 {
-    let denominator = denominator.max(1);
-    let alignment = alignment.max(1);
-    let scaled = ((u64::from(value) * u64::from(numerator)) + (u64::from(denominator) / 2))
-        / u64::from(denominator);
-    let rounded = u32::try_from(scaled).unwrap_or(u32::MAX).max(minimum);
-    let aligned = u64::from(rounded).div_ceil(u64::from(alignment)) * u64::from(alignment);
-
-    u32::try_from(aligned).unwrap_or(u32::MAX)
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn tauri_event_loop_runs_once_on_its_calling_thread() {
-        let thread = std::thread::current().id();
-        let calls = std::cell::Cell::new(0);
-        let result = run_tauri_event_loop(|| {
-            assert_eq!(std::thread::current().id(), thread);
-            calls.set(calls.get() + 1);
-            42
-        });
-        assert_eq!(calls.get(), 1);
-        assert_eq!(result, 42);
-    }
-
-    #[cfg(target_os = "linux")]
-    #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
-    async fn linux_tauri_event_loop_allows_blocking_plugin_setup_and_shutdown() {
-        let thread = std::thread::current().id();
-        run_tauri_event_loop(|| {
-            assert_eq!(std::thread::current().id(), thread);
-            let plugin_runtime = tokio::runtime::Builder::new_multi_thread()
-                .worker_threads(1)
-                .enable_all()
-                .build()
-                .unwrap();
-            assert_eq!(plugin_runtime.block_on(async { 1 }), 1);
-            let callback = tokio::spawn(async { 2 });
-            assert_eq!(plugin_runtime.block_on(callback).unwrap(), 2);
-            assert_eq!(plugin_runtime.block_on(async { 3 }), 3);
-        });
-        assert_eq!(tokio::spawn(async { 4 }).await.unwrap(), 4);
-    }
-
-    #[test]
-    fn default_editor_preview_resolution_matches_frontend_defaults() {
-        assert_eq!(default_editor_preview_resolution(), XY::new(1248, 702));
-    }
-
-    #[test]
-    fn scaled_editor_preview_resolution_rounds_like_frontend() {
-        assert_eq!(
-            scaled_editor_preview_resolution(XY::new(1919, 1079), 65, 100),
-            XY::new(1248, 702)
-        );
-    }
-
-    #[cfg(target_os = "linux")]
-    #[test]
-    fn wayland_clipboard_fallback_requires_wayland_without_x11() {
-        use std::ffi::OsStr;
-
-        assert!(uses_wayland_clipboard_fallback(
-            Some(OsStr::new("wayland-1")),
-            None
-        ));
-        assert!(!uses_wayland_clipboard_fallback(
-            Some(OsStr::new("wayland-1")),
-            Some(OsStr::new(":0"))
-        ));
-        assert!(!uses_wayland_clipboard_fallback(None, None));
-    }
-
-    #[test]
-    fn graphics_recovery_only_engages_for_gpu_init_deaths() {
-        use crash_sentinel::UnexpectedTermination;
-
-        // Clean previous exit: never engage.
-        assert!(!should_engage_graphics_recovery(None));
-
-        // Died outside GPU init (force-quit, power loss, OS kill): a healthy GPU
-        // machine must keep hardware rendering.
-        assert!(!should_engage_graphics_recovery(Some(
-            UnexpectedTermination {
-                during_gpu_init: false,
-                in_graphics_recovery: false,
-                blur_active: false,
-            }
-        )));
-
-        // Died during GPU bring-up on hardware: engage software recovery.
-        assert!(should_engage_graphics_recovery(Some(
-            UnexpectedTermination {
-                during_gpu_init: true,
-                in_graphics_recovery: false,
-                blur_active: false,
-            }
-        )));
-
-        // A recovery-mode session that also died must not chain into recovery
-        // forever; retry hardware.
-        assert!(!should_engage_graphics_recovery(Some(
-            UnexpectedTermination {
-                during_gpu_init: true,
-                in_graphics_recovery: true,
-                blur_active: false,
-            }
-        )));
-        assert!(!should_engage_graphics_recovery(Some(
-            UnexpectedTermination {
-                during_gpu_init: false,
-                in_graphics_recovery: true,
-                blur_active: false,
-            }
-        )));
-    }
-
-    #[test]
-    fn camera_blur_crash_recovery_disables_and_heals_on_update() {
-        use crash_sentinel::UnexpectedTermination;
-
-        let died_with_blur = Some(UnexpectedTermination {
-            during_gpu_init: false,
-            in_graphics_recovery: false,
-            blur_active: true,
-        });
-        let died_without_blur = Some(UnexpectedTermination {
-            during_gpu_init: false,
-            in_graphics_recovery: false,
-            blur_active: false,
-        });
-
-        // Clean exit, blur never disabled: stays enabled.
-        assert_eq!(next_camera_blur_disabled_version(None, None, "1.0"), None);
-
-        // Deaths unrelated to blur must not disable it.
-        assert_eq!(
-            next_camera_blur_disabled_version(None, died_without_blur, "1.0"),
-            None
-        );
-
-        // A death with blur active disables it at the current version.
-        assert_eq!(
-            next_camera_blur_disabled_version(None, died_with_blur, "1.0"),
-            Some("1.0".into())
-        );
-
-        // The disable persists across clean launches of the same version.
-        assert_eq!(
-            next_camera_blur_disabled_version(Some("1.0"), None, "1.0"),
-            Some("1.0".into())
-        );
-
-        // An app update heals: the new stack gets one retry.
-        assert_eq!(
-            next_camera_blur_disabled_version(Some("1.0"), None, "1.1"),
-            None
-        );
-
-        // But a fresh blur-attributed death beats version optimism.
-        assert_eq!(
-            next_camera_blur_disabled_version(Some("1.0"), died_with_blur, "1.1"),
-            Some("1.1".into())
-        );
-    }
-}
-
-#[derive(Default)]
-pub struct FinalizingRecordings {
-    recordings: Arc>,
-}
-
-pub struct CameraWindowCloseGate(AtomicBool);
-
-impl Default for CameraWindowCloseGate {
-    fn default() -> Self {
-        Self(AtomicBool::new(false))
-    }
-}
-
-impl CameraWindowCloseGate {
-    pub fn allow_close(&self) -> bool {
-        self.0.load(Ordering::Acquire)
-    }
-
-    pub fn set_allow_close(&self, value: bool) {
-        self.0.store(value, Ordering::Release);
-    }
-}
-
-pub struct AppExitState {
-    exiting: AtomicBool,
-    restarting: AtomicBool,
-    title_flush_pending: AtomicBool,
-    admission: std::sync::Mutex<()>,
-}
-
-impl Default for AppExitState {
-    fn default() -> Self {
-        Self {
-            exiting: AtomicBool::new(false),
-            restarting: AtomicBool::new(false),
-            title_flush_pending: AtomicBool::new(false),
-            admission: std::sync::Mutex::new(()),
-        }
-    }
-}
-
-impl AppExitState {
-    fn begin_title_flush(&self) -> Option> {
-        self.title_flush_pending
-            .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
-            .ok()
-            .map(|_| PendingTitleExit(self))
-    }
-
-    fn exit_pending(&self) -> bool {
-        self.is_exiting() || self.title_flush_pending.load(Ordering::Acquire)
-    }
-
-    pub fn begin(&self) -> bool {
-        self.exiting
-            .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
-            .is_ok()
-    }
-
-    pub fn begin_restart(&self) {
-        self.restarting.store(true, Ordering::Release);
-        self.exiting.store(true, Ordering::Release);
-    }
-
-    pub fn is_exiting(&self) -> bool {
-        self.exiting.load(Ordering::Acquire)
-    }
-
-    pub fn is_restarting(&self) -> bool {
-        self.restarting.load(Ordering::Acquire)
-    }
-}
-
-struct PendingTitleExit<'a>(&'a AppExitState);
-
-impl Drop for PendingTitleExit<'_> {
-    fn drop(&mut self) {
-        self.0.title_flush_pending.store(false, Ordering::Release);
-    }
-}
-
-pub struct MainWindowReadyState(AtomicBool);
-
-impl Default for MainWindowReadyState {
-    fn default() -> Self {
-        Self(AtomicBool::new(false))
-    }
-}
-
-impl MainWindowReadyState {
-    pub fn is_ready(&self) -> bool {
-        self.0.load(Ordering::Acquire)
-    }
-
-    pub fn set_ready(&self, value: bool) {
-        self.0.store(value, Ordering::Release);
-    }
-}
-
-const APP_EXIT_STEP_TIMEOUT: Duration = Duration::from_millis(750);
-const APP_EXIT_CAMERA_SHUTDOWN_TIMEOUT: Duration = Duration::from_millis(1200);
-const APP_EXIT_TOTAL_TIMEOUT: Duration = Duration::from_secs(3);
-const APP_EXIT_FORCE_TIMEOUT: Duration = Duration::from_secs(8);
-#[cfg(target_os = "macos")]
-const APP_MENU_QUIT_ID: &str = "app_quit";
-#[cfg(target_os = "macos")]
-static MACOS_NATIVE_TERMINATE_APP: std::sync::OnceLock = std::sync::OnceLock::new();
-
-async fn await_exit_step(name: &'static str, timeout: Duration, fut: F) -> Option
-where
-    E: std::fmt::Display,
-    F: Future>,
-{
-    let started = Instant::now();
-    match tokio::time::timeout(timeout, fut).await {
-        Ok(Ok(value)) => {
-            info!(
-                step = name,
-                elapsed_ms = started.elapsed().as_millis(),
-                "Exit cleanup step completed"
-            );
-            Some(value)
-        }
-        Ok(Err(err)) => {
-            warn!(
-                step = name,
-                elapsed_ms = started.elapsed().as_millis(),
-                error = %err,
-                "Exit cleanup step failed"
-            );
-            None
-        }
-        Err(_) => {
-            warn!(
-                step = name,
-                timeout_ms = timeout.as_millis(),
-                elapsed_ms = started.elapsed().as_millis(),
-                "Exit cleanup step timed out"
-            );
-            None
-        }
-    }
-}
-
-fn log_process_memory_snapshot(stage: &'static str) {
-    let Ok(pid) = sysinfo::get_current_pid() else {
-        return;
-    };
-
-    let mut system = sysinfo::System::new();
-    system.refresh_processes(sysinfo::ProcessesToUpdate::Some(&[pid]), true);
-
-    if let Some(process) = system.process(pid) {
-        info!(
-            stage = stage,
-            rss_mb = process.memory() / 1_048_576,
-            virtual_mb = process.virtual_memory() / 1_048_576,
-            "Process memory snapshot"
-        );
-    }
-}
-
-fn spawn_process_memory_sampler(app: AppHandle) {
-    tokio::spawn(async move {
-        let mut interval = tokio::time::interval(Duration::from_secs(60));
-
-        loop {
-            interval.tick().await;
-
-            if app_is_exiting(&app) {
-                break;
-            }
-
-            log_process_memory_snapshot("periodic");
-        }
-    });
-}
-
-fn force_exit(code: i32) -> ! {
-    unsafe extern "C" {
-        fn _exit(code: i32) -> !;
-    }
-    unsafe { _exit(code) }
-}
-
-fn spawn_exit_watchdog() {
-    std::thread::spawn(move || {
-        std::thread::sleep(APP_EXIT_FORCE_TIMEOUT);
-        error!(
-            timeout_ms = APP_EXIT_FORCE_TIMEOUT.as_millis(),
-            "Forcing process exit after shutdown deadline"
-        );
-        force_exit(0);
-    });
-}
-
-pub(crate) fn app_is_exiting(app: &AppHandle) -> bool {
-    match app.try_state::() {
-        Some(state) => state.is_exiting(),
-        None => false,
-    }
-}
-
-fn should_show_onboarding(app: &AppHandle) -> bool {
-    let settings = GeneralSettingsStore::get(app).ok().flatten();
-    let startup_completed = settings
-        .as_ref()
-        .map(|s| s.has_completed_startup)
-        .unwrap_or(false);
-    let onboarding_completed = settings
-        .as_ref()
-        .map(|s| s.has_completed_onboarding)
-        .unwrap_or(false);
-
-    !startup_completed
-        || !onboarding_completed
-        || !permissions::do_permissions_check(false).necessary_granted()
-}
-
-#[cfg(target_os = "macos")]
-fn build_macos_app_menu(app_handle: &AppHandle) -> tauri::Result> {
-    let pkg_info = app_handle.package_info();
-    let config = app_handle.config();
-    let about_metadata = AboutMetadata {
-        name: Some(pkg_info.name.clone()),
-        version: Some(pkg_info.version.to_string()),
-        copyright: config.bundle.copyright.clone(),
-        authors: config
-            .bundle
-            .publisher
-            .clone()
-            .map(|publisher| vec![publisher]),
-        ..Default::default()
-    };
-    let quit_label = config
-        .product_name
-        .as_ref()
-        .map(|name| format!("Quit {name}"))
-        .unwrap_or_else(|| "Quit Cap".to_string());
-
-    let window_menu = Submenu::with_id_and_items(
-        app_handle,
-        WINDOW_SUBMENU_ID,
-        "Window",
-        true,
-        &[
-            &PredefinedMenuItem::minimize(app_handle, None)?,
-            &PredefinedMenuItem::maximize(app_handle, None)?,
-            &PredefinedMenuItem::separator(app_handle)?,
-            &PredefinedMenuItem::close_window(app_handle, None)?,
-        ],
-    )?;
-
-    let help_menu = Submenu::with_id_and_items(app_handle, HELP_SUBMENU_ID, "Help", true, &[])?;
-
-    Menu::with_items(
-        app_handle,
-        &[
-            &Submenu::with_items(
-                app_handle,
-                pkg_info.name.clone(),
-                true,
-                &[
-                    &PredefinedMenuItem::about(app_handle, None, Some(about_metadata))?,
-                    &PredefinedMenuItem::separator(app_handle)?,
-                    &PredefinedMenuItem::services(app_handle, None)?,
-                    &PredefinedMenuItem::separator(app_handle)?,
-                    &PredefinedMenuItem::hide(app_handle, None)?,
-                    &PredefinedMenuItem::hide_others(app_handle, None)?,
-                    &PredefinedMenuItem::separator(app_handle)?,
-                    &MenuItem::with_id(
-                        app_handle,
-                        APP_MENU_QUIT_ID,
-                        quit_label,
-                        true,
-                        Some("Cmd+Q"),
-                    )?,
-                ],
-            )?,
-            &Submenu::with_items(
-                app_handle,
-                "File",
-                true,
-                &[&PredefinedMenuItem::close_window(app_handle, None)?],
-            )?,
-            &Submenu::with_items(
-                app_handle,
-                "Edit",
-                true,
-                &[
-                    &PredefinedMenuItem::undo(app_handle, None)?,
-                    &PredefinedMenuItem::redo(app_handle, None)?,
-                    &PredefinedMenuItem::separator(app_handle)?,
-                    &PredefinedMenuItem::cut(app_handle, None)?,
-                    &PredefinedMenuItem::copy(app_handle, None)?,
-                    &PredefinedMenuItem::paste(app_handle, None)?,
-                    &PredefinedMenuItem::select_all(app_handle, None)?,
-                ],
-            )?,
-            &Submenu::with_items(
-                app_handle,
-                "View",
-                true,
-                &[&PredefinedMenuItem::fullscreen(app_handle, None)?],
-            )?,
-            &window_menu,
-            &help_menu,
-        ],
-    )
-}
-
-#[cfg(target_os = "macos")]
-unsafe extern "C" fn macos_application_should_terminate(
-    _: &objc::runtime::Object,
-    _: objc::runtime::Sel,
-    _: cocoa::base::id,
-) -> isize {
-    if let Some(app) = MACOS_NATIVE_TERMINATE_APP.get() {
-        let app = app.clone();
-        tokio::spawn(async move {
-            request_app_exit(app).await;
-        });
-    } else {
-        warn!("macOS native termination requested before app exit handler was installed");
-    }
-
-    0
-}
-
-#[cfg(target_os = "macos")]
-fn install_macos_native_terminate_handler(app: &AppHandle) {
-    use cocoa::base::{id, nil};
-    use objc::{class, msg_send, sel, sel_impl};
-
-    let _ = MACOS_NATIVE_TERMINATE_APP.set(app.clone());
-
-    unsafe {
-        let ns_app: id = msg_send![class!(NSApplication), sharedApplication];
-        let delegate: id = msg_send![ns_app, delegate];
-
-        if delegate == nil {
-            warn!("Unable to install macOS native termination handler without app delegate");
-            return;
-        }
-
-        let delegate_class = (*delegate).class() as *const _ as *mut objc::runtime::Class;
-        let imp = std::mem::transmute::<
-            unsafe extern "C" fn(&objc::runtime::Object, objc::runtime::Sel, id) -> isize,
-            objc::runtime::Imp,
-        >(macos_application_should_terminate);
-        let added = objc::runtime::class_addMethod(
-            delegate_class,
-            sel!(applicationShouldTerminate:),
-            imp,
-            c"q@:@".as_ptr(),
-        );
-
-        if added == objc::runtime::YES {
-            info!("Installed macOS native termination handler");
-        } else {
-            warn!("macOS native termination handler was already installed");
-        }
-    }
-}
-
-fn now_millis() -> u64 {
-    SystemTime::now()
-        .duration_since(UNIX_EPOCH)
-        .map(|d| d.as_millis() as u64)
-        .unwrap_or(0)
-}
-
-#[derive(Debug)]
-pub struct CameraWindowPositionGuard {
-    ignore_until_ms: AtomicU64,
-}
-
-impl Default for CameraWindowPositionGuard {
-    fn default() -> Self {
-        Self {
-            ignore_until_ms: AtomicU64::new(0),
-        }
-    }
-}
-
-impl CameraWindowPositionGuard {
-    pub fn ignore_for(&self, duration_ms: u64) {
-        let now = now_millis();
-        let until = now.saturating_add(duration_ms);
-        self.ignore_until_ms.store(until, Ordering::Release);
-    }
-
-    pub fn should_ignore(&self) -> bool {
-        let now = now_millis();
-        now < self.ignore_until_ms.load(Ordering::Acquire)
-    }
-}
-
-pub type CameraWindowOperationLock = Mutex<()>;
-
-impl FinalizingRecordings {
-    fn request(
-        &self,
-        project: Arc,
-        retry_failed: bool,
-        origin: FinalizationOrigin,
-        preparing_requested: bool,
-    ) -> Result {
-        if project.access != FinalizationAccess::Write {
-            return Err("Recording directory was not admitted for recovery.".into());
-        }
-        let mut recordings = self
-            .recordings
-            .lock()
-            .expect("FinalizingRecordings mutex poisoned");
-        if let Some(attempt) = recordings.attempts.get(&project.identity)
-            && attempt
-                .result
-                .borrow()
-                .as_ref()
-                .is_none_or(|result| !retry_failed && result.is_err())
-        {
-            return Ok(FinalizationRequest::Existing(attempt.result.subscribe()));
-        }
-        let preparing_generation = if preparing_requested
-            && origin == FinalizationOrigin::Recording
-            && let Some(generation) = recordings.last_preparing_generation.checked_add(1)
-        {
-            recordings.last_preparing_generation = generation;
-            Some(generation)
-        } else {
-            None
-        };
-        let attempt = Arc::new(FinalizationAttempt {
-            id: uuid::Uuid::new_v4().to_string(),
-            origin,
-            project,
-            result: watch::channel(None).0,
-            preparing_generation,
-            preparing_presentation: watch::channel(None).0,
-            preparing: watch::channel(Default::default()).0,
-        });
-        recordings
-            .settled
-            .retain(|(identity, _)| *identity != attempt.project.identity);
-        let _ = recordings
-            .attempts
-            .insert(attempt.project.identity, attempt.clone());
-        Ok(FinalizationRequest::Started(FinalizationToken {
-            recordings: self.recordings.clone(),
-            attempt,
-        }))
-    }
-
-    fn start_with_origin(
-        &self,
-        project: Arc,
-        origin: FinalizationOrigin,
-        preparing_requested: bool,
-    ) -> Result {
-        match self.request(project, true, origin, preparing_requested)? {
-            FinalizationRequest::Started(token) => Ok(token),
-            FinalizationRequest::Existing(_) => Err(
-                "This recording is already being prepared. Please wait for it to finish.".into(),
-            ),
-        }
-    }
-
-    pub(crate) fn start_finalizing(
-        &self,
-        project: Arc,
-    ) -> Result {
-        self.start_with_origin(project, FinalizationOrigin::Recording, true)
-    }
-
-    pub(crate) fn start_recovering(
-        &self,
-        project: Arc,
-    ) -> Result {
-        self.start_with_origin(project, FinalizationOrigin::Recovery, false)
-    }
-
-    pub(crate) async fn recovery_success(&self, path: &Path) -> Result, String> {
-        let project = FinalizationProject::observe(path.to_path_buf()).await?;
-        self.recovery_success_for_project(&project).await
-    }
-
-    pub(crate) async fn recovery_success_for_project(
-        &self,
-        project: &Arc,
-    ) -> Result, String> {
-        project.validate_async().await?;
-        let attempt = {
-            let recordings = self.recordings.lock().unwrap();
-            let Some(attempt) = recordings.attempts.get(&project.identity) else {
-                return Ok(None);
-            };
-            if attempt.origin != FinalizationOrigin::Recovery {
-                return Ok(None);
-            }
-            attempt.clone()
-        };
-        if await_finalization_result(attempt.result.subscribe())
-            .await
-            .is_err()
-        {
-            return Ok(None);
-        }
-        project.validate_async().await?;
-        let recordings = self.recordings.lock().unwrap();
-        Ok(recordings
-            .attempts
-            .get(&project.identity)
-            .filter(|current| Arc::ptr_eq(current, &attempt))
-            .map(|_| attempt.id.clone()))
-    }
-
-    fn is_finalizing(
-        &self,
-        project: &FinalizationProject,
-    ) -> Option> {
-        let recordings = self.recordings.lock().unwrap();
-        recordings
-            .attempts
-            .get(&project.identity)
-            .filter(|attempt| !matches!(attempt.result.borrow().as_ref(), Some(Ok(()))))
-            .map(|attempt| attempt.result.subscribe())
-    }
-}
-
-fn recoverable_finalization_error(path: &Path, error: String) -> String {
-    if error.starts_with("Not enough space to finish this recording.")
-        || error
-            .to_ascii_lowercase()
-            .contains("may need to be recovered")
-    {
-        return error;
-    }
-    format!(
-        "This recording may need to be recovered. {error} Your recording files have been kept at {}. Try recovery again.",
-        path.display()
-    )
-}
-
-fn has_pending_finalizations(recordings: &FinalizingRecordingsMap) -> bool {
-    recordings
-        .attempts
-        .values()
-        .any(|attempt| attempt.result.borrow().is_none())
-}
-
-impl FinalizationToken {
-    fn publish(&self, result: Result<(), String>) -> bool {
-        let mut recordings = self.recordings.lock().unwrap();
-        if recordings
-            .attempts
-            .get(&self.attempt.project.identity)
-            .is_none_or(|current| !Arc::ptr_eq(current, &self.attempt))
-        {
-            return false;
-        }
-        let result = result.map_err(|error| {
-            recoverable_finalization_error(self.attempt.project.display_path(), error)
-        });
-        let succeeded = result.is_ok();
-        let published = self.attempt.result.send_if_modified(|current| {
-            if current.is_some() {
-                return false;
-            }
-            *current = Some(result);
-            true
-        });
-        if published {
-            if succeeded && self.attempt.origin == FinalizationOrigin::Recording {
-                let _ = recordings.attempts.remove(&self.attempt.project.identity);
-            } else {
-                recordings
-                    .settled
-                    .push_back((self.attempt.project.identity, self.attempt.id.clone()));
-                while recordings.settled.len() > MAX_SETTLED_FINALIZATIONS {
-                    if let Some((identity, id)) = recordings.settled.pop_front()
-                        && recordings.attempts.get(&identity).is_some_and(|attempt| {
-                            attempt.id == id && attempt.result.borrow().is_some()
-                        })
-                    {
-                        let _ = recordings.attempts.remove(&identity);
-                    }
-                }
-            }
-        }
-        published
-    }
-
-    pub(crate) fn finish(self, result: Result<(), String>) {
-        self.publish(result);
-    }
-}
-
-impl Drop for FinalizationToken {
-    fn drop(&mut self) {
-        self.publish(Err("Preparing this recording was interrupted.".into()));
-    }
-}
-
-async fn await_finalization_result(
-    mut result: watch::Receiver,
-) -> Result<(), String> {
-    loop {
-        if let Some(result) = result.borrow_and_update().clone() {
-            return result;
-        }
-        result
-            .changed()
-            .await
-            .map_err(|_| "Recording finalization ended without a result.".to_string())?;
-    }
-}
-
-pub(crate) async fn run_finalization_worker(
-    token: FinalizationToken,
-    work: impl FnOnce(&FinalizationProject) -> Result + Send + 'static,
-) -> Result {
-    let path = token.attempt.project.display_path().to_path_buf();
-    tokio::task::spawn_blocking(move || {
-        let project = &token.attempt.project;
-        let result = project
-            .validate()
-            .and_then(|()| work(project))
-            .and_then(|value| project.validate().map(|()| value))
-            .map_err(|error| recoverable_finalization_error(project.display_path(), error));
-        token.finish(result.as_ref().map(|_| ()).map_err(Clone::clone));
-        result
-    })
-    .await
-    .map_err(|error| {
-        recoverable_finalization_error(
-            &path,
-            format!("Recording finalization task failed: {error}"),
-        )
-    })?
-}
-
-#[allow(clippy::large_enum_variant)]
-pub enum RecordingState {
-    None,
-    Pending {
-        mode: RecordingMode,
-        target: ScreenCaptureTarget,
-    },
-    Active(InProgressRecording),
-}
-
-#[derive(Clone)]
-pub(crate) struct RequestedInput {
-    value: Option,
-    revision: u64,
-    pending: bool,
-    error: Option,
-    configuration: Option,
-}
-
-impl RequestedInput {
-    fn new(value: Option) -> Self {
-        Self {
-            value,
-            revision: 0,
-            pending: false,
-            error: None,
-            configuration: None,
-        }
-    }
-
-    fn begin(&mut self, value: Option) -> u64 {
-        self.value = value;
-        self.revision = self.revision.wrapping_add(1);
-        self.pending = true;
-        self.error = None;
-        self.configuration = None;
-        self.revision
-    }
-
-    fn begin_or_join(
-        &mut self,
-        value: Option,
-        configuration: serde_json::Value,
-        recording_starting: bool,
-    ) -> (u64, bool)
-    where
-        T: PartialEq,
-    {
-        if (self.pending || (recording_starting && self.error.is_none()))
-            && self.value == value
-            && self.configuration.as_ref() == Some(&configuration)
-        {
-            return (self.revision, true);
-        }
-        let revision = self.begin(value);
-        self.configuration = Some(configuration);
-        (revision, false)
-    }
-
-    fn finish(&mut self, revision: u64, result: &Result<(), String>) {
-        if self.revision == revision {
-            self.pending = false;
-            self.error = result.as_ref().err().cloned();
-        }
-    }
-
-    fn prepare_restore(&mut self, revision: u64) -> bool {
-        if self.revision != revision || self.pending {
-            return false;
-        }
-        self.pending = true;
-        self.error = None;
-        true
-    }
-
-    fn validate(&self, kind: &str) -> Result<(), String> {
-        if self.pending {
-            return Err(format!(
-                "The requested {kind} is still being configured. Wait before recording."
-            ));
-        }
-        if let Some(error) = &self.error {
-            return Err(format!(
-                "The requested {kind} could not be configured: {error}. Select it again or choose another input before recording."
-            ));
-        }
-        Ok(())
-    }
-}
-
-async fn wait_for_existing_input(
-    revision: u64,
-    kind: &str,
-    read: impl Fn() -> RequestedInput,
-) -> Result<(), String> {
-    tokio::time::timeout(Duration::from_secs(30), async {
-        loop {
-            let input = read();
-            if input.revision != revision {
-                return Err(format!(
-                    "{kind} selection was superseded by a newer request"
-                ));
-            }
-            if !input.pending {
-                return input.error.map_or(Ok(()), Err);
-            }
-            tokio::time::sleep(Duration::from_millis(10)).await;
-        }
-    })
-    .await
-    .map_err(|_| format!("Timed out waiting for the selected {kind}"))?
-}
-
-#[derive(Clone)]
-pub(crate) struct RequestedInputs {
-    microphone: RequestedInput,
-    camera: RequestedInput,
-}
-
-pub(crate) struct RequestedInputsState {
-    inner: Arc>,
-    operation: Mutex<()>,
-}
-
-impl RequestedInputsState {
-    fn new(microphone: Option, camera: Option) -> Self {
-        Self {
-            inner: Arc::new(std::sync::Mutex::new(RequestedInputs {
-                microphone: RequestedInput::new(microphone),
-                camera: RequestedInput::new(camera),
-            })),
-            operation: Mutex::new(()),
-        }
-    }
-
-    pub(crate) fn snapshot(&self) -> RequestedInputs {
-        self.inner.lock().unwrap().clone()
-    }
-
-    pub(crate) fn ready_snapshot(&self) -> Result {
-        let snapshot = self.snapshot();
-        snapshot.microphone.validate("microphone")?;
-        snapshot.camera.validate("camera")?;
-        Ok(snapshot)
-    }
-
-    pub(crate) fn ensure_ready_for_resume(&self) -> Result<(), String> {
-        self.ready_snapshot().map(|_| ()).map_err(|error| {
-            format!("Cannot resume recording: {error} Finish configuring or reselect the requested inputs before resuming.")
-        })
-    }
-
-    pub(crate) fn try_resume_guard(&self) -> Result, String> {
-        let guard = self.operation.try_lock().map_err(|_| {
-            "Input change in progress. Finish configuring or reselect the requested inputs before resuming.".to_string()
-        })?;
-        self.ensure_ready_for_resume()?;
-        Ok(guard)
-    }
-
-    pub(crate) fn is_current(&self, snapshot: &RequestedInputs) -> bool {
-        let current = self.inner.lock().unwrap();
-        current.microphone.revision == snapshot.microphone.revision
-            && current.camera.revision == snapshot.camera.revision
-    }
-
-    fn mic_is_current(&self, revision: u64) -> bool {
-        self.inner.lock().unwrap().microphone.revision == revision
-    }
-
-    fn camera_is_current(&self, revision: u64) -> bool {
-        self.inner.lock().unwrap().camera.revision == revision
-    }
-
-    fn publish_mic_if_current(&self, revision: u64, publish: impl FnOnce()) -> bool {
-        let current = self.inner.lock().unwrap();
-        if current.microphone.revision != revision {
-            return false;
-        }
-        publish();
-        true
-    }
-
-    pub(crate) fn publish_camera_if_current(&self, revision: u64, publish: impl FnOnce()) -> bool {
-        let current = self.inner.lock().unwrap();
-        if current.camera.revision != revision {
-            return false;
-        }
-        publish();
-        true
-    }
-
-    pub(crate) fn publish_if_current(
-        &self,
-        snapshot: &RequestedInputs,
-        publish: impl FnOnce(),
-    ) -> bool {
-        let current = self.inner.lock().unwrap();
-        if current.microphone.revision != snapshot.microphone.revision
-            || current.camera.revision != snapshot.camera.revision
-        {
-            return false;
-        }
-        publish();
-        true
-    }
-}
-
-#[derive(Default)]
-struct AppliedMicrophoneInput {
-    valid: bool,
-    generation: u64,
-    settings: Option,
-}
-
-impl AppliedMicrophoneInput {
-    fn prepare_change(
-        &mut self,
-        active: bool,
-        requested: Option<&str>,
-        selected: Option<&str>,
-    ) -> bool {
-        if active && self.valid && requested.is_some() && requested == selected {
-            return false;
-        }
-        self.invalidate();
-        true
-    }
-
-    fn invalidate(&mut self) {
-        self.valid = false;
-        self.generation = self.generation.wrapping_add(1);
-    }
-
-    fn confirm_if_current(&mut self, generation: u64) -> bool {
-        if self.generation != generation {
-            return false;
-        }
-        self.confirm();
-        true
-    }
-
-    fn confirm(&mut self) {
-        self.valid = true;
-    }
-}
-
-pub struct App {
-    #[deprecated = "can be removed when native camera preview is ready"]
-    camera_ws_port: u16,
-    #[deprecated = "can be removed when native camera preview is ready"]
-    camera_ws_sender: flume::Sender,
-    #[cfg(target_os = "linux")]
-    pub camera_processing: linux_instant_camera::ProcessingFactory,
-    camera_preview: CameraPreviewManager,
-    camera_preview_state_tx: tokio::sync::watch::Sender,
-    handle: AppHandle,
-    recording_state: RecordingState,
-    recording_logging_handle: LoggingHandle,
-    mic_feed: ActorRef,
-    mic_meter_sender: flume::Sender,
-    selected_mic_label: Option,
-    applied_mic_input: AppliedMicrophoneInput,
-    selected_camera_id: Option,
-    camera_in_use: bool,
-    camera_cleanup_done: bool,
-    camera_feed: ActorRef,
-    server_url: String,
-    logs_dir: Option,
-    disconnected_inputs: HashSet,
-    was_camera_only_recording: bool,
-}
-
-#[derive(specta::Type, Serialize, Deserialize, Clone, Debug)]
-#[serde(rename_all = "camelCase")]
-pub enum VideoType {
-    Screen,
-    Output,
-    Camera,
-}
-
-#[derive(Serialize, Deserialize, specta::Type, Debug)]
-pub enum UploadResult {
-    Success(String),
-    NotAuthenticated,
-    PlanCheckFailed,
-    UpgradeRequired,
-}
-
-#[derive(Serialize, Deserialize, specta::Type, Debug)]
-pub struct VideoRecordingMetadata {
-    pub duration: f64,
-    pub size: f64,
-}
-
-const CAMERA_PREVIEW_ERROR_EVENT: &str = "camera-preview-error";
-const CAMERA_PREVIEW_CLEAR_EVENT: &str = "camera-preview-clear";
-
-#[derive(Clone, Serialize)]
-#[serde(rename_all = "camelCase")]
-struct CameraPreviewErrorPayload {
-    title: String,
-    message: String,
-}
-
-fn camera_preview_error_message(err: &str) -> String {
-    if err.contains("DeviceNotFound") {
-        return "This camera is no longer available. Check that it is connected and allowed by system permissions.".to_string();
-    }
-
-    if err.contains("CameraTimeout") {
-        return "No frames were received from this camera. It may be closed, disconnected, covered, or in use by another app.".to_string();
-    }
-
-    if err.contains("StartCapturing") {
-        return "The system could not start this camera. It may be unavailable or in use by another app.".to_string();
-    }
-
-    if err.contains("InvalidFormat") {
-        return "This camera did not report a usable capture format.".to_string();
-    }
-
-    "The selected camera could not be started. Choose another camera or reconnect this one."
-        .to_string()
-}
-
-fn emit_camera_preview_error(app_handle: &AppHandle, message: String) {
-    let _ = app_handle.emit(
-        CAMERA_PREVIEW_ERROR_EVENT,
-        CameraPreviewErrorPayload {
-            title: "Camera unavailable".to_string(),
-            message,
-        },
-    );
-}
-
-fn emit_camera_preview_clear(app_handle: &AppHandle) {
-    let _ = app_handle.emit(CAMERA_PREVIEW_CLEAR_EVENT, ());
-}
-
-async fn add_camera_preview_ws_sender(
-    camera_feed: &ActorRef,
-    sender: flume::Sender,
-) {
-    add_camera_preview_sender(camera_feed, sender, "WebSocket").await;
-}
-
-async fn add_camera_preview_sender(
-    camera_feed: &ActorRef,
-    sender: flume::Sender,
-    label: &str,
-) {
-    let result = camera_feed.ask(feeds::camera::AddSender(sender)).await;
-    if let Err(err) = result {
-        warn!(error = %err, "Failed to add {label} camera sender");
-    }
-}
-
-async fn remove_camera_preview_sender(
-    camera_feed: &ActorRef,
-    sender: flume::Sender,
-    label: &str,
-) {
-    let result = camera_feed.ask(feeds::camera::RemoveSender(sender)).await;
-    if let Err(err) = result {
-        warn!(error = %err, "Failed to remove {label} camera sender");
-    }
-}
-
-async fn sync_camera_preview_sender(
-    camera_feed: &ActorRef,
-    camera_ws_sender: flume::Sender,
-    camera_preview_sender: Option,
-    use_ws_preview: bool,
-) {
-    if use_ws_preview {
-        if let Some(sender) = camera_preview_sender
-            && let Err(err) = sender.detach(camera_feed).await
-        {
-            warn!(error = %err, "Failed to remove native preview camera sender");
-        }
-
-        add_camera_preview_ws_sender(camera_feed, camera_ws_sender).await;
-    } else if let Some(sender) = camera_preview_sender {
-        if let Err(err) = sender.attach(camera_feed).await {
-            warn!(error = %err, "Failed to add native preview camera sender");
-        }
-        remove_camera_preview_sender(camera_feed, camera_ws_sender, "WebSocket").await;
-    } else {
-        add_camera_preview_ws_sender(camera_feed, camera_ws_sender).await;
-    }
-}
-
-impl App {
-    pub fn set_pending_recording(
-        &mut self,
-        mode: RecordingMode,
-        target: ScreenCaptureTarget,
-    ) -> Result<(), String> {
-        recording_start_allowed(
-            self.handle
-                .try_state::()
-                .is_some_and(|state| state.exit_pending()),
-            updates::recording_start_blocked(&self.handle),
-        )?;
-        #[cfg(target_os = "linux")]
-        if mode != RecordingMode::Instant
-            && recording::linux_instant::current(&self.handle).is_some()
-        {
-            return Err("Finish the pending Instant cleanup before recording".into());
-        }
-        if !matches!(self.recording_state, RecordingState::None) {
-            return Err("Recording already in progress".to_string());
-        }
-
-        self.recording_state = RecordingState::Pending { mode, target };
-        CurrentRecordingChanged.emit(&self.handle).ok();
-
-        Ok(())
-    }
-
-    pub fn set_current_recording(&mut self, actor: InProgressRecording) {
-        self.recording_state = RecordingState::Active(actor);
-        CurrentRecordingChanged.emit(&self.handle).ok();
-    }
-
-    pub fn clear_pending_recording(&mut self) -> bool {
-        #[cfg(target_os = "linux")]
-        if recording::linux_instant::blocks_cleanup(&self.handle) {
-            return false;
-        }
-        if !matches!(self.recording_state, RecordingState::Pending { .. }) {
-            return false;
-        }
-
-        self.recording_state = RecordingState::None;
-        self.was_camera_only_recording = false;
-        self.close_occluder_windows();
-        crate::windows::apply_content_protection(&self.handle, false);
-        if let Some(camera) = CapWindowId::Camera.get(&self.handle) {
-            let _ = camera.set_content_protected(false);
-        }
-        CurrentRecordingChanged.emit(&self.handle).ok();
-
-        true
-    }
-
-    pub fn clear_current_recording(&mut self) -> Option {
-        #[cfg(target_os = "linux")]
-        if recording::linux_instant::blocks_cleanup(&self.handle) {
-            return None;
-        }
-        let previous = std::mem::replace(&mut self.recording_state, RecordingState::None);
-        match previous {
-            RecordingState::Active(recording) => {
-                self.close_occluder_windows();
-                crate::windows::apply_content_protection(&self.handle, false);
-                Some(recording)
-            }
-            state => {
-                self.recording_state = state;
-                None
-            }
-        }
-    }
-
-    pub fn clear_recording_state(&mut self) -> Option {
-        #[cfg(target_os = "linux")]
-        if recording::linux_instant::blocks_cleanup(&self.handle) {
-            return None;
-        }
-        let previous = std::mem::replace(&mut self.recording_state, RecordingState::None);
-        self.close_occluder_windows();
-        crate::windows::apply_content_protection(&self.handle, false);
-        match previous {
-            RecordingState::Active(recording) => Some(recording),
-            _ => None,
-        }
-    }
-
-    fn close_occluder_windows(&self) {
-        for window in self.handle.webview_windows() {
-            if window.0.starts_with("window-capture-occluder-") {
-                let _ = window.1.close();
-            }
-        }
-    }
-
-    fn microphone_settings_for_label(
-        &self,
-        label: &str,
-    ) -> Option {
-        recording_settings::RecordingSettingsStore::microphone_settings_for(&self.handle, label)
-    }
-
-    fn camera_settings_for_id(
-        &self,
-        id: &DeviceOrModelID,
-    ) -> Option {
-        recording_settings::RecordingSettingsStore::camera_settings_for(&self.handle, id)
-    }
-
-    async fn restart_mic_feed(&mut self) -> Result<(), String> {
-        self.applied_mic_input.invalidate();
-        info!("Restarting microphone feed after actor shutdown");
-
-        let (error_tx, error_rx) = flume::bounded(1);
-        let mic_feed = MicrophoneFeed::spawn(MicrophoneFeed::new(error_tx));
-
-        spawn_mic_error_handler(self.handle.clone(), error_rx);
-
-        mic_feed
-            .ask(microphone::AddSender(self.mic_meter_sender.clone()))
-            .await
-            .map_err(|e| e.to_string())?;
-
-        if let Some(label) = self.selected_mic_label.clone()
-            && permissions::check_microphone_access().is_ok()
-        {
-            let settings = self.microphone_settings_for_label(&label);
-            match mic_feed.ask(microphone::SetInput { label, settings }).await {
-                Ok(ready) => {
-                    if let Err(err) = ready.await {
-                        if matches!(err, microphone::SetInputError::DeviceNotFound) {
-                            warn!("Selected microphone not available while restarting feed");
-                        } else {
-                            return Err(err.to_string());
-                        }
-                    }
-                }
-                Err(kameo::error::SendError::HandlerError(
-                    microphone::SetInputError::DeviceNotFound,
-                )) => {
-                    warn!("Selected microphone not available while restarting feed");
-                }
-                Err(err) => return Err(err.to_string()),
-            }
-        }
-
-        self.mic_feed = mic_feed;
-
-        Ok(())
-    }
-
-    async fn ensure_mic_feed_alive(&mut self) -> Result<(), String> {
-        if self.mic_feed.is_alive() {
-            return Ok(());
-        }
-
-        self.restart_mic_feed().await
-    }
-
-    async fn add_recording_logging_handle(&mut self, path: &PathBuf) -> Result<(), String> {
-        let logfile =
-            std::fs::File::create(path).map_err(|e| format!("Failed to create logfile: {e}"))?;
-
-        self.recording_logging_handle
-            .reload(Some(Box::new(
-                tracing_subscriber::fmt::layer()
-                    .with_ansi(false)
-                    .with_target(true)
-                    .with_writer(logfile),
-            ) as DynLoggingLayer))
-            .map_err(|e| format!("Failed to reload logging layer: {e}"))?;
-
-        Ok(())
-    }
-
-    pub fn current_recording(&self) -> Option<&InProgressRecording> {
-        match &self.recording_state {
-            RecordingState::Active(recording) => Some(recording),
-            _ => None,
-        }
-    }
-
-    pub fn current_recording_mut(&mut self) -> Option<&mut InProgressRecording> {
-        match &mut self.recording_state {
-            RecordingState::Active(recording) => Some(recording),
-            _ => None,
-        }
-    }
-
-    pub fn is_recording_active_or_pending(&self) -> bool {
-        !matches!(self.recording_state, RecordingState::None)
-            || clean_capture::blocks_idle_cleanup(&self.handle)
-    }
-
-    async fn handle_input_disconnect(&mut self, kind: RecordingInputKind) -> Result<(), String> {
-        if matches!(kind, RecordingInputKind::Microphone) {
-            self.applied_mic_input.invalidate();
-        }
-        if !self.disconnected_inputs.insert(kind) {
-            return Ok(());
-        }
-
-        let (title, body) = match kind {
-            RecordingInputKind::Microphone => (
-                "Microphone disconnected",
-                "Recording continues. Silence will be used until the microphone reconnects.",
-            ),
-            RecordingInputKind::Camera => (
-                "Camera disconnected",
-                "Recording continues without camera. Camera overlay will resume when the device reconnects.",
-            ),
-        };
-
-        let _ = NewNotification {
-            title: title.to_string(),
-            body: body.to_string(),
-            is_error: false,
-        }
-        .emit(&self.handle);
-
-        let _ = RecordingEvent::InputLost { input: kind }.emit(&self.handle);
-
-        Ok(())
-    }
-
-    async fn handle_input_restored(&mut self, kind: RecordingInputKind) -> Result<(), String> {
-        let app_handle = self.handle.clone();
-        let requested = app_handle.state::();
-        let camera_snapshot = requested.snapshot().camera;
-        if matches!(kind, RecordingInputKind::Camera)
-            && (self.selected_camera_id.is_none()
-                || camera_snapshot.pending
-                || camera_snapshot.value != self.selected_camera_id)
-        {
-            return Ok(());
-        }
-        let camera_revision = camera_snapshot.revision;
-        let pending = match kind {
-            RecordingInputKind::Microphone => self.disconnected_inputs.remove(&kind),
-            RecordingInputKind::Camera => self.disconnected_inputs.contains(&kind),
-        };
-        if !pending {
-            return Ok(());
-        }
-
-        match kind {
-            RecordingInputKind::Microphone => {
-                if let Err(error) = self.ensure_selected_mic_ready().await {
-                    warn!(%error, "Failed to restore microphone; will retry when access and the device are available");
-                    self.disconnected_inputs
-                        .insert(RecordingInputKind::Microphone);
-                    return Ok(());
-                }
-            }
-            RecordingInputKind::Camera => match self.ensure_selected_camera_ready().await {
-                Ok(()) => {
-                    if !requested.publish_camera_if_current(camera_revision, || {
-                        self.disconnected_inputs.remove(&RecordingInputKind::Camera);
-                        info!("Camera reconnected and reinitialized successfully");
-                        let _ = NewNotification {
-                            title: "Camera reconnected".to_string(),
-                            body: "Camera overlay has been restored.".to_string(),
-                            is_error: false,
-                        }
-                        .emit(&self.handle);
-                    }) {
-                        return Ok(());
-                    }
-                }
-                Err(e) => {
-                    warn!(error = %e, "Failed to reinitialize camera after reconnect, will retry on next poll");
-                    return Ok(());
-                }
-            },
-        }
-
-        if matches!(kind, RecordingInputKind::Camera) {
-            requested.publish_camera_if_current(camera_revision, || {
-                let _ = RecordingEvent::InputRestored { input: kind }.emit(&self.handle);
-            });
-        } else {
-            let _ = RecordingEvent::InputRestored { input: kind }.emit(&self.handle);
-        }
-
-        Ok(())
-    }
-
-    async fn ensure_selected_mic_ready(&mut self) -> Result<(), String> {
-        check_requested_microphone_permission(
-            self.selected_mic_label.as_deref(),
-            permissions::check_microphone_access,
-        )?;
-        self.applied_mic_input.invalidate();
-        self.ensure_mic_feed_alive().await?;
-
-        if let Some(label) = self.selected_mic_label.clone() {
-            let settings = self.microphone_settings_for_label(&label);
-            let ready = self
-                .mic_feed
-                .ask(feeds::microphone::SetInput { label, settings })
-                .await
-                .map_err(|e| e.to_string())?;
-
-            ready.await.map_err(|e| e.to_string())?;
-        }
-
-        Ok(())
-    }
-
-    async fn ensure_selected_camera_ready(&mut self) -> Result<(), String> {
-        let app_handle = self.handle.clone();
-        let requested = app_handle.state::();
-        let snapshot = requested.snapshot();
-        if snapshot.camera.pending || snapshot.camera.value != self.selected_camera_id {
-            return Err("Camera selection was superseded by a newer request".into());
-        }
-        check_requested_camera_permission(
-            self.selected_camera_id.as_ref(),
-            permissions::check_camera_access,
-        )?;
-        if let Some(id) = self.selected_camera_id.clone() {
-            let settings = self.camera_settings_for_id(&id);
-            let ready = self
-                .camera_feed
-                .ask(feeds::camera::SetInput {
-                    id: id.clone(),
-                    settings,
-                })
-                .await
-                .map_err(|e| e.to_string())?;
-
-            await_current_camera_request(async { ready.await.map_err(|e| e.to_string()) }, || {
-                requested.camera_is_current(snapshot.camera.revision)
-            })
-            .await??;
-        }
-
-        Ok(())
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app_handle, state))]
-async fn set_mic_input(
-    app_handle: AppHandle,
-    state: MutableState<'_, App>,
-    label: Option,
-) -> Result<(), String> {
-    let requested = app_handle.state::();
-    let settings = label.as_ref().and_then(|label| {
-        recording_settings::RecordingSettingsStore::microphone_settings_for(&app_handle, label)
-    });
-    let (revision, joined) = {
-        let state = state.read().await;
-        requested.inner.lock().unwrap().microphone.begin_or_join(
-            label.clone(),
-            serde_json::json!(settings),
-            matches!(state.recording_state, RecordingState::Pending { .. }),
-        )
-    };
-    if joined {
-        return wait_for_existing_input(revision, "Microphone", || {
-            requested.inner.lock().unwrap().microphone.clone()
-        })
-        .await;
-    }
-    let result = async {
-        check_requested_microphone_permission(
-            label.as_deref(),
-            permissions::check_microphone_access,
-        )?;
-        let _operation = requested.operation.lock().await;
-        if !requested.mic_is_current(revision) {
-            return Err("Microphone selection was superseded by a newer request".into());
-        }
-        apply_mic_input(&app_handle, state, label, revision).await
-    }
-    .await;
-    requested
-        .inner
-        .lock()
-        .unwrap()
-        .microphone
-        .finish(revision, &result);
-    result
-}
-
-fn check_requested_microphone_permission(
-    label: Option<&str>,
-    check: impl FnOnce() -> Result<(), String>,
-) -> Result<(), String> {
-    if label.is_some() {
-        check()?;
-    }
-    Ok(())
-}
-
-async fn finish_microphone_input_change(
-    change: impl std::future::Future>,
-    is_current: impl FnOnce() -> bool,
-    attach: impl std::future::Future>,
-) -> Result<(), String> {
-    change.await?;
-    if !is_current() {
-        return Err("Microphone selection was superseded by a newer request".into());
-    }
-    attach.await
-}
-
-const MICROPHONE_UNLOCK_TIMEOUT: Duration = Duration::from_millis(500);
-const MICROPHONE_UNLOCK_RETRY: Duration = Duration::from_millis(50);
-const MICROPHONE_CHANGE_TIMEOUT: Duration =
-    microphone::SETUP_TIMEOUT.saturating_add(Duration::from_secs(1));
-
-async fn wait_for_microphone_setup(
-    setup: impl std::future::Future>,
-) -> Result<(), String> {
-    tokio::time::timeout(MICROPHONE_CHANGE_TIMEOUT, setup)
-        .await
-        .map_err(|_| {
-            "Timed out configuring the requested microphone. Select it again before recording."
-                .to_string()
-        })?
-}
-
-enum MicrophoneRemovalError {
-    Locked,
-    Failed(String),
-}
-
-async fn wait_for_microphone_removal(mut remove: impl FnMut() -> F) -> Result<(), String>
-where
-    F: std::future::Future>,
-{
-    let deadline = tokio::time::Instant::now() + MICROPHONE_UNLOCK_TIMEOUT;
-    loop {
-        if tokio::time::Instant::now() >= deadline {
-            return Err("The microphone is still in use. Stop recording and try again.".into());
-        }
-        match tokio::time::timeout_at(deadline, remove()).await {
-            Ok(Ok(())) => return Ok(()),
-            Ok(Err(MicrophoneRemovalError::Failed(error))) => return Err(error),
-            Ok(Err(MicrophoneRemovalError::Locked)) => {}
-            Err(_) => {
-                return Err(
-                    "Timed out waiting for the microphone to close. Stop recording and try again."
-                        .into(),
-                );
-            }
-        }
-        let remaining = deadline.saturating_duration_since(tokio::time::Instant::now());
-        if remaining.is_zero() {
-            return Err("The microphone is still in use. Stop recording and try again.".into());
-        }
-        tokio::time::sleep(remaining.min(MICROPHONE_UNLOCK_RETRY)).await;
-    }
-}
-
-async fn remove_microphone_input(feed: &ActorRef) -> Result<(), String> {
-    wait_for_microphone_removal(|| async {
-        match feed.ask(microphone::RemoveInput).await {
-            Ok(()) => Ok(()),
-            Err(kameo::error::SendError::HandlerError(microphone::FeedLockedError)) => {
-                Err(MicrophoneRemovalError::Locked)
-            }
-            Err(error) => Err(MicrophoneRemovalError::Failed(error.to_string())),
-        }
-    })
-    .await
-}
-
-async fn acknowledge_studio_microphone(
-    acknowledgement: impl std::future::Future>,
-    update_ownership: impl std::future::Future>,
-    action: &str,
-) -> Result<(), String> {
-    tokio::time::timeout(MICROPHONE_UNLOCK_TIMEOUT, acknowledgement)
-        .await
-        .map_err(|_| {
-            format!("Timed out {action} the Studio microphone. Stop recording and try again.")
-        })??;
-    update_ownership.await
-}
-
-fn replace_owned_microphone(
-    owner: &std::path::Path,
-    current: Option<(&std::path::Path, &mut Option)>,
-    replacement: Option,
-) -> Result<(), String> {
-    let Some((current_owner, slot)) = current else {
-        return Err("The Studio recording stopped while changing microphone input.".into());
-    };
-    if current_owner != owner {
-        return Err("The Studio recording changed while changing microphone input.".into());
-    }
-    *slot = replacement;
-    Ok(())
-}
-
-fn studio_microphone_owner_matches(app: &App, owner: &std::path::Path) -> bool {
-    matches!(app.current_recording(), Some(InProgressRecording::Studio { common, .. })
-        if common.recording_dir == owner)
-}
-
-fn replace_studio_microphone(
-    app: &mut App,
-    owner: &std::path::Path,
-    replacement: Option>,
-) -> Result<(), String> {
-    let current = match app.current_recording_mut() {
-        Some(InProgressRecording::Studio {
-            common, mic_feed, ..
-        }) => Some((common.recording_dir.as_path(), mic_feed)),
-        _ => None,
-    };
-    replace_owned_microphone(owner, current, replacement)
-}
-
-async fn apply_mic_input(
-    app_handle: &AppHandle,
-    state: MutableState<'_, App>,
-    desired_label: Option,
-    revision: u64,
-) -> Result<(), String> {
-    let requested = app_handle.state::();
-    check_requested_microphone_permission(
-        desired_label.as_deref(),
-        permissions::check_microphone_access,
-    )?;
-
-    let settings = desired_label.as_ref().and_then(|label| {
-        recording_settings::RecordingSettingsStore::microphone_settings_for(app_handle, label)
-    });
-    let reusable = {
-        let app = state.read().await;
-        (!matches!(app.recording_state, RecordingState::Active(_))
-            && app.applied_mic_input.valid
-            && app.applied_mic_input.settings == settings
-            && app.selected_mic_label == desired_label)
-            .then(|| (app.mic_feed.clone(), app.applied_mic_input.generation))
-    };
-    if let Some((feed, generation)) = reusable
-        && let Some(label) = &desired_label
-        && MicrophoneFeed::list_names().contains(label)
-        && feed
-            .ask(microphone::CheckInput(label.clone()))
-            .await
-            .unwrap_or(false)
-    {
-        let app = state.read().await;
-        if requested.mic_is_current(revision)
-            && app.applied_mic_input.valid
-            && app.applied_mic_input.generation == generation
-        {
-            return Ok(());
-        }
-    }
-
-    let (mic_feed, studio_handle, applied_generation) = {
-        let mut app = state.write().await;
-        if !requested.mic_is_current(revision) {
-            return Err("Microphone selection was superseded by a newer request".into());
-        }
-        app.ensure_mic_feed_alive().await?;
-        let selected_label = app.selected_mic_label.clone();
-        let active = matches!(app.recording_state, RecordingState::Active(_));
-        let needs_change = app.applied_mic_input.prepare_change(
-            active,
-            desired_label.as_deref(),
-            selected_label.as_deref(),
-        );
-
-        if let Some(label) = desired_label.as_ref()
-            && !MicrophoneFeed::list_names().contains(label)
-        {
-            app.applied_mic_input.invalidate();
-            return Err(format!(
-                "Selected microphone '{label}' is no longer available. Reconnect it or choose another microphone."
-            ));
-        }
-        if !needs_change {
-            return Ok(());
-        }
-
-        let handle = match app.current_recording() {
-            Some(InProgressRecording::Studio { handle, common, .. }) => {
-                Some((handle.clone(), common.recording_dir.clone()))
-            }
-            _ => None,
-        };
-
-        (
-            app.mic_feed.clone(),
-            handle,
-            app.applied_mic_input.generation,
-        )
-    };
-
-    let change = async {
-        if let Some((handle, owner)) = &studio_handle {
-            acknowledge_studio_microphone(
-                async {
-                    handle
-                        .set_mic_feed(None)
-                        .await
-                        .map_err(|error| error.to_string())
-                },
-                async {
-                    let mut app = state.write().await;
-                    replace_studio_microphone(&mut app, owner, None)
-                },
-                "detaching",
-            )
-            .await?;
-            remove_microphone_input(&mic_feed).await?;
-        }
-
-        match desired_label.as_ref() {
-            None if studio_handle.is_none() => remove_microphone_input(&mic_feed).await?,
-            None => {}
-            Some(label) => {
-                if let Some((_, owner)) = &studio_handle
-                    && !studio_microphone_owner_matches(&*state.read().await, owner)
-                {
-                    return Err(
-                        "The Studio recording stopped while changing microphone input.".into(),
-                    );
-                }
-                wait_for_microphone_setup(async {
-                    mic_feed
-                        .ask(feeds::microphone::SetInput {
-                            label: label.clone(),
-                            settings,
-                        })
-                        .await
-                        .map_err(|error| error.to_string())?
-                        .await
-                        .map(drop)
-                        .map_err(|error| error.to_string())
-                })
-                .await?;
-            }
-        }
-
-        Ok(())
-    };
-    let attach = async {
-        if let Some((handle, owner)) = &studio_handle
-            && let Some(label) = desired_label.as_ref()
-        {
-            let mic_lock =
-                tokio::time::timeout(MICROPHONE_UNLOCK_TIMEOUT, mic_feed.ask(microphone::Lock))
-                    .await
-                    .map_err(|_| "Timed out locking the requested microphone.".to_string())?
-                    .map_err(|error| error.to_string())?;
-            if mic_lock.device_name() != label {
-                return Err(
-                    "Microphone input changed before Studio could attach it. Select it again."
-                        .into(),
-                );
-            }
-            let mic_lock = Arc::new(mic_lock);
-            acknowledge_studio_microphone(
-                async {
-                    handle
-                        .set_mic_feed(Some(mic_lock.clone()))
-                        .await
-                        .map_err(|error| error.to_string())
-                },
-                async {
-                    let mut app = state.write().await;
-                    replace_studio_microphone(&mut app, owner, Some(mic_lock.clone()))
-                },
-                "attaching",
-            )
-            .await?;
-        }
-
-        Ok(())
-    };
-    let apply_result =
-        finish_microphone_input_change(change, || requested.mic_is_current(revision), attach).await;
-
-    if let Some((_, owner)) = &studio_handle
-        && !studio_microphone_owner_matches(&*state.read().await, owner)
-    {
-        remove_microphone_input(&mic_feed).await?;
-        return Err("The Studio recording stopped while changing microphone input.".into());
-    }
-
-    match apply_result {
-        Ok(()) => {
-            let mut app = state.write().await;
-            if let Some((_, owner)) = &studio_handle
-                && !studio_microphone_owner_matches(&app, owner)
-            {
-                drop(app);
-                remove_microphone_input(&mic_feed).await?;
-                return Err("The Studio recording stopped while changing microphone input.".into());
-            }
-            let mut cleared = false;
-            let mut confirmed = false;
-            if !requested.publish_mic_if_current(revision, || {
-                if !app.applied_mic_input.confirm_if_current(applied_generation) {
-                    return;
-                }
-                confirmed = true;
-                app.applied_mic_input.settings = settings;
-                app.selected_mic_label = desired_label;
-                cleared = app
-                    .disconnected_inputs
-                    .remove(&RecordingInputKind::Microphone);
-            }) {
-                return Err("Microphone selection was superseded by a newer request".into());
-            }
-
-            if !confirmed {
-                return Err("Microphone changed or disconnected during setup. Select it again before recording.".into());
-            }
-            if cleared {
-                let _ = RecordingEvent::InputRestored {
-                    input: RecordingInputKind::Microphone,
-                }
-                .emit(&app.handle);
-            }
-
-            Ok(())
-        }
-        Err(err) => Err(err),
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-async fn upload_logs(app_handle: AppHandle) -> Result<(), String> {
-    logging::upload_log_file(&app_handle).await
-}
-
-#[tauri::command]
-#[specta::specta]
-fn get_system_diagnostics() -> cap_recording::diagnostics::SystemDiagnostics {
-    cap_recording::diagnostics::collect_diagnostics()
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app_handle, state))]
-#[allow(unused_mut)]
-async fn set_camera_input(
-    app_handle: AppHandle,
-    state: MutableState<'_, App>,
-    id: Option,
-    skip_camera_window: Option,
-) -> Result<(), String> {
-    let requested = app_handle.state::();
-    let settings = id.as_ref().and_then(|id| {
-        recording_settings::RecordingSettingsStore::camera_settings_for(&app_handle, id)
-    });
-    let (revision, joined) = {
-        let state = state.read().await;
-        requested.inner.lock().unwrap().camera.begin_or_join(
-            id.clone(),
-            serde_json::json!((settings, skip_camera_window.unwrap_or(false))),
-            matches!(state.recording_state, RecordingState::Pending { .. }),
-        )
-    };
-    if joined {
-        return wait_for_existing_input(revision, "Camera", || {
-            requested.inner.lock().unwrap().camera.clone()
-        })
-        .await;
-    }
-    let result = async {
-        check_requested_camera_permission(id.as_ref(), permissions::check_camera_access)?;
-        let _operation = requested.operation.lock().await;
-        if !requested.camera_is_current(revision) {
-            return Err("Camera selection was superseded by a newer request".into());
-        }
-        apply_camera_input(&app_handle, state, id, skip_camera_window, revision).await
-    }
-    .await;
-    requested
-        .inner
-        .lock()
-        .unwrap()
-        .camera
-        .finish(revision, &result);
-    result
-}
-
-fn check_requested_camera_permission(
-    id: Option<&DeviceOrModelID>,
-    check: impl FnOnce() -> Result<(), String>,
-) -> Result<(), String> {
-    if id.is_some() {
-        check()?;
-    }
-    Ok(())
-}
-
-async fn await_current_camera_request(
-    request: impl std::future::Future,
-    is_current: impl FnOnce() -> bool,
-) -> Result {
-    let result = request.await;
-    if !is_current() {
-        return Err("Camera selection was superseded by a newer request".into());
-    }
-    Ok(result)
-}
-
-async fn apply_camera_input(
-    app_handle: &AppHandle,
-    state: MutableState<'_, App>,
-    id: Option,
-    skip_camera_window: Option,
-    revision: u64,
-) -> Result<(), String> {
-    check_requested_camera_permission(id.as_ref(), permissions::check_camera_access)?;
-    let requested = app_handle.state::();
-    let operation_lock = app_handle.state::();
-    let _operation_guard = operation_lock.lock().await;
-    if !requested.camera_is_current(revision) {
-        return Err("Camera selection was superseded by a newer request".into());
-    }
-    let app = state.read().await;
-    let camera_feed = app.camera_feed.clone();
-    let studio_handle = match app.current_recording() {
-        Some(InProgressRecording::Studio { handle, .. }) => Some(handle.clone()),
-        _ => None,
-    };
-    let current_id = app.selected_camera_id.clone();
-    let camera_in_use = app.camera_in_use;
-    let recording_active = matches!(app.recording_state, RecordingState::Active(_));
-    drop(app);
-    if !requested.camera_is_current(revision) {
-        return Err("Camera selection was superseded by a newer request".into());
-    }
-
-    let skip_camera_window = skip_camera_window.unwrap_or(false);
-    let camera_window_is_visible = CapWindowId::Camera
-        .get(app_handle)
-        .and_then(|window| window.is_visible().ok())
-        .unwrap_or(false);
-
-    if id == current_id && camera_in_use && recording_active && !skip_camera_window {
-        let show_result = if camera_window_is_visible {
-            Ok(())
-        } else {
-            show_requested_camera_window(app_handle, revision).await
-        };
-
-        show_result
-            .map_err(|err| error!("Failed to show camera preview window: {err}"))
-            .ok();
-
-        return Ok(());
-    }
-
-    if let Some(id) = &id
-        && !is_camera_available(id)
-    {
-        return Err(format!(
-            "Selected camera '{}' is no longer available. Reconnect it or choose another camera.",
-            recording::camera_id_label(id)
-        ));
-    }
-
-    let settings = id.as_ref().and_then(|id| {
-        recording_settings::RecordingSettingsStore::camera_settings_for(app_handle, id)
-    });
-    if !recording_active
-        && !skip_camera_window
-        && camera_in_use
-        && id == current_id
-        && let Some(id) = &id
-        && camera_feed
-            .ask(feeds::camera::CheckInput {
-                id: id.clone(),
-                settings,
-            })
-            .await
-            .unwrap_or(false)
-    {
-        if !requested.camera_is_current(revision) {
-            return Err("Camera selection was superseded by a newer request".into());
-        }
-        if !camera_window_is_visible {
-            show_requested_camera_window(app_handle, revision).await?;
-        }
-        return Ok(());
-    }
-
-    if let Some(handle) = &studio_handle {
-        handle
-            .set_camera_feed(None)
-            .await
-            .map_err(|e| e.to_string())?;
-    }
-
-    match &id {
-        None => {
-            let shutdown_rx = {
-                let app = &mut *state.write().await;
-                let mut shutdown_rx = None;
-                if !requested.publish_camera_if_current(revision, || {
-                    app.camera_in_use = false;
-                    app.camera_cleanup_done = true;
-                    if skip_camera_window {
-                        shutdown_rx = app.camera_preview.begin_shutdown();
-                    } else {
-                        app.camera_preview.pause();
-                    }
-                }) {
-                    return Err("Camera selection was superseded by a newer request".into());
-                }
-                shutdown_rx
-            };
-
-            camera_feed
-                .ask(feeds::camera::RemoveInput)
-                .await
-                .map_err(|e| e.to_string())?;
-
-            if let Some(rx) = shutdown_rx {
-                let _ = tokio::time::timeout(Duration::from_millis(500), rx).await;
-            }
-
-            if !skip_camera_window && let Some(window) = CapWindowId::Camera.get(app_handle) {
-                let _ = window.hide();
-            }
-        }
-        Some(id) => {
-            if !requested.publish_camera_if_current(revision, || {
-                emit_camera_preview_clear(app_handle);
-            }) {
-                return Err("Camera selection was superseded by a newer request".into());
-            }
-            let (camera_ws_sender, camera_preview_sender, use_ws_preview) = {
-                let app = &mut *state.write().await;
-                let use_ws_preview = !(camera_window_is_visible
-                    && app.camera_preview.is_initialized()
-                    && !app.camera_preview.is_paused());
-                if !requested.publish_camera_if_current(revision, || {
-                    app.camera_in_use = true;
-                    app.camera_cleanup_done = false;
-                }) {
-                    return Err("Camera selection was superseded by a newer request".into());
-                }
-                #[allow(deprecated)]
-                (
-                    app.camera_ws_sender.clone(),
-                    app.camera_preview.sender(),
-                    use_ws_preview,
-                )
-            };
-
-            sync_camera_preview_sender(
-                &camera_feed,
-                camera_ws_sender,
-                camera_preview_sender,
-                use_ws_preview,
-            )
-            .await;
-
-            let mut showed_camera_window = skip_camera_window;
-            let mut attempts = 0;
-            let init_result: Result<(), String> = loop {
-                if !requested.camera_is_current(revision) {
-                    return Err("Camera selection was superseded by a newer request".into());
-                }
-                attempts += 1;
-
-                let request = camera_feed
-                    .ask(feeds::camera::SetInput {
-                        id: id.clone(),
-                        settings,
-                    })
-                    .await
-                    .map_err(|e| e.to_string());
-
-                if !requested.camera_is_current(revision) {
-                    return Err("Camera selection was superseded by a newer request".into());
-                }
-                if !showed_camera_window {
-                    showed_camera_window = true;
-                    let show_result = show_requested_camera_window(app_handle, revision).await;
-                    show_result
-                        .map_err(|err| error!("Failed to show camera preview window: {err}"))
-                        .ok();
-                }
-
-                let result = await_current_camera_request(
-                    async {
-                        match request {
-                            Ok(future) => future.await.map_err(|e| e.to_string()),
-                            Err(e) => Err(e),
-                        }
-                    },
-                    || requested.camera_is_current(revision),
-                )
-                .await?;
-
-                match result {
-                    Ok(_) => {
-                        if !requested.publish_camera_if_current(revision, || {
-                            emit_camera_preview_clear(app_handle);
-                        }) {
-                            return Err("Camera selection was superseded by a newer request".into());
-                        }
-                        break Ok(());
-                    }
-                    Err(e) => {
-                        if attempts == 1
-                            && !skip_camera_window
-                            && !requested.publish_camera_if_current(revision, || {
-                                emit_camera_preview_error(
-                                    app_handle,
-                                    camera_preview_error_message(&e),
-                                );
-                            })
-                        {
-                            return Err("Camera selection was superseded by a newer request".into());
-                        }
-                        if attempts >= 3 {
-                            break Err(format!(
-                                "Failed to initialize camera after {attempts} attempts: {e}"
-                            ));
-                        }
-                        debug!(
-                            "Failed to set camera input (attempt {}): {}. Retrying...",
-                            attempts, e
-                        );
-                        await_current_camera_request(
-                            tokio::time::sleep(Duration::from_millis(500)),
-                            || requested.camera_is_current(revision),
-                        )
-                        .await?;
-                    }
-                }
-            };
-
-            if !requested.camera_is_current(revision) {
-                return Err("Camera selection was superseded by a newer request".into());
-            }
-            if let Err(e) = init_result {
-                let message = camera_preview_error_message(&e);
-                let _ = camera_feed.ask(feeds::camera::RemoveInput).await;
-                let app = &mut *state.write().await;
-                if !requested.publish_camera_if_current(revision, || {
-                    app.camera_in_use = false;
-                    if app.disconnected_inputs.insert(RecordingInputKind::Camera) {
-                        let _ = RecordingEvent::InputLost {
-                            input: RecordingInputKind::Camera,
-                        }
-                        .emit(app_handle);
-                    }
-                    emit_camera_preview_error(app_handle, message.clone());
-                    let _ = NewNotification {
-                        title: "Camera unavailable".to_string(),
-                        body: message,
-                        is_error: true,
-                    }
-                    .emit(app_handle);
-                }) {
-                    return Err("Camera selection was superseded by a newer request".into());
-                }
-                return Err(e);
-            }
-        }
-    }
-
-    if !requested.camera_is_current(revision) {
-        return Err("Camera selection was superseded by a newer request".into());
-    }
-    if let Some(handle) = studio_handle
-        && id.is_some()
-    {
-        let camera_lock = camera_feed
-            .ask(feeds::camera::Lock)
-            .await
-            .map_err(|e| e.to_string())?;
-        handle
-            .set_camera_feed(Some(Arc::new(camera_lock)))
-            .await
-            .map_err(|e| e.to_string())?;
-    }
-
-    {
-        let app = &mut *state.write().await;
-        let mut cleared = false;
-        if !requested.publish_camera_if_current(revision, || {
-            app.selected_camera_id = id;
-            app.camera_in_use = app.selected_camera_id.is_some();
-            app.camera_cleanup_done = !app.camera_in_use;
-            cleared = app.disconnected_inputs.remove(&RecordingInputKind::Camera);
-        }) {
-            return Err("Camera selection was superseded by a newer request".into());
-        }
-
-        if cleared {
-            let _ = RecordingEvent::InputRestored {
-                input: RecordingInputKind::Camera,
-            }
-            .emit(&app.handle);
-        }
-    }
-
-    Ok(())
-}
-
-async fn show_requested_camera_window(app: &AppHandle, revision: u64) -> Result<(), String> {
-    let requested = app.state::();
-    if !requested.camera_is_current(revision) {
-        return Err("Camera selection was superseded by a newer request".into());
-    }
-    let result = ShowCapWindow::Camera { centered: false }.show(app).await;
-    if !requested.camera_is_current(revision) {
-        if let Some(window) = CapWindowId::Camera.get(app) {
-            let _ = window.hide();
-        }
-        return Err("Camera selection was superseded by a newer request".into());
-    }
-    result.map(|_| ()).map_err(|error| error.to_string())
-}
-
-pub(crate) async fn restore_requested_inputs(app_handle: &AppHandle) {
-    let requested = app_handle.state::();
-    let snapshot = requested.snapshot();
-    if snapshot.microphone.pending || snapshot.camera.pending {
-        return;
-    }
-    let microphone_permission = check_requested_microphone_permission(
-        snapshot.microphone.value.as_deref(),
-        permissions::check_microphone_access,
-    );
-    let camera_permission = check_requested_camera_permission(
-        snapshot.camera.value.as_ref(),
-        permissions::check_camera_access,
-    );
-    let _operation = requested.operation.lock().await;
-    let state = app_handle.state::>();
-    if !requested.is_current(&snapshot) || state.read().await.is_recording_active_or_pending() {
-        return;
-    }
-    if !requested
-        .inner
-        .lock()
-        .unwrap()
-        .microphone
-        .prepare_restore(snapshot.microphone.revision)
-    {
-        return;
-    }
-    let mic_result = match microphone_permission {
-        Ok(()) => {
-            apply_mic_input(
-                app_handle,
-                state.clone(),
-                snapshot.microphone.value.clone(),
-                snapshot.microphone.revision,
-            )
-            .await
-        }
-        Err(error) => Err(error),
-    };
-    requested
-        .inner
-        .lock()
-        .unwrap()
-        .microphone
-        .finish(snapshot.microphone.revision, &mic_result);
-    if let Err(error) = mic_result {
-        warn!(%error, "Failed to restore requested microphone");
-    }
-
-    let restore_camera = {
-        let state = state.read().await;
-        requested.is_current(&snapshot)
-            && !state.is_recording_active_or_pending()
-            && !state.camera_cleanup_done
-            && !state.camera_in_use
-            && snapshot.camera.value.is_some()
-    };
-    if !restore_camera {
-        return;
-    }
-    if !requested
-        .inner
-        .lock()
-        .unwrap()
-        .camera
-        .prepare_restore(snapshot.camera.revision)
-    {
-        return;
-    }
-    let camera_result = match camera_permission {
-        Ok(()) => {
-            apply_camera_input(
-                app_handle,
-                state,
-                snapshot.camera.value,
-                Some(false),
-                snapshot.camera.revision,
-            )
-            .await
-        }
-        Err(error) => Err(error),
-    };
-    requested
-        .inner
-        .lock()
-        .unwrap()
-        .camera
-        .finish(snapshot.camera.revision, &camera_result);
-    if let Err(error) = camera_result {
-        warn!(%error, "Failed to restore requested camera");
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app_handle, state))]
-async fn set_native_camera_preview_enabled(
-    app_handle: AppHandle,
-    state: MutableState<'_, App>,
-    enabled: bool,
-) -> Result<(), String> {
-    if enabled && cfg!(not(target_os = "macos")) {
-        return Err("Native camera preview is only available on macOS".to_string());
-    }
-
-    let operation_lock = app_handle.state::();
-    let _operation_guard = operation_lock.lock().await;
-
-    GeneralSettingsStore::update(&app_handle, |settings| {
-        settings.enable_native_camera_preview = enabled;
-    })?;
-
-    let window = CapWindowId::Camera.get(&app_handle);
-
-    if enabled {
-        let Some(window) = window else {
-            return Ok(());
-        };
-        let is_visible = window.is_visible().unwrap_or(false);
-        if !is_visible {
-            return Ok(());
-        }
-
-        let init_result = {
-            let mut app = state.write().await;
-            windows::ensure_camera_input_active(&mut app).await;
-            if app.selected_camera_id.is_none() || !app.camera_in_use {
-                None
-            } else {
-                let camera_feed = app.camera_feed.clone();
-                Some(app.camera_preview.init_window(window, camera_feed).await)
-            }
-        };
-
-        let Some(init_result) = init_result else {
-            return Ok(());
-        };
-
-        if let Err(err) = init_result {
-            GeneralSettingsStore::update(&app_handle, |settings| {
-                settings.enable_native_camera_preview = false;
-            })?;
-            return Err(format!("Failed to enable native camera preview: {err}"));
-        }
-
-        let (camera_feed, camera_ws_sender) = {
-            let app = state.read().await;
-            #[allow(deprecated)]
-            (app.camera_feed.clone(), app.camera_ws_sender.clone())
-        };
-        #[allow(deprecated)]
-        let result = camera_feed
-            .ask(feeds::camera::RemoveSender(camera_ws_sender))
-            .await;
-        if let Err(err) = result {
-            warn!(error = %err, "Failed to remove camera WebSocket sender");
-        }
-
-        return Ok(());
-    }
-
-    let (shutdown_rx, camera_feed, camera_ws_sender, should_restore_ws_sender) = {
-        let mut app = state.write().await;
-        #[allow(deprecated)]
-        (
-            app.camera_preview.begin_shutdown(),
-            app.camera_feed.clone(),
-            app.camera_ws_sender.clone(),
-            app.selected_camera_id.is_some() && app.camera_in_use,
-        )
-    };
-
-    if let Some(rx) = shutdown_rx {
-        let _ = tokio::time::timeout(Duration::from_secs(2), rx).await;
-    }
-
-    if should_restore_ws_sender {
-        #[allow(deprecated)]
-        let result = camera_feed
-            .ask(feeds::camera::AddSender(camera_ws_sender))
-            .await;
-        if let Err(err) = result {
-            warn!(error = %err, "Failed to restore camera WebSocket sender");
-        }
-    }
-
-    Ok(())
-}
-
-fn display_for_position(pos_x: f64, pos_y: f64) -> Option {
-    Display::list().into_iter().find_map(|display| {
-        let bounds = display.raw_handle().logical_bounds()?;
-        let x = bounds.position().x();
-        let y = bounds.position().y();
-        let width = bounds.size().width();
-        let height = bounds.size().height();
-        if pos_x >= x && pos_x < x + width && pos_y >= y && pos_y < y + height {
-            Some(display)
-        } else {
-            None
-        }
-    })
-}
-
-// On Windows the per-monitor logical rects overlap in mixed-DPI layouts, so a
-// window's display must be resolved from its physical position; logical
-// containment (display_for_position) can match the wrong monitor there.
-#[cfg(windows)]
-fn display_for_physical_position(pos_x: f64, pos_y: f64) -> Option {
-    Display::list().into_iter().find(|display| {
-        display
-            .raw_handle()
-            .physical_bounds()
-            .is_some_and(|bounds| {
-                pos_x >= bounds.position().x()
-                    && pos_x < bounds.position().x() + bounds.size().width()
-                    && pos_y >= bounds.position().y()
-                    && pos_y < bounds.position().y() + bounds.size().height()
-            })
-    })
-}
-
-pub(crate) fn update_camera_window_position_settings(
-    settings: &mut GeneralSettingsStore,
-    x: f64,
-    y: f64,
-    display_id: Option,
-) {
-    let display = display_id
-        .and_then(|id| Display::from_id(&id))
-        .or_else(|| display_for_position(x, y));
-    let display_id = display.as_ref().map(|display| display.id());
-    let monitor_name = display
-        .as_ref()
-        .and_then(|display| display.name())
-        .filter(|name| !name.trim().is_empty());
-    let position = general_settings::WindowPosition { x, y, display_id };
-    settings.camera_window_position = Some(position.clone());
-    if let Some(monitor_name) = monitor_name {
-        settings
-            .camera_window_positions_by_monitor_name
-            .insert(monitor_name, position);
-    }
-}
-
-fn spawn_mic_error_handler(app_handle: AppHandle, error_rx: flume::Receiver) {
-    tokio::spawn(async move {
-        let state = app_handle.state::>();
-        let state = state.inner().clone();
-
-        let error_rx = error_rx;
-
-        while let Ok(err) = error_rx.recv_async().await {
-            if app_is_exiting(&app_handle) {
-                break;
-            }
-
-            error!("Mic feed actor error: {err}");
-
-            {
-                let mut app = state.write().await;
-
-                if let Err(handle_err) = app
-                    .handle_input_disconnect(RecordingInputKind::Microphone)
-                    .await
-                {
-                    warn!("Failed to handle mic disconnect event: {handle_err}");
-                }
-            }
-
-            tokio::time::sleep(Duration::from_millis(500)).await;
-
-            if app_is_exiting(&app_handle) {
-                break;
-            }
-
-            let mut app = state.write().await;
-            if app_is_exiting(&app_handle) {
-                break;
-            }
-            match app.ensure_selected_mic_ready().await {
-                Ok(()) => {
-                    info!("Microphone stream recovered after error");
-                    if let Err(restored_err) = app
-                        .handle_input_restored(RecordingInputKind::Microphone)
-                        .await
-                    {
-                        warn!("Failed to handle mic restoration: {restored_err}");
-                    }
-                }
-                Err(restart_err) => {
-                    warn!("Failed to restart microphone input after error: {restart_err}");
-                }
-            }
-        }
-    });
-}
-
-fn spawn_device_watchers(app_handle: AppHandle) {
-    spawn_microphone_watcher(app_handle.clone());
-    spawn_camera_watcher(app_handle);
-}
-
-#[derive(Serialize, Type, tauri_specta::Event, Debug, Clone)]
-pub struct DevicesUpdated {
-    cameras: Vec,
-    microphones: Vec,
-    permissions: permissions::OSPermissionsCheck,
-}
-
-#[tauri::command]
-#[specta::specta]
-async fn get_devices_snapshot() -> DevicesUpdated {
-    let permissions = permissions::do_permissions_check(false);
-    let cameras = if permissions.camera.permitted() {
-        cap_camera::list_cameras().collect()
-    } else {
-        Vec::new()
-    };
-    let microphones = if permissions.microphone.permitted() {
-        MicrophoneFeed::list_names()
-    } else {
-        Vec::new()
-    };
-    DevicesUpdated {
-        cameras,
-        microphones,
-        permissions,
-    }
-}
-
-fn any_webview_window_visible(app: &AppHandle) -> bool {
-    app.webview_windows()
-        .values()
-        .any(|window| window.is_visible().unwrap_or(false))
-}
-
-fn spawn_devices_snapshot_emitter(app_handle: AppHandle) {
-    tokio::spawn(async move {
-        let mut last_perm_tuple: (u8, u8, u8, u8) = (255, 255, 255, 255);
-        let mut last_camera_ids: Vec = Vec::new();
-        let mut last_mics: Vec = Vec::new();
-        let mut fast_loops = 0u32;
-        loop {
-            if app_is_exiting(&app_handle) {
-                break;
-            }
-
-            if power_observer::is_system_asleep() {
-                tokio::time::sleep(std::time::Duration::from_secs(1)).await;
-                continue;
-            }
-
-            if !any_webview_window_visible(&app_handle) {
-                tokio::time::sleep(std::time::Duration::from_secs(5)).await;
-                continue;
-            }
-
-            let permissions = permissions::do_permissions_check(false);
-            let Some((cameras, microphones)) = collect_device_inventory(
-                || app_is_exiting(&app_handle),
-                permissions.camera.permitted(),
-                permissions.microphone.permitted(),
-                || cap_camera::list_cameras().collect::>(),
-                MicrophoneFeed::list_names,
-            ) else {
-                break;
-            };
-            let perm_tuple = (
-                match permissions.screen_recording {
-                    permissions::OSPermissionStatus::NotNeeded => 0,
-                    permissions::OSPermissionStatus::Empty => 1,
-                    permissions::OSPermissionStatus::Granted => 2,
-                    permissions::OSPermissionStatus::Denied => 3,
-                },
-                match permissions.microphone {
-                    permissions::OSPermissionStatus::NotNeeded => 0,
-                    permissions::OSPermissionStatus::Empty => 1,
-                    permissions::OSPermissionStatus::Granted => 2,
-                    permissions::OSPermissionStatus::Denied => 3,
-                },
-                match permissions.camera {
-                    permissions::OSPermissionStatus::NotNeeded => 0,
-                    permissions::OSPermissionStatus::Empty => 1,
-                    permissions::OSPermissionStatus::Granted => 2,
-                    permissions::OSPermissionStatus::Denied => 3,
-                },
-                match permissions.accessibility {
-                    permissions::OSPermissionStatus::NotNeeded => 0,
-                    permissions::OSPermissionStatus::Empty => 1,
-                    permissions::OSPermissionStatus::Granted => 2,
-                    permissions::OSPermissionStatus::Denied => 3,
-                },
-            );
-            let camera_ids: Vec =
-                cameras.iter().map(|c| c.device_id().to_string()).collect();
-            let mut changed = perm_tuple != last_perm_tuple;
-            if !changed {
-                changed = camera_ids != last_camera_ids || microphones != last_mics;
-            }
-            if changed && !app_is_exiting(&app_handle) {
-                DevicesUpdated {
-                    cameras: cameras.clone(),
-                    microphones: microphones.clone(),
-                    permissions: permissions.clone(),
-                }
-                .emit(&app_handle)
-                .ok();
-                last_perm_tuple = perm_tuple;
-                last_camera_ids = camera_ids;
-                last_mics = microphones;
-            }
-            let dur = if fast_loops < 10 {
-                std::time::Duration::from_millis(500)
-            } else {
-                std::time::Duration::from_secs(5)
-            };
-            fast_loops = fast_loops.saturating_add(1);
-            tokio::time::sleep(dur).await;
-
-            if app_is_exiting(&app_handle) {
-                break;
-            }
-        }
-    });
-}
-
-fn spawn_system_resume_detector(app_handle: AppHandle) {
-    const TICK: Duration = Duration::from_secs(5);
-    const WAKE_THRESHOLD: Duration = Duration::from_secs(20);
-
-    tokio::spawn(async move {
-        let mut last_instant = std::time::Instant::now();
-        let mut last_system_time = std::time::SystemTime::now();
-
-        loop {
-            if app_is_exiting(&app_handle) {
-                break;
-            }
-
-            tokio::time::sleep(TICK).await;
-
-            if app_is_exiting(&app_handle) {
-                break;
-            }
-
-            let now_instant = std::time::Instant::now();
-            let now_system = std::time::SystemTime::now();
-
-            let monotonic_delta = now_instant.saturating_duration_since(last_instant);
-            let wall_delta = now_system
-                .duration_since(last_system_time)
-                .unwrap_or_default();
-
-            last_instant = now_instant;
-            last_system_time = now_system;
-
-            let drift = wall_delta.saturating_sub(monotonic_delta);
-            let slept = drift >= WAKE_THRESHOLD || monotonic_delta >= TICK + WAKE_THRESHOLD;
-
-            if slept {
-                tracing::warn!(
-                    monotonic_ms = monotonic_delta.as_millis(),
-                    wall_ms = wall_delta.as_millis(),
-                    "System resume drift detected; scheduling resume recovery"
-                );
-
-                schedule_resume_recovery(app_handle.clone());
-            }
-        }
-    });
-}
-
-pub(crate) fn schedule_resume_recovery(app_handle: AppHandle) {
-    tauri::async_runtime::spawn(async move {
-        if app_is_exiting(&app_handle) {
-            return;
-        }
-
-        tokio::time::sleep(Duration::from_millis(500)).await;
-
-        if app_is_exiting(&app_handle) {
-            return;
-        }
-
-        #[cfg(target_os = "macos")]
-        {
-            if let Some(prewarmer) =
-                app_handle.try_state::()
-            {
-                prewarmer.request(true).await;
-            } else {
-                warn!("ScreenCapturePrewarmer state unavailable during resume recovery");
-            }
-        }
-
-        if !app_is_exiting(&app_handle) {
-            emit_app_event_safely(&app_handle, RequestScreenCapturePrewarm { force: true });
-        }
-
-        if !app_is_exiting(&app_handle) {
-            let snapshot = get_devices_snapshot().await;
-            emit_app_event_safely(&app_handle, snapshot);
-        }
-    });
-}
-
-async fn cleanup_camera_window(app: AppHandle, session_id: u64) {
-    if app_is_exiting(&app) {
-        return;
-    }
-
-    let state = app.state::>();
-
-    let camera_feed = {
-        let mut app_state = state.write().await;
-
-        if app_is_exiting(&app) {
-            return;
-        }
-
-        let current_session_id = app_state
-            .camera_preview
-            .session_id_handle()
-            .load(Ordering::Acquire);
-
-        if current_session_id != session_id {
-            tracing::info!(
-                "Camera cleanup aborted: session mismatch (cleanup session {} vs current {})",
-                session_id,
-                current_session_id
-            );
-            return;
-        }
-
-        if app_state.camera_cleanup_done {
-            return;
-        }
-
-        app_state.camera_cleanup_done = true;
-        app_state.camera_preview.pause();
-
-        if app_state.is_recording_active_or_pending() {
-            return;
-        }
-
-        let has_visible_target_overlay = app.webview_windows().iter().any(|(label, window)| {
-            label.starts_with("target-select-overlay-") && window.is_visible().unwrap_or(false)
-        });
-
-        let main_window_visible = CapWindowId::Main
-            .get(&app)
-            .and_then(|w| w.is_visible().ok())
-            .unwrap_or(false);
-
-        let is_camera_only_mode = recording_settings::RecordingSettingsStore::get(&app)
-            .ok()
-            .flatten()
-            .and_then(|s| s.target)
-            .is_some_and(|t| matches!(t, ScreenCaptureTarget::CameraOnly));
-
-        if is_camera_only_mode && main_window_visible {
-            tracing::info!("Camera cleanup: preserving camera feed for camera-only mode");
-            return;
-        }
-
-        if has_visible_target_overlay {
-            return;
-        }
-
-        app_state.camera_feed.clone()
-    };
-
-    let _ = tokio::time::timeout(
-        APP_EXIT_STEP_TIMEOUT,
-        camera_feed.ask(feeds::camera::RemoveInput),
-    )
-    .await;
-
-    let mut app_state = state.write().await;
-    app_state.camera_in_use = false;
-}
-
-async fn cleanup_camera_after_overlay_close(app: AppHandle, captured_session_id: u64) {
-    if app_is_exiting(&app) {
-        return;
-    }
-
-    let state = app.state::>();
-
-    let camera_feed = {
-        let mut app_state = state.write().await;
-
-        if app_is_exiting(&app) {
-            return;
-        }
-
-        let current_session_id = app_state
-            .camera_preview
-            .session_id_handle()
-            .load(Ordering::Acquire);
-        if current_session_id != captured_session_id {
-            tracing::info!(
-                "Camera cleanup after overlay aborted: session mismatch ({} vs {})",
-                captured_session_id,
-                current_session_id
-            );
-            return;
-        }
-
-        if app_state.camera_cleanup_done {
-            return;
-        }
-
-        if app_state.is_recording_active_or_pending() {
-            return;
-        }
-
-        let has_camera_window = CapWindowId::Camera.get(&app).is_some();
-        if has_camera_window {
-            return;
-        }
-
-        let has_visible_target_overlay = app.webview_windows().iter().any(|(label, window)| {
-            label.starts_with("target-select-overlay-") && window.is_visible().unwrap_or(false)
-        });
-        if has_visible_target_overlay {
-            return;
-        }
-
-        app_state.camera_cleanup_done = true;
-
-        if !app_state.camera_in_use {
-            return;
-        }
-
-        app_state.camera_feed.clone()
-    };
-
-    let _ = camera_feed.ask(feeds::camera::RemoveInput).await;
-
-    let mut app_state = state.write().await;
-    app_state.camera_in_use = false;
-}
-
-async fn cleanup_app_resources_for_exit(app: &AppHandle) {
-    let started = Instant::now();
-    log_process_memory_snapshot("exit_cleanup_begin");
-
-    // Reverse the macOS Liquid Glass private SPI (remove the NSGlassEffectView, restore
-    // window/WKWebView occlusion detection) BEFORE anything else, so a slow camera/ML
-    // shutdown can never starve it. Leaving an occlusion-suppressed private glass view
-    // attached when the process hard-exits can wedge WindowServer on macOS 26 and soft-
-    // restart the user's login session. Bounded so a stuck main thread can't block exit.
-    #[cfg(target_os = "macos")]
-    {
-        let _ = await_exit_step(
-            "teardown_liquid_glass",
-            APP_EXIT_STEP_TIMEOUT,
-            crate::platform::teardown_all_liquid_glass(app),
-        )
-        .await;
-    }
-
-    export::cancel_all_exports();
-    upload::lifecycle::shutdown().await;
-    power_observer::uninstall(app);
-    fake_window::cancel_all_fake_window_listeners(app);
-    close_target_select_overlays(app);
-
-    let preparing = app
-        .state::()
-        .inner()
-        .clone();
-    let _ = await_exit_step(
-        "dispose_preparing_editor_frames",
-        APP_EXIT_STEP_TIMEOUT,
-        preparing.dispose_all(),
-    )
-    .await;
-
-    let app_for_pending_editors = app.clone();
-    let _ = await_exit_step(
-        "dispose_pending_editor_instances",
-        APP_EXIT_STEP_TIMEOUT,
-        async move {
-            PendingEditorInstances::dispose_all(&app_for_pending_editors).await;
-            Ok::<(), String>(())
-        },
-    )
-    .await;
-
-    let app_for_editors = app.clone();
-    let _ = await_exit_step(
-        "dispose_editor_instances",
-        APP_EXIT_STEP_TIMEOUT,
-        async move {
-            EditorInstances::dispose_all(&app_for_editors).await;
-            Ok::<(), String>(())
-        },
-    )
-    .await;
-
-    let app_for_pending_screenshot_editors = app.clone();
-    let _ = await_exit_step(
-        "dispose_pending_screenshot_editor_instances",
-        APP_EXIT_STEP_TIMEOUT,
-        async move {
-            PendingScreenshotEditorInstances::dispose_all(&app_for_pending_screenshot_editors)
-                .await;
-            Ok::<(), String>(())
-        },
-    )
-    .await;
-
-    let app_for_screenshot_editors = app.clone();
-    let _ = await_exit_step(
-        "dispose_screenshot_editor_instances",
-        APP_EXIT_STEP_TIMEOUT,
-        async move {
-            ScreenshotEditorInstances::dispose_all(&app_for_screenshot_editors).await;
-            Ok::<(), String>(())
-        },
-    )
-    .await;
-
-    log_process_memory_snapshot("exit_after_editor_dispose");
-
-    let (mic_feed, camera_feed, camera_shutdown) = {
-        let Some(state) = app.try_state::>() else {
-            warn!("App state unavailable during exit cleanup");
-            return;
-        };
-        let mut app_state = state.write().await;
-        let camera_shutdown = app_state.camera_preview.begin_shutdown();
-        app_state.applied_mic_input.invalidate();
-        app_state.camera_in_use = false;
-        app_state.selected_camera_id = None;
-        (
-            app_state.mic_feed.clone(),
-            app_state.camera_feed.clone(),
-            camera_shutdown,
-        )
-    };
-
-    let _ = await_exit_step(
-        "remove_microphone_input",
-        APP_EXIT_STEP_TIMEOUT,
-        async move { mic_feed.ask(microphone::RemoveInput).await },
-    )
-    .await;
-    let _ = await_exit_step("remove_camera_input", APP_EXIT_STEP_TIMEOUT, async move {
-        camera_feed.ask(feeds::camera::RemoveInput).await
-    })
-    .await;
-
-    if let Some(rx) = camera_shutdown {
-        let _ = await_exit_step(
-            "camera_preview_shutdown",
-            APP_EXIT_CAMERA_SHUTDOWN_TIMEOUT,
-            rx,
-        )
-        .await;
-    }
-
-    captions::release_ml_models().await;
-    log_process_memory_snapshot("exit_cleanup_end");
-    info!(
-        elapsed_ms = started.elapsed().as_millis(),
-        "Exit cleanup completed"
-    );
-}
-
-#[cfg(target_os = "macos")]
-fn finalize_app_exit(app: &AppHandle, exit_code: i32) -> ! {
-    let _ = app;
-    sentry::Hub::with(|hub| {
-        if let Some(client) = hub.client() {
-            let _ = client.flush(Some(Duration::from_millis(250)));
-        }
-    });
-    match app_exit_action(exit_code) {
-        AppExitAction::Process(code) => force_exit(code),
-    }
-}
-
-#[cfg(not(target_os = "macos"))]
-fn finalize_app_exit(app: &AppHandle, exit_code: i32) {
-    match app_exit_action(exit_code) {
-        AppExitAction::Runtime(code) => app.exit(code),
-    }
-}
-
-pub(crate) fn with_idle_app(
-    app: &AppHandle,
-    include_exports: bool,
-    begin: impl FnOnce() -> T,
-) -> Result {
-    with_idle_app_for_title_flush(app, include_exports, false, begin)
-}
-
-fn with_idle_app_for_title_flush(
-    app: &AppHandle,
-    include_exports: bool,
-    owns_title_flush: bool,
-    begin: impl FnOnce() -> T,
-) -> Result {
-    let exit_state = app
-        .try_state::()
-        .ok_or(ExitBlocked::StateUnavailable)?;
-    let _admission = exit_state
-        .admission
-        .try_lock()
-        .map_err(|_| ExitBlocked::StateUnavailable)?;
-    if exit_state.is_exiting()
-        || (!owns_title_flush && exit_state.title_flush_pending.load(Ordering::Acquire))
-    {
-        return Err(ExitBlocked::AlreadyExiting);
-    }
-    let state = app
-        .try_state::>()
-        .ok_or(ExitBlocked::StateUnavailable)?;
-    let finalizing = app
-        .try_state::()
-        .ok_or(ExitBlocked::StateUnavailable)?;
-    let _clean_capture = app
-        .try_state::()
-        .ok_or(ExitBlocked::StateUnavailable)?;
-    let updates = app
-        .try_state::()
-        .ok_or(ExitBlocked::StateUnavailable)?;
-    if updates.is_installing() {
-        return Err(ExitBlocked::UpdateInstalling);
-    }
-    with_idle_recording_state(
-        &state,
-        |state| {
-            if state.is_recording_active_or_pending() || clean_capture::phase(app).is_some() {
-                return Err(ExitBlocked::RecordingActive);
-            }
-            let recordings = finalizing
-                .recordings
-                .try_lock()
-                .map_err(|_| ExitBlocked::StateUnavailable)?;
-            if has_pending_finalizations(&recordings) {
-                return Err(ExitBlocked::FinalizationActive);
-            }
-            if include_exports {
-                if export::export_session_active() {
-                    return Err(ExitBlocked::ExportActive);
-                }
-                if upload::upload_session_active() {
-                    return Err(ExitBlocked::UploadActive);
-                }
-            }
-            Ok(())
-        },
-        begin,
-    )
-}
-
-fn begin_app_exit_if_idle(app: &AppHandle, restarting: bool) -> Result {
-    let exit_state = app
-        .try_state::()
-        .ok_or(ExitBlocked::StateUnavailable)?;
-    with_idle_app(app, restarting, || {
-        if !exit_state.begin() {
-            return false;
-        }
-        if restarting {
-            exit_state.begin_restart();
-        }
-        true
-    })
-}
-
-pub(crate) fn prepare_app_exit(
-    app: &AppHandle,
-    prepare: impl FnOnce() -> Result<(), String>,
-) -> Result<(), String> {
-    let exit_state = app
-        .try_state::()
-        .ok_or(ExitBlocked::StateUnavailable.message())?;
-    with_idle_app(app, true, || {
-        prepare_then_begin_exit(prepare, || exit_state.begin())
-    })
-    .map_err(|reason| reason.message().to_string())?
-}
-
-fn show_exit_blocked(app: &AppHandle, reason: ExitBlocked) {
-    warn!(
-        ?reason,
-        "Refusing app exit while recording safety is unconfirmed"
-    );
-    app.dialog()
-        .message(reason.message())
-        .title("Cap is still busy")
-        .kind(tauri_plugin_dialog::MessageDialogKind::Warning)
-        .show(|_| {});
-}
-
-#[derive(Clone, Serialize)]
-#[serde(rename_all = "camelCase")]
-struct EditorTitleSaveRequest {
-    request_id: String,
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct EditorTitleSaveResponse {
-    request_id: String,
-    window_label: String,
-    error: Option,
-}
-
-async fn wait_for_editor_title_saves(
-    request_id: &str,
-    mut pending: HashSet,
-    mut responses: tokio::sync::mpsc::UnboundedReceiver,
-    timeout: Duration,
-) -> Result<(), String> {
-    tokio::time::timeout(timeout, async {
-        while !pending.is_empty() {
-            let response = responses
-                .recv()
-                .await
-                .ok_or("The editor title save connection closed before saving finished.")?;
-            if response.request_id != request_id || !pending.remove(&response.window_label) {
-                continue;
-            }
-            if let Some(error) = response.error {
-                return Err(format!("Could not save the recording title: {error}"));
-            }
-        }
-        Ok(())
-    })
-    .await
-    .map_err(|_| {
-        "Could not confirm that all recording titles were saved. Try Quit again.".to_string()
-    })?
-}
-
-async fn flush_editor_titles_for_exit(
-    app: &AppHandle,
-) -> Result, String> {
-    let labels: HashSet<_> = app
-        .webview_windows()
-        .into_keys()
-        .filter(|label| matches!(CapWindowId::from_str(label), Ok(CapWindowId::Editor { .. })))
-        .collect();
-    if labels.is_empty() {
-        return Ok(None);
-    }
-
-    let request = EditorTitleSaveRequest {
-        request_id: uuid::Uuid::new_v4().to_string(),
-    };
-    let (sender, responses) = tokio::sync::mpsc::unbounded_channel();
-    let listener = app.listen_any("editor-title-save-finished", move |event| {
-        if let Ok(response) = serde_json::from_str(event.payload()) {
-            let _ = sender.send(response);
-        }
-    });
-    let result = async {
-        for label in &labels {
-            app.emit_to(label, "editor-title-save-request", &request)
-                .map_err(|error| format!("Could not request an editor title save: {error}"))?;
-        }
-        wait_for_editor_title_saves(
-            &request.request_id,
-            labels.clone(),
-            responses,
-            Duration::from_secs(5),
-        )
-        .await?;
-        if app.webview_windows().keys().any(|label| {
-            !labels.contains(label)
-                && matches!(CapWindowId::from_str(label), Ok(CapWindowId::Editor { .. }))
-        }) {
-            return Err("Another editor opened while preparing to quit. Try Quit again.".into());
-        }
-        Ok(())
-    }
-    .await;
-    app.unlisten(listener);
-    if result.is_err() {
-        let _ = app.emit("editor-title-save-cancelled", &request);
-    }
-    result.map(|()| Some(request))
-}
-
-#[tauri::command]
-#[specta::specta]
-fn restart_app(app: AppHandle) -> Result<(), String> {
-    match begin_app_exit_if_idle(&app, true) {
-        Ok(true) => {
-            app.request_restart();
-            Ok(())
-        }
-        Ok(false) => Err("Cap is already shutting down.".into()),
-        Err(reason) => Err(reason.message().into()),
-    }
-}
-
-pub async fn request_app_exit(app: AppHandle) {
-    let Some(exit_state) = app.try_state::() else {
-        show_exit_blocked(&app, ExitBlocked::StateUnavailable);
-        return;
-    };
-    let pending = match with_idle_app(&app, false, || exit_state.begin_title_flush()) {
-        Ok(Some(pending)) => pending,
-        Ok(None) => return,
-        Err(ExitBlocked::AlreadyExiting) => return,
-        Err(reason) => {
-            show_exit_blocked(&app, reason);
-            return;
-        }
-    };
-    let request = match flush_editor_titles_for_exit(&app).await {
-        Ok(request) => request,
-        Err(error) => {
-            drop(pending);
-            warn!(%error, "Quit canceled because an editor title could not be saved");
-            app.dialog()
-                .message(format!(
-                    "{error}\n\nCap is still open. Your title is still in the editor."
-                ))
-                .title("Title not saved")
-                .kind(tauri_plugin_dialog::MessageDialogKind::Warning)
-                .show(|_| {});
-            return;
-        }
-    };
-    let admission = with_idle_app_for_title_flush(&app, true, true, || exit_state.begin());
-    drop(pending);
-    match admission {
-        Ok(true) => {}
-        result => {
-            if let Some(request) = request {
-                let _ = app.emit("editor-title-save-cancelled", request);
-            }
-            if let Err(reason) = result {
-                show_exit_blocked(&app, reason);
-            }
-            return;
-        }
-    }
-    complete_admitted_app_exit(app).await;
-}
-
-pub(crate) async fn complete_admitted_app_exit(app: AppHandle) {
-    #[cfg(target_os = "macos")]
-    cancel_macos_startup_opens(&app);
-    spawn_exit_watchdog();
-    export::cancel_all_exports();
-
-    if tokio::time::timeout(APP_EXIT_TOTAL_TIMEOUT, cleanup_app_resources_for_exit(&app))
-        .await
-        .is_err()
-    {
-        error!(
-            timeout_ms = APP_EXIT_TOTAL_TIMEOUT.as_millis(),
-            "Timed out while cleaning up app resources for exit"
-        );
-    } else {
-        // Cleanup finished within budget — disarm the sentinel so this graceful exit
-        // is not reported as an unexpected termination on next launch. A timed-out
-        // (hung) shutdown deliberately leaves it armed.
-        crash_sentinel::mark_clean_exit();
-    }
-
-    finalize_app_exit(&app, 0);
-}
-
-pub(crate) fn find_mic_by_label(devices: &[String], selected_label: &str) -> Option {
-    if devices.iter().any(|name| name == selected_label) {
-        return Some(selected_label.to_string());
-    }
-
-    None
-}
-
-fn spawn_microphone_watcher(app_handle: AppHandle) {
-    tokio::spawn(async move {
-        let state = app_handle.state::>();
-        let state = state.inner().clone();
-
-        loop {
-            if app_is_exiting(&app_handle) {
-                break;
-            }
-
-            if power_observer::is_system_asleep() {
-                tokio::time::sleep(Duration::from_secs(1)).await;
-                continue;
-            }
-
-            let (should_check, label, is_marked) = {
-                let guard = state.read().await;
-                (
-                    matches!(guard.recording_state, RecordingState::Active(_)),
-                    guard.selected_mic_label.clone(),
-                    guard
-                        .disconnected_inputs
-                        .contains(&RecordingInputKind::Microphone),
-                )
-            };
-
-            if should_check && let Some(selected_label) = label {
-                let Some(devices) = run_while_active(
-                    || app_is_exiting(&app_handle),
-                    microphone::MicrophoneFeed::list_names,
-                ) else {
-                    break;
-                };
-                let matched = find_mic_by_label(&devices, &selected_label);
-
-                if matched.is_none() && !is_marked {
-                    let mut app = state.write().await;
-                    if let Err(err) = app
-                        .handle_input_disconnect(RecordingInputKind::Microphone)
-                        .await
-                    {
-                        warn!("Failed to handle mic disconnect: {err}");
-                    }
-                } else if matched.is_some() && is_marked {
-                    let mut app = state.write().await;
-
-                    if let Err(err) = app
-                        .handle_input_restored(RecordingInputKind::Microphone)
-                        .await
-                    {
-                        warn!("Failed to handle mic reconnection: {err}");
-                    }
-                }
-            }
-
-            tokio::time::sleep(Duration::from_secs(1)).await;
-        }
-    });
-}
-
-fn spawn_camera_watcher(app_handle: AppHandle) {
-    tokio::spawn(async move {
-        let state = app_handle.state::>();
-        let state = state.inner().clone();
-
-        loop {
-            if app_is_exiting(&app_handle) {
-                break;
-            }
-
-            if power_observer::is_system_asleep() {
-                tokio::time::sleep(Duration::from_secs(1)).await;
-                continue;
-            }
-
-            let (should_check, camera_id, is_marked) = {
-                let guard = state.read().await;
-                (
-                    matches!(guard.recording_state, RecordingState::Active(_))
-                        && guard.camera_in_use,
-                    guard.selected_camera_id.clone(),
-                    guard
-                        .disconnected_inputs
-                        .contains(&RecordingInputKind::Camera),
-                )
-            };
-
-            if should_check && let Some(ref selected_id) = camera_id {
-                let Some(available) = run_while_active(
-                    || app_is_exiting(&app_handle),
-                    || is_camera_available(selected_id),
-                ) else {
-                    break;
-                };
-                debug!(
-                    "Camera watcher: checking availability for {:?}, available={}, is_marked={}",
-                    selected_id, available, is_marked
-                );
-
-                if !available && !is_marked {
-                    warn!(
-                        "Camera watcher: camera {:?} detected as unavailable, continuing recording without camera",
-                        selected_id
-                    );
-                    let mut app = state.write().await;
-                    if let Err(err) = app
-                        .handle_input_disconnect(RecordingInputKind::Camera)
-                        .await
-                    {
-                        warn!("Failed to handle camera disconnect: {err}");
-                    }
-                } else if available && is_marked {
-                    let mut app = state.write().await;
-                    if let Err(err) = app.handle_input_restored(RecordingInputKind::Camera).await {
-                        warn!("Failed to handle camera reconnection: {err}");
-                    }
-                }
-            }
-
-            tokio::time::sleep(Duration::from_secs(1)).await;
-        }
-    });
-}
-
-pub(crate) fn is_camera_available(id: &DeviceOrModelID) -> bool {
-    let cameras: Vec<_> = cap_camera::list_cameras().collect();
-    debug!(
-        "is_camera_available: looking for {:?} in {} cameras",
-        id,
-        cameras.len()
-    );
-    for camera in &cameras {
-        debug!(
-            "  - device_id={}, model_id={:?}, name={}",
-            camera.device_id(),
-            camera.model_id(),
-            camera.display_name()
-        );
-    }
-    cameras.iter().any(|info| match id {
-        DeviceOrModelID::DeviceID(device_id) => info.device_id() == device_id,
-        DeviceOrModelID::ModelID(model_id) => {
-            info.model_id().is_some_and(|existing| existing == model_id)
-        }
-    })
-}
-
-#[derive(specta::Type, Serialize, tauri_specta::Event, Clone)]
-pub struct RecordingOptionsChanged;
-
-#[derive(Deserialize, specta::Type, Serialize, tauri_specta::Event, Debug, Clone)]
-pub struct NewStudioRecordingAdded {
-    path: PathBuf,
-}
-
-#[derive(Deserialize, specta::Type, Serialize, tauri_specta::Event, Debug, Clone)]
-pub struct EditorRecordingAdded {
-    pub editor_path: PathBuf,
-    pub recording_path: PathBuf,
-}
-
-#[derive(Deserialize, specta::Type, tauri_specta::Event, Debug, Clone, Serialize)]
-pub struct RecordingDeleted {
-    path: PathBuf,
-}
-
-#[derive(specta::Type, tauri_specta::Event, Serialize)]
-pub struct SetCaptureAreaPending(bool);
-
-#[derive(Deserialize, specta::Type, Serialize, tauri_specta::Event, Debug, Clone)]
-pub struct NewScreenshotAdded {
-    path: PathBuf,
-}
-
-#[derive(Deserialize, specta::Type, Serialize, tauri_specta::Event, Debug, Clone)]
-pub struct RecordingStarted;
-
-#[derive(Deserialize, specta::Type, Serialize, tauri_specta::Event, Debug, Clone)]
-pub struct RecordingStopped;
-
-#[derive(Deserialize, specta::Type, Serialize, tauri_specta::Event, Debug, Clone)]
-pub struct RequestStartRecording {
-    pub mode: RecordingMode,
-}
-
-#[derive(Deserialize, specta::Type, Serialize, tauri_specta::Event, Debug, Clone)]
-pub struct RequestOpenRecordingPicker {
-    pub target_mode: Option,
-}
-
-#[derive(Deserialize, specta::Type, Serialize, tauri_specta::Event, Debug, Clone)]
-pub struct RequestSetTargetMode {
-    pub target_mode: Option,
-    pub display_id: Option,
-}
-
-#[derive(Deserialize, specta::Type, Serialize, tauri_specta::Event, Debug, Clone)]
-pub struct RequestOpenSettings {
-    page: String,
-}
-
-#[derive(Deserialize, specta::Type, Serialize, tauri_specta::Event, Debug, Clone)]
-pub struct RequestScrollToSettingsSection {
-    pub section: String,
-}
-
-#[derive(Deserialize, specta::Type, Serialize, tauri_specta::Event, Debug, Clone)]
-pub struct RequestScreenCapturePrewarm {
-    #[serde(default)]
-    pub force: bool,
-}
-
-#[derive(Deserialize, specta::Type, Serialize, tauri_specta::Event, Debug, Clone)]
-pub struct NewNotification {
-    title: String,
-    body: String,
-    is_error: bool,
-}
-
-type ArcLock = Arc>;
-pub type MutableState<'a, T> = State<'a, Arc>>;
-
-#[cfg(target_os = "linux")]
-pub enum ClipboardContext {
-    Platform(PlatformClipboardContext),
-    Wayland(AppHandle),
-}
-
-#[cfg(target_os = "linux")]
-fn uses_wayland_clipboard_fallback(
-    wayland_display: Option<&std::ffi::OsStr>,
-    x11_display: Option<&std::ffi::OsStr>,
-) -> bool {
-    wayland_display.is_some() && x11_display.is_none()
-}
-
-#[cfg(target_os = "linux")]
-impl ClipboardContext {
-    fn new(app: &AppHandle) -> clipboard_rs::common::Result {
-        match PlatformClipboardContext::new() {
-            Ok(context) => Ok(Self::Platform(context)),
-            Err(error)
-                if uses_wayland_clipboard_fallback(
-                    std::env::var_os("WAYLAND_DISPLAY").as_deref(),
-                    std::env::var_os("DISPLAY").as_deref(),
-                ) =>
-            {
-                info!(%error, "Using native Wayland clipboard");
-                Ok(Self::Wayland(app.clone()))
-            }
-            Err(error) => Err(error),
-        }
-    }
-
-    fn set_text(&self, text: String) -> clipboard_rs::common::Result<()> {
-        match self {
-            Self::Platform(context) => context.set_text(text),
-            Self::Wayland(app) => app.clipboard().write_text(text).map_err(Into::into),
-        }
-    }
-
-    fn set_image(&self, image: clipboard_rs::RustImageData) -> clipboard_rs::common::Result<()> {
-        match self {
-            Self::Platform(context) => context.set_image(image),
-            Self::Wayland(app) => {
-                let rgba = image.to_rgba8()?;
-                let width = rgba.width();
-                let height = rgba.height();
-                let image = tauri::image::Image::new_owned(rgba.into_raw(), width, height);
-                app.clipboard().write_image(&image).map_err(Into::into)
-            }
-        }
-    }
-
-    fn set_files(&self, files: Vec) -> clipboard_rs::common::Result<()> {
-        match self {
-            Self::Platform(context) => context.set_files(files),
-            Self::Wayland(app) => {
-                let urls = files
-                    .into_iter()
-                    .map(|path| {
-                        tauri::Url::from_file_path(&path)
-                            .map(|url| url.to_string())
-                            .map_err(|()| format!("Invalid clipboard file path: {path}"))
-                    })
-                    .collect::, _>>()?;
-
-                if urls.is_empty() {
-                    return Err("No files supplied for clipboard".into());
-                }
-
-                app.clipboard()
-                    .write_text(urls.join("\r\n"))
-                    .map_err(Into::into)
-            }
-        }
-    }
-}
-
-type SingleTuple = (T,);
-
-#[derive(Serialize, Type)]
-struct JsonValue(
-    #[serde(skip)] PhantomData,
-    #[specta(type = SingleTuple)] serde_json::Value,
-);
-
-impl Clone for JsonValue {
-    fn clone(&self) -> Self {
-        Self(PhantomData, self.1.clone())
-    }
-}
-
-impl JsonValue {
-    fn new(value: &T) -> Self {
-        Self(PhantomData, json!(value))
-    }
-}
-
-#[derive(Serialize, Type)]
-#[serde(rename_all = "camelCase")]
-pub struct RecordingInfo {
-    capture_target: ScreenCaptureTarget,
-}
-
-#[derive(Serialize, Type)]
-#[serde(rename_all = "camelCase")]
-enum CurrentRecordingTarget {
-    Window {
-        id: WindowId,
-        bounds: Option,
-    },
-    Screen {
-        id: DisplayId,
-    },
-    Area {
-        screen: DisplayId,
-        bounds: LogicalBounds,
-    },
-    Camera,
-}
-
-#[derive(Serialize, Type)]
-#[serde(rename_all = "camelCase")]
-pub enum RecordingStatus {
-    Pending,
-    Recording,
-}
-
-#[derive(Serialize, Type)]
-#[serde(rename_all = "camelCase")]
-struct CurrentRecording {
-    target: CurrentRecordingTarget,
-    mode: RecordingMode,
-    status: RecordingStatus,
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(state))]
-async fn get_current_recording(
-    state: MutableState<'_, App>,
-) -> Result>, ()> {
-    let state = state.read().await;
-
-    let (mode, capture_target, status) = match &state.recording_state {
-        RecordingState::None => {
-            return Ok(JsonValue::new(&None));
-        }
-        RecordingState::Pending { mode, target } => (*mode, target, RecordingStatus::Pending),
-        RecordingState::Active(inner) => (
-            inner.mode(),
-            inner.capture_target(),
-            RecordingStatus::Recording,
-        ),
-    };
-
-    let target = match capture_target {
-        ScreenCaptureTarget::Display { id } => CurrentRecordingTarget::Screen { id: id.clone() },
-        ScreenCaptureTarget::Window { id } => {
-            let bounds =
-                scap_targets::Window::from_id(id).and_then(|w| w.display_relative_logical_bounds());
-            CurrentRecordingTarget::Window {
-                id: id.clone(),
-                bounds,
-            }
-        }
-        ScreenCaptureTarget::Area { screen, bounds } => CurrentRecordingTarget::Area {
-            screen: screen.clone(),
-            bounds: *bounds,
-        },
-        ScreenCaptureTarget::CameraOnly => CurrentRecordingTarget::Camera,
-    };
-
-    Ok(JsonValue::new(&Some(CurrentRecording {
-        target,
-        mode,
-        status,
-    })))
-}
-
-#[derive(Serialize, Type, tauri_specta::Event, Clone)]
-pub struct CurrentRecordingChanged;
-
-pub(crate) async fn create_screenshot(
-    input: PathBuf,
-    output: PathBuf,
-    size: Option<(u32, u32)>,
-) -> Result<(), String> {
-    let result: Result<(), String> = tokio::task::spawn_blocking(move || -> Result<(), String> {
-        let mut ictx = ffmpeg::format::input(&input).map_err(|e| e.to_string())?;
-        let input_stream = ictx
-            .streams()
-            .best(ffmpeg::media::Type::Video)
-            .ok_or("No video stream found")?;
-        let video_stream_index = input_stream.index();
-
-        let mut decoder =
-            ffmpeg::codec::context::Context::from_parameters(input_stream.parameters())
-                .map_err(|e| e.to_string())?
-                .decoder()
-                .video()
-                .map_err(|e| e.to_string())?;
-
-        let mut scaler = ffmpeg::software::scaling::context::Context::get(
-            decoder.format(),
-            decoder.width(),
-            decoder.height(),
-            ffmpeg::format::Pixel::RGB24,
-            size.map_or(decoder.width(), |s| s.0),
-            size.map_or(decoder.height(), |s| s.1),
-            ffmpeg::software::scaling::flag::Flags::BILINEAR,
-        )
-        .map_err(|e| e.to_string())?;
-
-        let mut frame = ffmpeg::frame::Video::empty();
-        for (stream, packet) in ictx.packets() {
-            if stream.index() == video_stream_index {
-                decoder.send_packet(&packet).map_err(|e| e.to_string())?;
-                if decoder.receive_frame(&mut frame).is_ok() {
-                    let mut rgb_frame = ffmpeg::frame::Video::empty();
-                    scaler
-                        .run(&frame, &mut rgb_frame)
-                        .map_err(|e| e.to_string())?;
-
-                    let width = rgb_frame.width() as usize;
-                    let height = rgb_frame.height() as usize;
-                    let bytes_per_pixel = 3;
-                    let src_stride = rgb_frame.stride(0);
-                    let dst_stride = width * bytes_per_pixel;
-
-                    let mut img_buffer = vec![0u8; height * dst_stride];
-
-                    for y in 0..height {
-                        let src_slice =
-                            &rgb_frame.data(0)[y * src_stride..y * src_stride + dst_stride];
-                        let dst_slice = &mut img_buffer[y * dst_stride..(y + 1) * dst_stride];
-                        dst_slice.copy_from_slice(src_slice);
-                    }
-
-                    let img = image::RgbImage::from_raw(width as u32, height as u32, img_buffer)
-                        .ok_or("Failed to create image from frame data")?;
-
-                    img.save_with_format(&output, image::ImageFormat::Jpeg)
-                        .map_err(|e| e.to_string())?;
-
-                    return Ok(());
-                }
-            }
-        }
-
-        Err("Failed to create screenshot".to_string())
-    })
-    .await
-    .map_err(|e| format!("Task join error: {e}"))?;
-
-    result
-}
-
-pub(crate) async fn create_screenshot_source_from_segments(
-    segments_dir: &std::path::Path,
-) -> Result {
-    let init_path = segments_dir.join("init.mp4");
-    if !init_path.exists() {
-        return Err(format!("init.mp4 not found in {}", segments_dir.display()));
-    }
-
-    let first_segment = find_first_segment(segments_dir)
-        .ok_or_else(|| format!("No .m4s segments found in {}", segments_dir.display()))?;
-
-    let temp_path = segments_dir.join(".screenshot_source.mp4");
-    let mut out = tokio::fs::File::create(&temp_path)
-        .await
-        .map_err(|e| format!("Failed to create screenshot source: {e}"))?;
-
-    let mut init_file = tokio::fs::File::open(&init_path)
-        .await
-        .map_err(|e| format!("Failed to open init.mp4: {e}"))?;
-    tokio::io::copy(&mut init_file, &mut out)
-        .await
-        .map_err(|e| format!("Failed to copy init.mp4: {e}"))?;
-
-    let mut seg_file = tokio::fs::File::open(&first_segment)
-        .await
-        .map_err(|e| format!("Failed to open {}: {e}", first_segment.display()))?;
-    tokio::io::copy(&mut seg_file, &mut out)
-        .await
-        .map_err(|e| format!("Failed to copy segment: {e}"))?;
-
-    Ok(temp_path)
-}
-
-fn find_first_segment(dir: &std::path::Path) -> Option {
-    let mut segments: Vec = std::fs::read_dir(dir)
-        .ok()?
-        .filter_map(|e| {
-            let path = e.ok()?.path();
-            if path.extension().is_some_and(|ext| ext == "m4s") {
-                Some(path)
-            } else {
-                None
-            }
-        })
-        .collect();
-    segments.sort();
-    segments.into_iter().next()
-}
-
-// async fn create_thumbnail(input: PathBuf, output: PathBuf, size: (u32, u32)) -> Result<(), String> {
-//     println!("Creating thumbnail: input={input:?}, output={output:?}, size={size:?}");
-
-//     tokio::task::spawn_blocking(move || -> Result<(), String> {
-//         let img = image::open(&input).map_err(|e| {
-//             eprintln!("Failed to open image: {e}");
-//             e.to_string()
-//         })?;
-
-//         let width = img.width() as usize;
-//         let height = img.height() as usize;
-//         let bytes_per_pixel = 3;
-//         let src_stride = width * bytes_per_pixel;
-
-//         let rgb_img = img.to_rgb8();
-//         let img_buffer = rgb_img.as_raw();
-
-//         let mut corrected_buffer = vec![0u8; height * src_stride];
-
-//         for y in 0..height {
-//             let src_slice = &img_buffer[y * src_stride..(y + 1) * src_stride];
-//             let dst_slice = &mut corrected_buffer[y * src_stride..(y + 1) * src_stride];
-//             dst_slice.copy_from_slice(src_slice);
-//         }
-
-//         let corrected_img =
-//             image::RgbImage::from_raw(width as u32, height as u32, corrected_buffer)
-//                 .ok_or("Failed to create corrected image")?;
-
-//         let thumbnail = image::imageops::resize(
-//             &corrected_img,
-//             size.0,
-//             size.1,
-//             image::imageops::FilterType::Lanczos3,
-//         );
-
-//         thumbnail
-//             .save_with_format(&output, image::ImageFormat::Png)
-//             .map_err(|e| {
-//                 eprintln!("Failed to save thumbnail: {e}");
-//                 e.to_string()
-//             })?;
-
-//         println!("Thumbnail created successfully");
-//         Ok(())
-//     })
-//     .await
-//     .map_err(|e| format!("Task join error: {e}"))?
-// }
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-async fn copy_file_to_path(app: AppHandle, src: String, dst: String) -> Result<(), String> {
-    run_command_safely("copy_file_to_path", copy_file_to_path_inner(app, src, dst)).await
-}
-
-async fn copy_file_to_path_inner(app: AppHandle, src: String, dst: String) -> Result<(), String> {
-    info!(%src, %dst, "Attempting to copy file");
-
-    let is_screenshot = src.contains("screenshots/");
-    let is_gif = src.ends_with(".gif") || dst.ends_with(".gif");
-
-    let src_path = std::path::Path::new(&src);
-    if !src_path.exists() {
-        return Err(format!("Source file {src} does not exist"));
-    }
-
-    if !is_screenshot && !is_gif && !is_valid_video(src_path) {
-        let mut attempts = 0;
-        while attempts < 10 {
-            // Replaced `std::thread::sleep` with `tokio::time::sleep` — the previous version
-            // blocked the tokio worker for up to 10 seconds, which on release builds with
-            // smaller worker pools could starve the runtime and cause unrelated tasks to time
-            // out (including window/IPC events).
-            tokio::time::sleep(std::time::Duration::from_secs(1)).await;
-            if is_valid_video(src_path) {
-                break;
-            }
-            attempts += 1;
-        }
-        if attempts == 10 {
-            return Err("Source video file is not a valid MP4".to_string());
-        }
-    }
-
-    if let Some(parent) = std::path::Path::new(&dst).parent() {
-        tokio::fs::create_dir_all(parent)
-            .await
-            .map_err(|e| format!("Failed to create target directory: {e}"))?;
-    }
-
-    let mut attempts = 0;
-    const MAX_ATTEMPTS: u32 = 3;
-    let mut last_error = None;
-
-    while attempts < MAX_ATTEMPTS {
-        match tokio::fs::copy(&src, &dst).await {
-            Ok(bytes) => {
-                let src_size = match tokio::fs::metadata(&src).await {
-                    Ok(metadata) => metadata.len(),
-                    Err(e) => {
-                        last_error = Some(format!("Failed to get source file metadata: {e}"));
-                        attempts += 1;
-                        tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
-                        continue;
-                    }
-                };
-
-                if bytes != src_size {
-                    last_error = Some(format!(
-                        "File copy verification failed: copied {bytes} bytes but source is {src_size} bytes"
-                    ));
-                    let _ = tokio::fs::remove_file(&dst).await;
-                    attempts += 1;
-                    tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
-                    continue;
-                }
-
-                if !is_screenshot && !is_gif && !is_valid_video(std::path::Path::new(&dst)) {
-                    last_error = Some("Destination file is not a valid".to_string());
-                    let _ = tokio::fs::remove_file(&dst).await;
-                    attempts += 1;
-                    tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
-                    continue;
-                }
-
-                info!(bytes, %src, %dst, "Successfully copied file");
-
-                notifications::send_notification(
-                    &app,
-                    if is_screenshot {
-                        notifications::NotificationType::ScreenshotSaved
-                    } else {
-                        notifications::NotificationType::VideoSaved
-                    },
-                );
-                return Ok(());
-            }
-            Err(e) => {
-                last_error = Some(e.to_string());
-                attempts += 1;
-                if attempts < MAX_ATTEMPTS {
-                    tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
-                    continue;
-                }
-            }
-        }
-    }
-
-    let last_error_message = last_error
-        .as_deref()
-        .unwrap_or("Maximum retry attempts exceeded");
-    error!(
-        %src,
-        %dst,
-        attempts = MAX_ATTEMPTS,
-        error = %last_error_message,
-        "Failed to copy file after retries"
-    );
-
-    notifications::send_notification(
-        &app,
-        if is_screenshot {
-            notifications::NotificationType::ScreenshotSaveFailed
-        } else {
-            notifications::NotificationType::VideoSaveFailed
-        },
-    );
-
-    Err(last_error.unwrap_or_else(|| "Maximum retry attempts exceeded".to_string()))
-}
-
-pub fn is_valid_video(path: &std::path::Path) -> bool {
-    match ffmpeg::format::input(path) {
-        Ok(input_context) => {
-            // Check if we have at least one video stream
-            input_context
-                .streams()
-                .any(|stream| stream.parameters().medium() == ffmpeg::media::Type::Video)
-        }
-        Err(_) => false,
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(clipboard))]
-async fn copy_screenshot_to_clipboard(
-    clipboard: MutableState<'_, ClipboardContext>,
-    path: String,
-) -> Result<(), String> {
-    println!("Copying screenshot to clipboard: {path:?}");
-
-    let img_data = clipboard_rs::RustImageData::from_path(&path)
-        .map_err(|e| format!("Failed to copy screenshot to clipboard: {e}"))?;
-    clipboard
-        .write()
-        .await
-        .set_image(img_data)
-        .map_err(|err| format!("Failed to copy screenshot to clipboard: {err}"))?;
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(clipboard, data))]
-async fn copy_image_to_clipboard(
-    clipboard: MutableState<'_, ClipboardContext>,
-    data: Vec,
-) -> Result<(), String> {
-    println!("Copying image to clipboard ({} bytes)", data.len());
-
-    let img_data = clipboard_rs::RustImageData::from_bytes(&data)
-        .map_err(|e| format!("Failed to create image data from bytes: {e}"))?;
-    clipboard
-        .write()
-        .await
-        .set_image(img_data)
-        .map_err(|err| format!("Failed to copy image to clipboard: {err}"))?;
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(clipboard, instance))]
-async fn copy_rendered_screenshot_to_clipboard(
-    clipboard: MutableState<'_, ClipboardContext>,
-    instance: WindowScreenshotEditorInstance,
-) -> Result<(), String> {
-    let data = render_screenshot_png(&instance).await?;
-
-    let img_data = clipboard_rs::RustImageData::from_bytes(&data)
-        .map_err(|e| format!("Failed to create image data from bytes: {e}"))?;
-    clipboard
-        .write()
-        .await
-        .set_image(img_data)
-        .map_err(|err| format!("Failed to copy image to clipboard: {err}"))?;
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(_app))]
-async fn open_file_path(_app: AppHandle, path: PathBuf) -> Result<(), String> {
-    let path_str = path.to_str().ok_or("Invalid path")?;
-    let is_dir = path.is_dir();
-
-    #[cfg(target_os = "windows")]
-    {
-        if is_dir {
-            Command::new("explorer")
-                .arg(path_str)
-                .spawn()
-                .map_err(|e| format!("Failed to open folder: {e}"))?;
-        } else {
-            Command::new("explorer")
-                .args(["/select,", path_str])
-                .spawn()
-                .map_err(|e| format!("Failed to open folder: {e}"))?;
-        }
-    }
-
-    #[cfg(target_os = "macos")]
-    {
-        if is_dir {
-            Command::new("open")
-                .arg(path_str)
-                .spawn()
-                .map_err(|e| format!("Failed to open folder: {e}"))?;
-        } else {
-            Command::new("open")
-                .arg("-R")
-                .arg(path_str)
-                .spawn()
-                .map_err(|e| format!("Failed to open folder: {e}"))?;
-        }
-    }
-
-    #[cfg(target_os = "linux")]
-    {
-        if is_dir {
-            Command::new("xdg-open")
-                .arg(path_str)
-                .spawn()
-                .map_err(|e| format!("Failed to open folder: {e}"))?;
-        } else {
-            Command::new("xdg-open")
-                .arg(
-                    path.parent()
-                        .ok_or("Invalid path")?
-                        .to_str()
-                        .ok_or("Invalid path")?,
-                )
-                .spawn()
-                .map_err(|e| format!("Failed to open folder: {e}"))?;
-        }
-    }
-
-    Ok(())
-}
-
-/// The opener's Linux backend makes blocking zbus calls, which panic inside an async task.
-pub(crate) async fn reveal_in_dir(app: AppHandle, path: PathBuf) -> Result<(), String> {
-    cap_utils::run_on_dedicated_thread("reveal-item-in-dir", move || {
-        app.opener().reveal_item_in_dir(path)
-    })
-    .await
-    .map_err(|e| e.to_string())?
-    .map_err(|e| e.to_string())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-async fn reveal_item_in_dir(app: AppHandle, path: PathBuf) -> Result<(), String> {
-    reveal_in_dir(app, path)
-        .await
-        .map_err(|e| format!("Failed to reveal item: {e}"))
-}
-
-#[derive(Deserialize, specta::Type, tauri_specta::Event, Debug, Clone)]
-struct RenderFrameEvent {
-    frame_number: u32,
-    fps: u32,
-    resolution_base: XY,
-}
-
-#[derive(Serialize, specta::Type, tauri_specta::Event, Debug, Clone)]
-struct EditorStateChanged {
-    playhead_position: u32,
-}
-
-/// Rendered display/camera placement of the latest preview frame, in
-/// output-frame pixels — consumed by the editor's on-canvas layout overlay.
-#[derive(Serialize, specta::Type, tauri_specta::Event, Debug, Clone, PartialEq)]
-pub(crate) struct FrameLayoutEvent {
-    display: [f32; 4],
-    camera: Option<[f32; 4]>,
-    output_width: u32,
-    output_height: u32,
-}
-
-impl From for FrameLayoutEvent {
-    fn from(layout: cap_editor::FrameLayout) -> Self {
-        Self {
-            display: layout.display,
-            camera: layout.camera,
-            output_width: layout.output_size[0],
-            output_height: layout.output_size[1],
-        }
-    }
-}
-
-impl EditorStateChanged {
-    fn new(s: &EditorState) -> Self {
-        Self {
-            playhead_position: s.playhead_position,
-        }
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(editor_instance))]
-async fn start_playback(
-    editor_instance: WindowEditorInstance,
-    fps: u32,
-    resolution_base: XY,
-) -> Result<(), String> {
-    editor_instance.start_playback(fps, resolution_base).await;
-
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(editor_instance))]
-async fn stop_playback(editor_instance: WindowEditorInstance) -> Result<(), String> {
-    let mut state = editor_instance.state.lock().await;
-
-    if let Some(handle) = state.playback_task.take() {
-        handle.stop();
-    }
-
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-async fn commit_editor_preparing_frame(
-    editor_instance: WindowEditorInstance,
-    instance_id: String,
-    frame_number: u32,
-    fps: u32,
-) -> Result {
-    editor_instance.commit_preparing_frame(&instance_id, frame_number, fps)
-}
-
-#[tauri::command]
-#[specta::specta]
-async fn start_editor_handoff_playback(
-    editor_instance: WindowEditorInstance,
-    instance_id: String,
-    frame_number: u32,
-    fps: u32,
-    resolution_base: XY,
-) -> Result {
-    editor_instance
-        .start_handoff_playback(&instance_id, frame_number, fps, resolution_base)
-        .await
-}
-
-#[tauri::command]
-#[specta::specta]
-async fn stop_editor_handoff_playback(
-    editor_instance: WindowEditorInstance,
-    instance_id: String,
-    playback_id: String,
-) -> Result<(), String> {
-    editor_instance
-        .stop_handoff_playback(&instance_id, &playback_id)
-        .await
-}
-
-#[derive(Serialize, Type, Debug)]
-#[serde(rename_all = "camelCase")]
-struct SerializedEditorInstance {
-    instance_id: String,
-    preparing_playback: bool,
-    frames_socket_url: String,
-    preparing_snapshot: Option,
-    recording_duration: f64,
-    saved_project_config: ProjectConfiguration,
-    recordings: Arc,
-    path: PathBuf,
-    /// Notch geometry the overlay uses when the project sets no manual
-    /// placement: this recording's own measurements where the recorder took
-    /// them, else a stock MacBook notch for the editor to start from.
-    notch_base: cap_project::DisplayNotch,
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(window))]
-async fn create_editor_instance(window: Window) -> Result {
-    let CapWindowId::Editor { id } =
-        CapWindowId::from_str(window.label()).map_err(|e| e.to_string())?
-    else {
-        return Err("Invalid window".to_string());
-    };
-
-    let path = {
-        let window_ids = EditorWindowIds::get(window.app_handle());
-        let window_ids = window_ids.ids.lock().unwrap();
-
-        let Some((path, _)) = window_ids.iter().find(|(_, _id)| *_id == id) else {
-            return Err("Editor instance not found".to_string());
-        };
-        path.clone()
-    };
-
-    let editor_instance = EditorInstances::get_or_create(&window, path).await?;
-
-    Ok(SerializedEditorInstance {
-        instance_id: editor_instance.instance_id.to_string(),
-        preparing_playback: editor_instance.preparing_adoption().is_some(),
-        preparing_snapshot: window
-            .state::()
-            .snapshot_for_window(id),
-        frames_socket_url: format!("ws://localhost:{}", editor_instance.ws_port),
-        recording_duration: editor_instance.recordings.duration(),
-        saved_project_config: {
-            let project_config = editor_instance.project_config.1.borrow();
-            project_config.clone()
-        },
-        recordings: editor_instance.recordings.clone(),
-        path: editor_instance.project_path.clone(),
-        notch_base: editor_instance
-            .render_constants
-            .meta
-            .display_notch()
-            .unwrap_or(cap_project::DEFAULT_MACBOOK_NOTCH),
-    })
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(window))]
-async fn get_editor_project_path(window: Window) -> Result {
-    let CapWindowId::Editor { id } =
-        CapWindowId::from_str(window.label()).map_err(|e| e.to_string())?
-    else {
-        return Err("Invalid window".to_string());
-    };
-
-    let window_ids = EditorWindowIds::get(window.app_handle());
-    let window_ids = window_ids.ids.lock().unwrap();
-
-    let Some((path, _)) = window_ids.iter().find(|(_, _id)| *_id == id) else {
-        return Err("Editor instance not found".to_string());
-    };
-
-    Ok(path.clone())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(editor))]
-async fn get_editor_meta(editor: WindowEditorInstance) -> Result {
-    let path = editor.project_path.clone();
-    RecordingMeta::load_for_project(&path).map_err(|e| e.to_string())
-}
-
-#[tauri::command]
-#[specta::specta]
-async fn get_recording_meta_by_path(project_path: PathBuf) -> Result {
-    RecordingMeta::load_for_project(&project_path).map_err(|e| e.to_string())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(editor))]
-async fn set_pretty_name(editor: WindowEditorInstance, pretty_name: String) -> Result<(), String> {
-    let mut meta = editor.meta().clone();
-    meta.pretty_name = pretty_name;
-    meta.save_for_project().map_err(|e| e.to_string())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app, clipboard))]
-async fn copy_video_to_clipboard(
-    app: AppHandle,
-    clipboard: MutableState<'_, ClipboardContext>,
-    path: String,
-) -> Result<(), String> {
-    println!("copying");
-    let _ = clipboard.write().await.set_files(vec![path]);
-
-    notifications::send_notification(
-        &app,
-        notifications::NotificationType::VideoCopiedToClipboard,
-    );
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument]
-async fn get_video_metadata(path: PathBuf) -> Result {
-    let recording_meta = RecordingMeta::load_for_project(&path).map_err(|v| v.to_string())?;
-
-    fn get_duration_for_path(path: PathBuf) -> Result {
-        let input =
-            ffmpeg::format::input(&path).map_err(|e| format!("Failed to open video file: {e}"))?;
-
-        let raw_duration = input.duration();
-        if raw_duration <= 0 {
-            return Err(format!(
-                "Unknown or invalid duration for video file: {path:?}"
-            ));
-        }
-
-        let duration = raw_duration as f64 / AV_TIME_BASE as f64;
-        Ok(duration)
-    }
-
-    let display_paths = match &recording_meta.inner {
-        RecordingMetaInner::Instant(_) => {
-            vec![path.join("content/output.mp4")]
-        }
-        RecordingMetaInner::Studio(meta) => {
-            let status = meta.status();
-            if let StudioRecordingStatus::Failed { .. } = status {
-                return Err("Unable to get metadata on failed recording".to_string());
-            } else if let StudioRecordingStatus::InProgress = status {
-                return Err("Unable to get metadata on in-progress recording".to_string());
-            }
-
-            match &**meta {
-                StudioRecordingMeta::SingleSegment { segment } => {
-                    vec![recording_meta.path(&segment.display.path)]
-                }
-                StudioRecordingMeta::MultipleSegments { inner } => inner
-                    .segments
-                    .iter()
-                    .map(|s| recording_meta.path(&s.display.path))
-                    .collect(),
-            }
-        }
-    };
-
-    let duration = display_paths
-        .into_iter()
-        .map(get_duration_for_path)
-        .try_fold(0f64, |acc, item| -> Result {
-            let d = item?;
-            Ok(acc + d)
-        })?;
-
-    let (width, height) = (1920, 1080);
-    let fps = 30;
-
-    let base_bitrate = if width <= 1280 && height <= 720 {
-        4_000_000.0
-    } else if width <= 1920 && height <= 1080 {
-        8_000_000.0
-    } else if width <= 2560 && height <= 1440 {
-        14_000_000.0
-    } else {
-        20_000_000.0
-    };
-
-    let fps_factor = (fps as f64) / 30.0;
-    let video_bitrate = base_bitrate * fps_factor;
-    let audio_bitrate = 192_000.0;
-    let total_bitrate = video_bitrate + audio_bitrate;
-    let estimated_size_mb = (total_bitrate * duration) / (8.0 * 1024.0 * 1024.0);
-
-    Ok(VideoRecordingMetadata {
-        size: estimated_size_mb,
-        duration,
-    })
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-fn close_recordings_overlay_window(app: AppHandle) {
-    #[cfg(target_os = "macos")]
-    {
-        let app_for_close = app.clone();
-        app.run_on_main_thread(move || {
-            use tauri_nspanel::ManagerExt;
-            if let Ok(panel) =
-                app_for_close.get_webview_panel(&CapWindowId::RecordingsOverlay.label())
-            {
-                panel.released_when_closed(false);
-                panel.close();
-            }
-        })
-        .ok();
-    }
-
-    if !cfg!(target_os = "macos")
-        && let Some(window) = CapWindowId::RecordingsOverlay.get(&app)
-    {
-        let _ = window.close();
-    }
-}
-
-#[tauri::command(async)]
-#[specta::specta]
-#[instrument(skip(_app))]
-fn focus_captures_panel(_app: AppHandle) {
-    #[cfg(target_os = "macos")]
-    {
-        let app_for_focus = _app.clone();
-        _app.run_on_main_thread(move || {
-            use tauri_nspanel::ManagerExt;
-            if let Ok(panel) =
-                app_for_focus.get_webview_panel(&CapWindowId::RecordingsOverlay.label())
-            {
-                panel.make_key_window();
-            }
-        })
-        .ok();
-    }
-}
-
-#[derive(Serialize, Deserialize, specta::Type, Clone)]
-#[serde(tag = "type", rename_all = "camelCase")]
-pub struct FramesRendered {
-    rendered_count: u32,
-    total_frames: u32,
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(editor_instance))]
-async fn set_playhead_position(
-    editor_instance: WindowEditorInstance,
-    frame_number: u32,
-) -> Result<(), String> {
-    editor_instance
-        .modify_and_emit_state(|state| {
-            state.playhead_position = frame_number;
-        })
-        .await;
-
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(editor_instance))]
-async fn set_project_config(
-    editor_instance: WindowEditorInstance,
-    config: ProjectConfiguration,
-) -> Result<(), String> {
-    editor_instance.project_config.0.send(config.clone()).ok();
-
-    config
-        .write(&editor_instance.project_path)
-        .map_err(|error| format!("Failed to write project config: {error}"))?;
-
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(editor_instance))]
-async fn update_project_config_in_memory(
-    editor_instance: WindowEditorInstance,
-    config: ProjectConfiguration,
-    frame_number: Option,
-    fps: Option,
-    resolution_base: Option>,
-) -> Result<(), String> {
-    editor_instance.project_config.0.send(config).ok();
-    if let (Some(frame), Some(f), Some(res)) = (frame_number, fps, resolution_base) {
-        editor_instance.preview_tx.send_modify(|v| {
-            *v = Some((frame, f, res));
-        });
-    }
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app, editor_instance))]
-async fn generate_zoom_segments_from_clicks(
-    app: AppHandle,
-    editor_instance: WindowEditorInstance,
-) -> Result, String> {
-    let meta = editor_instance.meta();
-    let recordings = &editor_instance.recordings;
-
-    let zoom_amount = GeneralSettingsStore::get(&app)
-        .ok()
-        .flatten()
-        .and_then(|settings| settings.default_zoom_amount)
-        .unwrap_or(recording::DEFAULT_AUTO_ZOOM_AMOUNT);
-
-    let zoom_segments =
-        recording::generate_zoom_segments_for_project(meta, recordings, zoom_amount);
-
-    Ok(zoom_segments)
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(editor_instance))]
-async fn generate_keyboard_segments(
-    editor_instance: WindowEditorInstance,
-    grouping_threshold_ms: f64,
-    linger_duration_ms: f64,
-    show_modifiers: bool,
-    show_special_keys: bool,
-) -> Result, String> {
-    let project = editor_instance.project_config.1.borrow().clone();
-    let Some(timeline) = project.timeline else {
-        return Ok(Vec::new());
-    };
-    let settings = cap_project::KeyboardSettings {
-        grouping_threshold_ms,
-        linger_duration: (linger_duration_ms / 1000.0) as f32,
-        show_modifiers,
-        show_special_keys,
-        ..Default::default()
-    };
-    let meta = editor_instance.meta().clone();
-    tokio::task::spawn_blocking(move || {
-        cap_project::generate_project_keyboard_segments(&meta, &timeline, &settings)
-    })
-    .await
-    .map_err(|error| format!("Keyboard generation failed: {error}"))?
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument]
-async fn list_audio_devices() -> Result, ()> {
-    if !permissions::do_permissions_check(false)
-        .microphone
-        .permitted()
-    {
-        return Ok(vec![]);
-    }
-
-    Ok(MicrophoneFeed::list_names())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument]
-async fn list_system_fonts() -> Vec {
-    tokio::task::spawn_blocking(cap_rendering::system_font_families)
-        .await
-        .unwrap_or_default()
-}
-
-#[derive(Serialize, Type, Debug, Clone)]
-pub struct UploadProgress {
-    progress: f64,
-}
-
-#[derive(Debug, Deserialize, Type)]
-pub enum UploadMode {
-    Initial {
-        pre_created_video: Option,
-    },
-    Reupload,
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app, channel))]
-async fn upload_exported_video(
-    app: AppHandle,
-    path: PathBuf,
-    mode: UploadMode,
-    channel: Channel,
-    organization_id: Option,
-) -> Result {
-    let Ok(Some(auth)) = AuthStore::get(&app) else {
-        AuthStore::set(&app, None).map_err(|e| e.to_string())?;
-        return Ok(UploadResult::NotAuthenticated);
-    };
-
-    let mut meta = RecordingMeta::load_for_project(&path).map_err(|v| v.to_string())?;
-
-    if matches!(meta.inner, RecordingMetaInner::Instant(_)) {
-        match upload::lifecycle::retry_existing(app.clone(), &path).await {
-            Ok(Some(link)) => return Ok(UploadResult::Success(link)),
-            Ok(None) => {}
-            Err(AuthedApiError::InvalidAuthentication) => {
-                return Ok(UploadResult::NotAuthenticated);
-            }
-            Err(error) => return Err(error.to_string()),
-        }
-    }
-
-    let file_path = meta.output_path();
-    if !file_path.exists() {
-        notifications::send_notification(&app, notifications::NotificationType::UploadFailed);
-        return Err("Failed to upload video: Rendered video not found".to_string());
-    }
-
-    let metadata = build_video_meta(&file_path)
-        .map_err(|err| format!("Error getting output video meta: {err}"))?;
-
-    if !auth.is_upgraded() && metadata.duration_in_secs > 300.0 {
-        return Ok(UploadResult::UpgradeRequired);
-    }
-
-    channel.send(UploadProgress { progress: 0.0 }).ok();
-
-    let existing_video_id = upload::reusable_video_id(meta.sharing.as_ref(), meta.upload.as_ref());
-    let (s3_config, created_link) = match async {
-        let video_id = match mode {
-            UploadMode::Initial { pre_created_video } => {
-                if let Some(video_id) = existing_video_id.clone() {
-                    Some(video_id)
-                } else if let Some(pre_created) = pre_created_video {
-                    return Ok((pre_created.config, Some(pre_created.link)));
-                } else {
-                    None
-                }
-            }
-            UploadMode::Reupload => {
-                let Some(sharing) = meta.sharing.clone() else {
-                    return Err("No sharing metadata found".into());
-                };
-
-                Some(sharing.id)
-            }
-        };
-
-        let created = create_or_get_video(
-            &app,
-            false,
-            video_id,
-            Some(meta.pretty_name.clone()),
-            Some(metadata.clone()),
-            organization_id,
-        )
-        .await?;
-        Ok((created.config, created.share_url))
-    }
-    .await
-    {
-        Ok(data) => data,
-        Err(AuthedApiError::InvalidAuthentication) => return Ok(UploadResult::NotAuthenticated),
-        Err(AuthedApiError::UpgradeRequired) => return Ok(UploadResult::UpgradeRequired),
-        Err(err) => return Err(err.to_string()),
-    };
-
-    if existing_video_id
-        .as_ref()
-        .is_some_and(|video_id| *video_id != s3_config.id)
-    {
-        return Err("Server did not preserve the existing share link".into());
-    }
-
-    let screenshot_path = meta.project_path.join("screenshots/display.jpg");
-    meta.upload = Some(UploadMeta::SinglePartUpload {
-        video_id: s3_config.id.clone(),
-        file_path: file_path.clone(),
-        screenshot_path: screenshot_path.clone(),
-        recording_dir: path.clone(),
-    });
-    meta.save_for_project()
-        .map_err(|error| format!("Failed to persist upload state: {error}"))?;
-
-    match upload_video(
-        &app,
-        s3_config.id.clone(),
-        file_path,
-        screenshot_path,
-        meta.sharing.is_some(),
-        Some(channel.clone()),
-    )
-    .await
-    {
-        Ok(uploaded_video) => {
-            channel.send(UploadProgress { progress: 1.0 }).ok();
-
-            let link = meta
-                .sharing
-                .as_ref()
-                .map(|sharing| sharing.link.clone())
-                .or(created_link)
-                .unwrap_or(uploaded_video.link);
-
-            meta.upload = Some(UploadMeta::Complete);
-            meta.sharing = Some(SharingMeta {
-                link: link.clone(),
-                id: uploaded_video.id.clone(),
-                content_hash: None,
-            });
-            meta.save_for_project()
-                .map_err(|error| format!("Failed to persist sharing state: {error}"))?;
-
-            let _ = app
-                .state::>()
-                .write()
-                .await
-                .set_text(link.clone());
-
-            NotificationType::ShareableLinkCopied.send(&app);
-            Ok(UploadResult::Success(link))
-        }
-        Err(AuthedApiError::UpgradeRequired) => Ok(UploadResult::UpgradeRequired),
-        Err(e) => {
-            error!("Failed to upload video: {e}");
-
-            NotificationType::UploadFailed.send(&app);
-
-            meta.upload = Some(UploadMeta::Failed {
-                error: e.to_string(),
-            });
-            meta.save_for_project()
-                .map_err(|e| error!("Failed to save recording meta: {e}"))
-                .ok();
-
-            Err(e.to_string())
-        }
-    }
-}
-
-fn screenshot_project_path_from_path(path: &std::path::Path) -> Option {
-    path.ancestors()
-        .find(|ancestor| ancestor.extension().and_then(|s| s.to_str()) == Some("cap"))
-        .map(std::path::Path::to_path_buf)
-}
-
-fn load_screenshot_project_meta(
-    path: &std::path::Path,
-) -> Result<(PathBuf, RecordingMeta), String> {
-    let project_path = screenshot_project_path_from_path(path)
-        .ok_or_else(|| format!("Could not find screenshot project for {}", path.display()))?;
-    let meta = RecordingMeta::load_for_project(&project_path)
-        .map_err(|err| format!("Failed to load screenshot metadata: {err}"))?;
-    Ok((project_path, meta))
-}
-
-fn save_screenshot_sharing(
-    project_path: &std::path::Path,
-    mut meta: RecordingMeta,
-    uploaded: &upload::UploadedItem,
-    content_hash: Option,
-) -> Result<(), String> {
-    meta.sharing = Some(SharingMeta {
-        link: uploaded.link.clone(),
-        id: uploaded.id.clone(),
-        content_hash,
-    });
-    meta.save_for_project()
-        .map_err(|err| format!("Error saving project {}: {err}", project_path.display()))
-}
-
-#[derive(Serialize, Type, Debug)]
-#[serde(rename_all = "camelCase")]
-struct ScreenshotSharingState {
-    link: String,
-    content_hash: Option,
-}
-
-#[derive(Serialize, Type, Debug)]
-#[serde(rename_all = "camelCase")]
-struct ScreenshotProjectShareState {
-    config: ProjectConfiguration,
-    sharing: Option,
-}
-
-async fn copy_screenshot_share_link(
-    clipboard: &MutableState<'_, ClipboardContext>,
-    link: String,
-    app: &AppHandle,
-) -> Result<(), String> {
-    let _ = clipboard.write().await.set_text(link);
-    notifications::send_notification(app, notifications::NotificationType::ShareableLinkCopied);
-    Ok(())
-}
-
-fn screenshot_share_link_for_hash(
-    sharing: Option<&SharingMeta>,
-    content_hash: &str,
-) -> Option {
-    let sharing = sharing?;
-    if sharing.content_hash.as_deref() == Some(content_hash) {
-        return Some(sharing.link.clone());
-    }
-    None
-}
-
-async fn upgrade_required_result(app: &AppHandle) -> UploadResult {
-    if let Err(error) = open_pricing_page(app).await {
-        warn!(%error, "Failed to open pricing page");
-    }
-    UploadResult::UpgradeRequired
-}
-
-#[tauri::command]
-#[specta::specta]
-fn get_screenshot_project_share_state(
-    path: PathBuf,
-) -> Result {
-    let (project_path, meta) = load_screenshot_project_meta(&path)?;
-    let config = ProjectConfiguration::load(&project_path)
-        .map_err(|err| format!("Failed to load screenshot config: {err}"))?;
-    let sharing = meta.sharing.map(|sharing| ScreenshotSharingState {
-        link: sharing.link,
-        content_hash: sharing.content_hash,
-    });
-
-    Ok(ScreenshotProjectShareState { config, sharing })
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app, clipboard))]
-async fn copy_current_screenshot_share_link(
-    app: AppHandle,
-    clipboard: MutableState<'_, ClipboardContext>,
-    project_path: PathBuf,
-    content_hash: String,
-) -> Result, String> {
-    let (_, meta) = load_screenshot_project_meta(&project_path)?;
-    let Some(link) = screenshot_share_link_for_hash(meta.sharing.as_ref(), &content_hash) else {
-        return Ok(None);
-    };
-
-    copy_screenshot_share_link(&clipboard, link.clone(), &app).await?;
-    Ok(Some(UploadResult::Success(link)))
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app, clipboard))]
-async fn upload_screenshot(
-    app: AppHandle,
-    clipboard: MutableState<'_, ClipboardContext>,
-    screenshot_path: PathBuf,
-) -> Result {
-    let Ok(Some(auth)) = AuthStore::get(&app) else {
-        AuthStore::set(&app, None).map_err(|e| e.to_string())?;
-        return Ok(UploadResult::NotAuthenticated);
-    };
-
-    if !auth.is_upgraded() {
-        return Ok(upgrade_required_result(&app).await);
-    }
-
-    println!("Uploading screenshot: {screenshot_path:?}");
-
-    let (project_path, meta) = load_screenshot_project_meta(&screenshot_path)?;
-    if let Some(sharing) = meta.sharing.as_ref() {
-        copy_screenshot_share_link(&clipboard, sharing.link.clone(), &app).await?;
-        return Ok(UploadResult::Success(sharing.link.clone()));
-    }
-
-    let uploaded = match upload_screenshot_file(&app, screenshot_path.clone(), None, None).await {
-        Ok(uploaded) => uploaded,
-        Err(AuthedApiError::InvalidAuthentication) => return Ok(UploadResult::NotAuthenticated),
-        Err(AuthedApiError::UpgradeRequired) => return Ok(upgrade_required_result(&app).await),
-        Err(e) => return Err(e.to_string()),
-    };
-    save_screenshot_sharing(&project_path, meta, &uploaded, None)?;
-
-    println!("Copying to clipboard: {:?}", uploaded.link);
-
-    copy_screenshot_share_link(&clipboard, uploaded.link.clone(), &app).await?;
-
-    Ok(UploadResult::Success(uploaded.link))
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app, clipboard, image_bytes))]
-async fn upload_rendered_screenshot(
-    app: AppHandle,
-    clipboard: MutableState<'_, ClipboardContext>,
-    image_bytes: Vec,
-    content_type: String,
-    project_path: PathBuf,
-    content_hash: Option,
-) -> Result {
-    let Ok(Some(auth)) = AuthStore::get(&app) else {
-        AuthStore::set(&app, None).map_err(|e| e.to_string())?;
-        return Ok(UploadResult::NotAuthenticated);
-    };
-
-    if !auth.is_upgraded() {
-        return Ok(upgrade_required_result(&app).await);
-    }
-
-    let (project_path, meta) = load_screenshot_project_meta(&project_path)?;
-    let existing_video_id = meta.sharing.as_ref().map(|sharing| sharing.id.clone());
-    let uploaded =
-        match upload_screenshot_bytes(&app, image_bytes, &content_type, existing_video_id, None)
-            .await
-        {
-            Ok(uploaded) => uploaded,
-            Err(AuthedApiError::InvalidAuthentication) => {
-                return Ok(UploadResult::NotAuthenticated);
-            }
-            Err(AuthedApiError::UpgradeRequired) => return Ok(upgrade_required_result(&app).await),
-            Err(e) => return Err(e.to_string()),
-        };
-    save_screenshot_sharing(&project_path, meta, &uploaded, content_hash)?;
-
-    copy_screenshot_share_link(&clipboard, uploaded.link.clone(), &app).await?;
-
-    Ok(UploadResult::Success(uploaded.link))
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(window))]
-async fn save_file_dialog(
-    window: tauri::Window,
-    file_name: String,
-    file_type: String,
-) -> Result, String> {
-    run_command_safely(
-        "save_file_dialog",
-        save_file_dialog_inner(window, file_name, file_type),
-    )
-    .await
-}
-
-async fn save_file_dialog_inner(
-    window: tauri::Window,
-    file_name: String,
-    file_type: String,
-) -> Result, String> {
-    info!(file_name, file_type, "Save file dialog requested");
-
-    let file_name = file_name
-        .strip_suffix(".cap")
-        .unwrap_or(&file_name)
-        .to_string();
-
-    let (name, extension) = match file_type.as_str() {
-        "recording" | "mp4" => ("MP4 Video", "mp4"),
-        "gif" => ("GIF Image", "gif"),
-        "mov" => ("MOV Video", "mov"),
-        "screenshot" | "png" => ("PNG Image", "png"),
-        "srt" => ("SubRip Subtitle", "srt"),
-        "vtt" => ("WebVTT", "vtt"),
-        _ => {
-            warn!(file_type, "Invalid save file dialog type");
-            return Err("Invalid file type".to_string());
-        }
-    };
-
-    info!(file_name, name, extension, "Showing save file dialog");
-
-    #[cfg(target_os = "linux")]
-    let path = export::show_linux_save_dialog(
-        window.clone(),
-        tokio_util::sync::CancellationToken::new(),
-        file_name,
-        name,
-        extension,
-    )
-    .await?;
-    #[cfg(target_os = "macos")]
-    let path = export::show_macos_save_dialog(window.app_handle(), file_name, extension).await?;
-    #[cfg(not(any(target_os = "linux", target_os = "macos")))]
-    let path = {
-        use tauri_plugin_dialog::DialogExt;
-
-        let app = window.app_handle().clone();
-        // Use `tokio::sync::oneshot` so the async runtime worker yields while the native dialog
-        // is open instead of being parked by a synchronous `std::sync::mpsc` receive. The
-        // previous version blocked a runtime worker for the lifetime of the dialog which, in
-        // release builds with fewer/active workers, could starve other tasks and let an unrelated
-        // exit event slip through before the export session guard incremented.
-        let (tx, rx) = tokio::sync::oneshot::channel();
-
-        app.dialog()
-            .file()
-            .set_title("Save File")
-            .set_file_name(file_name)
-            .add_filter(name, &[extension])
-            .save_file(move |path| {
-                let _ = tx.send(
-                    path.as_ref()
-                        .and_then(|p| p.as_path())
-                        .map(std::path::PathBuf::from),
-                );
-            });
-
-        match rx.await {
-            Ok(result) => {
-                info!(path = ?result, "Save file dialog completed");
-                result
-            }
-            Err(e) => {
-                warn!(error = %e, "Save file dialog failed");
-                notifications::send_notification(
-                    &app,
-                    notifications::NotificationType::VideoSaveFailed,
-                );
-                return Err(e.to_string());
-            }
-        }
-    };
-    if let Some(path) = &path {
-        use tauri_plugin_fs::FsExt;
-        if let Some(scope) = window.try_fs_scope() {
-            scope.allow_file(path).map_err(|error| error.to_string())?;
-        }
-        window
-            .state::()
-            .allow_file(path)
-            .map_err(|error| error.to_string())?;
-    }
-    Ok(path.map(|path| path.to_string_lossy().into_owned()))
-}
-
-#[derive(Serialize, specta::Type)]
-pub struct RecordingMetaWithMetadata {
-    #[serde(flatten)]
-    pub inner: RecordingMeta,
-    // Easier accessors for within webview
-    // THESE MUST COME AFTER `inner` to override flattened fields with the same name
-    pub mode: RecordingMode,
-    pub status: StudioRecordingStatus,
-    // Number of recorded takes (segments) the recording is made up of.
-    pub clip_count: u32,
-    pub sort_time_millis: f64,
-}
-
-impl RecordingMetaWithMetadata {
-    fn new(inner: RecordingMeta, sort_time_millis: f64) -> Self {
-        Self {
-            mode: match &inner.inner {
-                RecordingMetaInner::Studio(_) => RecordingMode::Studio,
-                RecordingMetaInner::Instant(_) => RecordingMode::Instant,
-            },
-            clip_count: match &inner.inner {
-                RecordingMetaInner::Studio(meta) => match &**meta {
-                    StudioRecordingMeta::MultipleSegments { inner } => inner.segments.len() as u32,
-                    StudioRecordingMeta::SingleSegment { .. } => 1,
-                },
-                RecordingMetaInner::Instant(_) => 1,
-            },
-            status: match &inner.inner {
-                RecordingMetaInner::Studio(meta) => match &**meta {
-                    StudioRecordingMeta::MultipleSegments { inner } => inner
-                        .status
-                        .clone()
-                        .unwrap_or(StudioRecordingStatus::Complete),
-                    StudioRecordingMeta::SingleSegment { .. } => StudioRecordingStatus::Complete,
-                },
-                RecordingMetaInner::Instant(InstantRecordingMeta::InProgress { .. }) => {
-                    StudioRecordingStatus::InProgress
-                }
-                RecordingMetaInner::Instant(InstantRecordingMeta::Failed { error }) => {
-                    StudioRecordingStatus::Failed {
-                        error: error.clone(),
-                    }
-                }
-                RecordingMetaInner::Instant(InstantRecordingMeta::Complete { .. }) => {
-                    StudioRecordingStatus::Complete
-                }
-            },
-            sort_time_millis,
-            inner,
-        }
-    }
-}
-
-#[derive(Serialize, specta::Type)]
-pub struct ScreenshotMetaWithMetadata {
-    #[serde(flatten)]
-    pub inner: RecordingMeta,
-    pub sort_time_millis: f64,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, Type, PartialEq, Eq)]
-#[serde(rename_all = "lowercase")]
-pub enum FileType {
-    Recording,
-    Screenshot,
-}
-
-#[tauri::command(async)]
-#[specta::specta]
-#[instrument]
-fn get_recording_meta(
-    path: PathBuf,
-    _file_type: FileType,
-) -> Result {
-    let sort_time_millis = media_sort_time_millis(&path);
-    RecordingMeta::load_for_project(&path)
-        .map(|meta| RecordingMetaWithMetadata::new(meta, sort_time_millis))
-        .map_err(|e| format!("Failed to load recording meta: {e}"))
-}
-
-fn media_sort_time(path: &Path) -> SystemTime {
-    let Ok(metadata) = path.metadata() else {
-        return UNIX_EPOCH;
-    };
-
-    metadata
-        .created()
-        .or_else(|_| metadata.modified())
-        .unwrap_or(UNIX_EPOCH)
-}
-
-fn media_sort_time_millis(path: &Path) -> f64 {
-    media_sort_time(path)
-        .duration_since(UNIX_EPOCH)
-        .unwrap_or_default()
-        .as_secs_f64()
-        * 1000.0
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-async fn list_recordings(
-    app: AppHandle,
-) -> Result, String> {
-    tokio::task::spawn_blocking(move || list_recordings_inner(&app, usize::MAX))
-        .await
-        .map_err(|error| error.to_string())
-}
-
-#[tauri::command]
-#[specta::specta]
-async fn list_recent_recordings(
-    app: AppHandle,
-) -> Result, String> {
-    tokio::task::spawn_blocking(move || list_recordings_inner(&app, 9))
-        .await
-        .map_err(|error| error.to_string())
-}
-
-fn newest_valid_media(
-    mut candidates: Vec<(T, f64)>,
-    limit: usize,
-    mut load: impl FnMut(T, f64) -> Option,
-) -> Vec {
-    candidates.sort_by(|(_, a), (_, b)| b.total_cmp(a));
-    candidates
-        .into_iter()
-        .filter_map(|(candidate, timestamp)| load(candidate, timestamp))
-        .take(limit)
-        .collect()
-}
-
-fn list_recordings_inner(
-    app: &AppHandle,
-    limit: usize,
-) -> Vec<(PathBuf, RecordingMetaWithMetadata)> {
-    // Recordings can live in multiple folders (the active one, the default
-    // one, and any previously used custom folders) — scan them all so
-    // switching the storage folder never hides existing recordings.
-    let mut result = Vec::new();
-    for recordings_dir in recordings_locations::known_recordings_dirs(app) {
-        let Ok(entries) = std::fs::read_dir(&recordings_dir) else {
-            continue;
-        };
-
-        for entry in entries.flatten() {
-            let path = entry.path();
-
-            if !path.is_dir() {
-                continue;
-            }
-
-            let timestamp = media_sort_time_millis(&path);
-            result.push((path, timestamp));
-        }
-    }
-
-    newest_valid_media(result, limit, |path, timestamp| {
-        let meta = RecordingMeta::load_for_project(&path).ok()?;
-        Some((path, RecordingMetaWithMetadata::new(meta, timestamp)))
-    })
-}
-
-fn acquire_recording_delete_lock(
-    path: &std::path::Path,
-) -> Result {
-    cap_recording::upload_resume::UploadLock::acquire(path).map_err(|error| error.to_string())
-}
-
-fn recording_delete_target(
-    recordings_dirs: &[PathBuf],
-    path: &Path,
-) -> Result, String> {
-    if path
-        .components()
-        .any(|component| matches!(component, std::path::Component::ParentDir))
-    {
-        return Err("Invalid path".to_string());
-    }
-
-    let canonical_dirs: Vec<_> = recordings_dirs
-        .iter()
-        .filter_map(|dir| dir.canonicalize().ok())
-        .collect();
-    if recordings_dirs
-        .iter()
-        .chain(&canonical_dirs)
-        .any(|dir| path == dir)
-    {
-        return Err("Path is not inside a recordings directory".to_string());
-    }
-
-    if path
-        .try_exists()
-        .map_err(|error| format!("Failed to inspect recording path: {error}"))?
-    {
-        let canonical_path = path
-            .canonicalize()
-            .map_err(|error| format!("Failed to resolve recording path: {error}"))?;
-        if canonical_dirs.iter().any(|dir| &canonical_path == dir)
-            || !canonical_dirs
-                .iter()
-                .any(|dir| canonical_path.starts_with(dir))
-        {
-            return Err("Path is not inside a recordings directory".to_string());
-        }
-        Ok(Some(canonical_path))
-    } else if recordings_dirs
-        .iter()
-        .chain(&canonical_dirs)
-        .any(|dir| path.starts_with(dir))
-    {
-        Ok(None)
-    } else {
-        Err("Path is not inside a recordings directory".to_string())
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-async fn delete_recording_directory(app: AppHandle, path: PathBuf) -> Result<(), String> {
-    // The library lists recordings from every known storage folder, so
-    // deletion must accept the same set — but nothing outside it.
-    let recordings_dirs = recordings_locations::known_recordings_dirs(&app);
-
-    if let Some(canonical_path) = recording_delete_target(&recordings_dirs, &path)? {
-        upload::lifecycle::cancel(&canonical_path).await;
-        let ownership = acquire_recording_delete_lock(&canonical_path)?;
-        upload::lifecycle::mark_cancelled(&canonical_path).map_err(|error| error.to_string())?;
-        std::fs::remove_dir_all(&canonical_path)
-            .map_err(|error| format!("Failed to delete recording: {error}"))?;
-        drop(ownership);
-    }
-
-    let _ = RecordingDeleted { path }.emit(&app);
-
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-async fn list_screenshots(
-    app: AppHandle,
-) -> Result, String> {
-    tokio::task::spawn_blocking(move || list_screenshots_inner(&app, usize::MAX))
-        .await
-        .map_err(|error| error.to_string())?
-}
-
-#[tauri::command]
-#[specta::specta]
-async fn list_recent_screenshots(
-    app: AppHandle,
-) -> Result, String> {
-    tokio::task::spawn_blocking(move || list_screenshots_inner(&app, 9))
-        .await
-        .map_err(|error| error.to_string())?
-}
-
-fn list_screenshots_inner(
-    app: &AppHandle,
-    limit: usize,
-) -> Result, String> {
-    let screenshots_dir = screenshots_path(app);
-
-    let result = std::fs::read_dir(&screenshots_dir)
-        .map_err(|e| format!("Failed to read screenshots directory: {e}"))?
-        .filter_map(|entry| {
-            let entry = entry.ok()?;
-            let path = entry.path();
-            if path.is_dir() && path.extension().and_then(|s| s.to_str()) == Some("cap") {
-                let png_path = std::fs::read_dir(&path)
-                    .ok()?
-                    .filter_map(|e| e.ok())
-                    .find(|e| e.path().extension().and_then(|s| s.to_str()) == Some("png"))
-                    .map(|e| e.path())?;
-
-                let sort_time_millis = media_sort_time_millis(&png_path);
-                Some(((path, png_path), sort_time_millis))
-            } else {
-                None
-            }
-        })
-        .collect::>();
-
-    Ok(newest_valid_media(
-        result,
-        limit,
-        |(path, png_path), sort_time_millis| {
-            let inner = RecordingMeta::load_for_project(&path).ok()?;
-            Some((
-                png_path,
-                ScreenshotMetaWithMetadata {
-                    inner,
-                    sort_time_millis,
-                },
-            ))
-        },
-    ))
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-async fn check_upgraded_and_update(app: AppHandle) -> Result {
-    println!("Checking upgraded status and updating...");
-
-    if let Ok(Some(settings)) = GeneralSettingsStore::get(&app)
-        && settings.commercial_license.is_some()
-    {
-        return Ok(true);
-    }
-
-    let Ok(Some(auth)) = AuthStore::get(&app) else {
-        return Ok(false);
-    };
-
-    if let Some(ref plan) = auth.plan
-        && plan.manual
-    {
-        return Ok(true);
-    }
-
-    println!("Fetching plan");
-    let response = app
-        .authed_api_request("/api/desktop/plan", |client, url| client.get(url))
-        .await
-        .map_err(|e| {
-            println!("Failed to fetch plan: {e}");
-            e.to_string()
-        })?;
-
-    println!("Plan fetch response status: {}", response.status());
-    let plan_data = response.json::().await.map_err(|e| {
-        println!("Failed to parse plan response: {e}");
-        format!("Failed to parse plan response: {e}")
-    })?;
-
-    let is_pro = plan_data
-        .get("upgraded")
-        .and_then(|v| v.as_bool())
-        .unwrap_or(false);
-    println!("Pro status: {is_pro}");
-    let updated_auth = AuthStore {
-        secret: auth.secret,
-        user_id: auth.user_id,
-        plan: Some(Plan {
-            upgraded: is_pro,
-            manual: auth.plan.map(|p| p.manual).unwrap_or(false),
-            last_checked: chrono::Utc::now().timestamp() as i32,
-        }),
-        organizations: auth.organizations,
-        organizations_updated_at: auth.organizations_updated_at,
-    };
-    println!("Updating auth store with new pro status");
-    AuthStore::set(&app, Some(updated_auth)).map_err(|e| e.to_string())?;
-
-    Ok(is_pro)
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-fn open_external_link(app: tauri::AppHandle, url: String) -> Result<(), String> {
-    if let Ok(Some(settings)) = GeneralSettingsStore::get(&app)
-        && settings.disable_auto_open_links
-    {
-        return Ok(());
-    }
-
-    app.shell()
-        .open(&url, None)
-        .map_err(|e| format!("Failed to open URL: {e}"))?;
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(_app))]
-async fn reset_camera_permissions(_app: AppHandle) -> Result<(), String> {
-    #[cfg(target_os = "macos")]
-    {
-        let bundle_id = _app.config().identifier.clone();
-
-        Command::new("tccutil")
-            .arg("reset")
-            .arg("Camera")
-            .arg(bundle_id)
-            .output()
-            .map_err(|_| "Failed to reset camera permissions".to_string())?;
-    }
-
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(_app))]
-async fn reset_microphone_permissions(_app: AppHandle) -> Result<(), String> {
-    #[cfg(target_os = "macos")]
-    {
-        let bundle_id = _app.config().identifier.clone();
-
-        Command::new("tccutil")
-            .arg("reset")
-            .arg("Microphone")
-            .arg(bundle_id)
-            .output()
-            .map_err(|_| "Failed to reset microphone permissions".to_string())?;
-    }
-
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-async fn clear_presets(app: AppHandle) -> Result<(), String> {
-    presets::PresetsStore::clear(&app)
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-async fn is_camera_window_open(app: AppHandle) -> bool {
-    CapWindowId::Camera
-        .get(&app)
-        .map(|w| w.is_visible().unwrap_or(false))
-        .unwrap_or(false)
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(editor_instance))]
-async fn seek_to(editor_instance: WindowEditorInstance, frame_number: u32) -> Result<(), String> {
-    editor_instance
-        .modify_and_emit_state(|state| {
-            state.playhead_position = frame_number;
-        })
-        .await;
-
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(editor_instance))]
-async fn get_display_frame_for_cropping(
-    editor_instance: WindowEditorInstance,
-    fps: u32,
-) -> Result, String> {
-    use cap_project::ClipOffsets;
-    use cap_rendering::{PixelFormat, cpu_yuv};
-    use image::{ImageEncoder, codecs::jpeg::JpegEncoder};
-    use std::io::Cursor;
-    use std::time::Instant;
-
-    let total_started_at = Instant::now();
-
-    let frame_number = editor_instance.state.lock().await.playhead_position;
-    let time_secs = frame_number as f64 / fps as f64;
-
-    let project = editor_instance.project_config.1.borrow().clone();
-    let lookup_started_at = Instant::now();
-
-    let (segment_time, segment) = project
-        .get_segment_time(time_secs)
-        .ok_or_else(|| "No segment found for current time".to_string())?;
-
-    let segment_medias = editor_instance
-        .segment_medias
-        .get(segment.recording_clip as usize)
-        .ok_or_else(|| "Segment media not found".to_string())?;
-
-    let clip_offsets = project
-        .clips
-        .iter()
-        .find(|v| v.index == segment.recording_clip)
-        .map(|v| v.offsets)
-        .unwrap_or(ClipOffsets::default());
-    let lookup_elapsed_ms = lookup_started_at.elapsed().as_secs_f64() * 1000.0;
-
-    let decode_started_at = Instant::now();
-    let segment_frames = segment_medias
-        .decoders
-        .get_frames(segment_time as f32, false, true, clip_offsets)
-        .await
-        .ok_or_else(|| "Failed to get frame".to_string())?;
-    let decode_elapsed_ms = decode_started_at.elapsed().as_secs_f64() * 1000.0;
-
-    let screen_frame = segment_frames
-        .screen_frame
-        .ok_or_else(|| "Failed to get screen frame".to_string())?;
-    let width = screen_frame.width();
-    let height = screen_frame.height();
-
-    let convert_started_at = Instant::now();
-    let rgba_data = match screen_frame.format() {
-        PixelFormat::Rgba => screen_frame.data().to_vec(),
-        PixelFormat::Nv12 => {
-            let y_plane = screen_frame.y_plane().ok_or("Missing Y plane")?;
-            let uv_plane = screen_frame.uv_plane().ok_or("Missing UV plane")?;
-            let mut rgba = vec![0u8; (width * height * 4) as usize];
-            cpu_yuv::nv12_to_rgba(
-                y_plane,
-                uv_plane,
-                width,
-                height,
-                screen_frame.y_stride(),
-                screen_frame.uv_stride(),
-                &mut rgba,
-            );
-            rgba
-        }
-        PixelFormat::Yuv420p => {
-            let y_plane = screen_frame.y_plane().ok_or("Missing Y plane")?;
-            let u_plane = screen_frame.u_plane().ok_or("Missing U plane")?;
-            let v_plane = screen_frame.v_plane().ok_or("Missing V plane")?;
-            let mut rgba = vec![0u8; (width * height * 4) as usize];
-            cpu_yuv::yuv420p_to_rgba(
-                y_plane,
-                u_plane,
-                v_plane,
-                width,
-                height,
-                screen_frame.y_stride(),
-                screen_frame.uv_stride(),
-                &mut rgba,
-            );
-            rgba
-        }
-    };
-    let convert_elapsed_ms = convert_started_at.elapsed().as_secs_f64() * 1000.0;
-
-    let encode_started_at = Instant::now();
-
-    // The cropper maps interactions back to full display dimensions, so the
-    // reference image only needs to be sharp enough to position the crop. A
-    // downscaled JPEG keeps decode + IPC transfer near-instant even when the
-    // playhead is deep into a long recording.
-    const MAX_PREVIEW_DIM: u32 = 1440;
-
-    let rgba_image = image::RgbaImage::from_raw(width, height, rgba_data)
-        .ok_or_else(|| "Failed to build image buffer from frame".to_string())?;
-
-    let longest_side = width.max(height);
-    let resized = if longest_side > MAX_PREVIEW_DIM {
-        let scale = MAX_PREVIEW_DIM as f32 / longest_side as f32;
-        let target_w = ((width as f32 * scale).round() as u32).max(1);
-        let target_h = ((height as f32 * scale).round() as u32).max(1);
-        image::imageops::resize(
-            &rgba_image,
-            target_w,
-            target_h,
-            image::imageops::FilterType::Triangle,
-        )
-    } else {
-        rgba_image
-    };
-
-    let rgb_image = image::DynamicImage::ImageRgba8(resized).into_rgb8();
-    let out_width = rgb_image.width();
-    let out_height = rgb_image.height();
-
-    let mut jpeg_data = Cursor::new(Vec::new());
-    JpegEncoder::new_with_quality(&mut jpeg_data, 82)
-        .write_image(
-            rgb_image.as_raw(),
-            out_width,
-            out_height,
-            image::ExtendedColorType::Rgb8,
-        )
-        .map_err(|e| format!("Failed to encode JPEG: {e}"))?;
-    let encode_elapsed_ms = encode_started_at.elapsed().as_secs_f64() * 1000.0;
-    let total_elapsed_ms = total_started_at.elapsed().as_secs_f64() * 1000.0;
-
-    debug!(
-        target: "cap_crop_profile",
-        frame_number = frame_number,
-        time_secs = time_secs,
-        segment_time = segment_time,
-        width = width,
-        height = height,
-        out_width = out_width,
-        out_height = out_height,
-        lookup_ms = lookup_elapsed_ms,
-        decode_ms = decode_elapsed_ms,
-        convert_ms = convert_elapsed_ms,
-        encode_ms = encode_elapsed_ms,
-        total_ms = total_elapsed_ms,
-        "crop frame profile"
-    );
-
-    Ok(jpeg_data.into_inner())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(editor_instance))]
-async fn get_mic_waveforms(editor_instance: WindowEditorInstance) -> Result>, String> {
-    let mut out = Vec::new();
-
-    for segment in editor_instance.segment_medias.iter() {
-        // Waits for the background decode; a failed track just renders as an
-        // empty waveform (playback/export surface the actual error).
-        match segment.audio.get().await {
-            Ok(Some(audio)) => out.push(audio::align_waveform_to_playback(
-                audio::get_waveform(&audio),
-                segment.audio_timing_repair.mic_offset_secs,
-            )),
-            Ok(None) => out.push(Vec::new()),
-            Err(error) => {
-                warn!(%error, "Mic audio failed to load; returning empty waveform");
-                out.push(Vec::new());
-            }
-        }
-    }
-
-    Ok(out)
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(editor_instance))]
-async fn get_system_audio_waveforms(
-    editor_instance: WindowEditorInstance,
-) -> Result>, String> {
-    let mut out = Vec::new();
-
-    for segment in editor_instance.segment_medias.iter() {
-        match segment.system_audio.get().await {
-            Ok(Some(audio)) => out.push(audio::align_waveform_to_playback(
-                audio::get_waveform(&audio),
-                segment.audio_timing_repair.system_audio_offset_secs,
-            )),
-            Ok(None) => out.push(Vec::new()),
-            Err(error) => {
-                warn!(%error, "System audio failed to load; returning empty waveform");
-                out.push(Vec::new());
-            }
-        }
-    }
-
-    Ok(out)
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app, editor_instance, window))]
-async fn editor_delete_project(
-    app: tauri::AppHandle,
-    editor_instance: WindowEditorInstance,
-    window: tauri::Window,
-) -> Result<(), String> {
-    let _ = window.close();
-
-    tokio::time::sleep(std::time::Duration::from_millis(20)).await;
-
-    let path = editor_instance.0.project_path.clone();
-    drop(editor_instance);
-
-    let _ = tokio::fs::remove_dir_all(&path).await;
-
-    RecordingDeleted { path }.emit(&app).ok();
-
-    Ok(())
-}
-
-async fn open_pricing_page(app: &AppHandle) -> Result<(), String> {
-    app.shell()
-        .open("https://cap.so/pricing?ref=desktop", None)
-        .map_err(|e| e.to_string())
-}
-
-// keep this async otherwise opening windows may hang on windows
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-async fn show_window(app: AppHandle, window: ShowCapWindow) -> Result<(), String> {
-    if matches!(window, ShowCapWindow::Upgrade) {
-        return open_pricing_page(&app).await;
-    }
-
-    if matches!(window, ShowCapWindow::Camera { .. }) {
-        let operation_lock = app.state::();
-        let _operation_guard = operation_lock.lock().await;
-        window.show(&app).await.map_err(|e| e.to_string())?;
-        return Ok(());
-    }
-
-    window.show(&app).await.map_err(|e| e.to_string())?;
-    Ok(())
-}
-
-#[tauri::command(async)]
-#[specta::specta]
-#[instrument]
-fn list_fails() -> Result, ()> {
-    Ok(cap_fail::get_state())
-}
-
-#[tauri::command(async)]
-#[specta::specta]
-#[instrument]
-fn set_fail(name: String, value: bool) {
-    cap_fail::set_fail(&name, value)
-}
-
-async fn check_notification_permissions(app: AppHandle) {
-    let Ok(Some(settings)) = GeneralSettingsStore::get(&app) else {
-        return;
-    };
-
-    if !settings.enable_notifications {
-        return;
-    }
-
-    match app.notification().permission_state() {
-        Ok(state) if state != PermissionState::Granted => {
-            info!("Requesting notification permission");
-            match app.notification().request_permission() {
-                Ok(PermissionState::Granted) => {
-                    info!("Notification permission granted");
-                }
-                Ok(_) | Err(_) => {
-                    GeneralSettingsStore::update(&app, |s| {
-                        s.enable_notifications = false;
-                    })
-                    .ok();
-                }
-            }
-        }
-        Ok(_) => {
-            debug!("Notification permission already granted");
-        }
-        Err(e) => {
-            error!("Error checking notification permission state: {e}");
-        }
-    }
-}
-
-// fn configure_logging(folder: &PathBuf) -> tracing_appender::non_blocking::WorkerGuard {
-//     let file_appender = tracing_appender::rolling::daily(folder, "cap-logs.log");
-//     let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender);
-
-//     let filter = || tracing_subscriber::filter::EnvFilter::builder().parse_lossy("cap-*=TRACE");
-
-//     tracing_subscriber::registry()
-//         .with(
-//             tracing_subscriber::fmt::layer()
-//                 .with_ansi(false)
-//                 .with_target(false)
-//                 .with_writer(non_blocking)
-//                 .with_filter(filter()),
-//         )
-//         .with(
-//             tracing_subscriber::fmt::layer()
-//                 .with_ansi(true)
-//                 .with_target(false)
-//                 .with_filter(filter()),
-//         )
-//         .init();
-
-//     _guard
-// }
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-async fn set_server_url(app: MutableState<'_, App>, server_url: String) -> Result<(), ()> {
-    let mut app = app.write().await;
-    telemetry::set_server_url(&server_url);
-    app.server_url = server_url;
-
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-async fn pick_recordings_folder(app: AppHandle) -> Result, String> {
-    use tauri_plugin_dialog::DialogExt;
-
-    let (tx, rx) = tokio::sync::oneshot::channel();
-
-    app.dialog()
-        .file()
-        .set_title("Choose Recordings Folder")
-        .pick_folder(move |path| {
-            let _ = tx.send(
-                path.as_ref()
-                    .and_then(|p| p.as_path())
-                    .and_then(|p| p.to_str())
-                    .map(|s| s.to_string()),
-            );
-        });
-
-    let result = rx.await.map_err(|e| e.to_string())?;
-    if let Some(ref path) = result {
-        general_settings::GeneralSettingsStore::update(&app, |s| {
-            let previous = s.recordings_path.replace(path.clone());
-            recordings_locations::remember_previous_recordings_path(s, previous, Some(path));
-        })?;
-    }
-    Ok(result)
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-async fn reset_recordings_folder(app: AppHandle) -> Result<(), String> {
-    general_settings::GeneralSettingsStore::update(&app, |s| {
-        let previous = s.recordings_path.take();
-        recordings_locations::remember_previous_recordings_path(s, previous, None);
-    })
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-async fn set_camera_preview_state(
-    app: MutableState<'_, App>,
-    state: CameraPreviewState,
-) -> Result<(), String> {
-    let app_guard = app.read().await;
-    let state_for_ws = state.clone();
-    app_guard
-        .camera_preview
-        .set_state(state)
-        .map_err(|err| format!("Error saving camera window state: {err}"))?;
-
-    let _ = app_guard.camera_preview_state_tx.send(state_for_ws);
-    drop(app_guard);
-
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-fn set_camera_window_position(app: AppHandle, x: f64, y: f64) -> Result<(), String> {
-    if app
-        .try_state::()
-        .is_some_and(|guard| guard.should_ignore())
-    {
-        return Ok(());
-    }
-
-    GeneralSettingsStore::update(&app, |settings| {
-        update_camera_window_position_settings(settings, x, y, None);
-    })?;
-
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument]
-fn ignore_camera_window_position(
-    guard: State<'_, CameraWindowPositionGuard>,
-    duration_ms: u32,
-) -> Result<(), String> {
-    guard.ignore_for(duration_ms as u64);
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(state))]
-async fn refresh_camera_feed(state: MutableState<'_, App>) -> Result<(), String> {
-    let app = state.read().await;
-    let camera_feed = app.camera_feed.clone();
-
-    #[allow(deprecated)]
-    let camera_ws_sender = app.camera_ws_sender.clone();
-
-    let camera_preview_sender = app.camera_preview.sender();
-    let use_ws_preview = app.camera_preview.is_paused() || camera_preview_sender.is_none();
-
-    drop(app);
-
-    if use_ws_preview {
-        if let Some(sender) = camera_preview_sender {
-            sender
-                .detach(&camera_feed)
-                .await
-                .map_err(|err| format!("error removing native preview sender: {err}"))?;
-        }
-
-        #[allow(deprecated)]
-        camera_feed
-            .ask(feeds::camera::AddSender(camera_ws_sender))
-            .await
-            .map_err(|err| format!("error re-adding camera ws sender: {err}"))?;
-    } else if let Some(sender) = camera_preview_sender {
-        #[allow(deprecated)]
-        camera_feed
-            .ask(feeds::camera::RemoveSender(camera_ws_sender))
-            .await
-            .map_err(|err| format!("error removing camera ws sender: {err}"))?;
-
-        sender
-            .attach(&camera_feed)
-            .await
-            .map_err(|err| format!("error re-adding camera preview sender: {err}"))?;
-    } else {
-        #[allow(deprecated)]
-        camera_feed
-            .ask(feeds::camera::AddSender(camera_ws_sender))
-            .await
-            .map_err(|err| format!("error re-adding camera ws sender: {err}"))?;
-    }
-
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app, state))]
-async fn destroy_camera_window(app: AppHandle, state: MutableState<'_, App>) -> Result<(), String> {
-    let shutdown_rx = {
-        let mut app_state = state.write().await;
-        app_state.camera_preview.begin_shutdown()
-    };
-
-    if let Some(rx) = shutdown_rx {
-        let _ = tokio::time::timeout(std::time::Duration::from_millis(500), rx).await;
-    }
-
-    windows::cleanup_camera_window(&app, None, true, true).await;
-
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-async fn await_camera_preview_ready(app: MutableState<'_, App>) -> Result {
-    let app = app.read().await.camera_feed.clone();
-
-    let (tx, rx) = oneshot::channel();
-    app.tell(feeds::camera::ListenForReady(tx))
-        .await
-        .map_err(|err| format!("error registering ready listener: {err}"))?;
-    rx.await
-        .map_err(|err| format!("error receiving ready signal: {err}"))?;
-    Ok(true)
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-async fn update_auth_plan(app: AppHandle) {
-    AuthStore::update_auth_plan(&app).await.ok();
-}
-
-pub async fn open_target_picker(
-    app: &tauri::AppHandle,
-    target_mode: recording_settings::RecordingTargetMode,
-) {
-    use tauri::Manager;
-
-    hide_main_window(app);
-
-    let state = app.state::();
-    let display_id = None;
-
-    let session = match target_select_overlay::open_target_select_overlays_for_session(
-        app.clone(),
-        state.inner(),
-        None,
-        display_id.clone(),
-        Some(target_mode),
-    )
-    .await
-    {
-        Ok(session) => session,
-        Err(error) => {
-            warn!(%error, "Failed to open target picker");
-            let _ = ShowCapWindow::Main {
-                init_target_mode: None,
-            }
-            .show(app)
-            .await;
-            return;
-        }
-    };
-
-    tokio::time::sleep(std::time::Duration::from_millis(100)).await;
-    if !state.picker_is_current(session) {
-        return;
-    }
-
-    let _ = RequestSetTargetMode {
-        target_mode: Some(target_mode),
-        display_id,
-    }
-    .emit(app);
-}
-
-type FilteredRegistry = tracing_subscriber::layer::Layered<
-    tracing_subscriber::filter::FilterFn bool>,
-    tracing_subscriber::Registry,
->;
-
-pub type DynLoggingLayer = Box + Send + Sync>;
-type LoggingHandle = tracing_subscriber::reload::Handle, FilteredRegistry>;
-
-#[cfg(debug_assertions)]
-pub fn initialize_stop_editor_benchmark(
-    create_log_directory: impl FnOnce(&std::path::Path, &std::path::Path) -> std::io::Result,
-) -> Result, String> {
-    stop_editor_benchmark::initialize(create_log_directory)
-}
-
-/// Software recovery exists to break GPU-driver crash loops: a process that died
-/// while wgpu adapter/device initialisation was in flight. Any other unexpected
-/// termination (force-quit, power loss, OS kill, a hung shutdown) says nothing
-/// about the GPU, and forcing the WARP software rasterizer would cripple editor
-/// playback (seconds-per-frame renders) on perfectly healthy hardware. A previous
-/// session that was *already* in software recovery and still died shows software
-/// mode isn't saving the machine, so retry hardware rather than chaining recovery
-/// launches forever.
-#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
-fn should_engage_graphics_recovery(
-    previous_termination: Option,
-) -> bool {
-    previous_termination.is_some_and(|prev| prev.during_gpu_init && !prev.in_graphics_recovery)
-}
-
-#[cfg(target_os = "windows")]
-fn configure_windows_graphics_recovery(
-    previous_termination: Option,
-) {
-    if should_engage_graphics_recovery(previous_termination) {
-        cap_rendering::set_force_software_wgpu_adapter(true);
-        crash_sentinel::mark_graphics_recovery();
-        warn!(
-            "Previous Cap session terminated during GPU initialisation; using Windows software graphics recovery mode for this launch"
-        );
-    } else if previous_termination.is_some() {
-        info!(
-            "Previous session terminated unexpectedly, but not during first-time GPU initialisation; keeping hardware graphics"
-        );
-    }
-}
-
-#[cfg(not(target_os = "windows"))]
-fn configure_windows_graphics_recovery(
-    _previous_termination: Option,
-) {
-}
-
-/// Decides what `camera_blur_disabled_by_crash` should hold for this launch: a
-/// death with the blur pipeline active disables blur at the current version
-/// (fresh crash evidence beats version optimism), an existing disable carries
-/// over within the same app version, and an app update clears it so the new
-/// ort/wgpu/driver stack gets one retry.
-fn next_camera_blur_disabled_version(
-    stored: Option<&str>,
-    previous_termination: Option,
-    current_version: &str,
-) -> Option {
-    if previous_termination.is_some_and(|prev| prev.blur_active) {
-        return Some(current_version.to_string());
-    }
-    stored.filter(|v| *v == current_version).map(String::from)
-}
-
-/// Breaks the camera-background-blur crash loop: a native DirectML/driver crash
-/// never reaches a panic handler, and the blur toggle is persisted frontend-side,
-/// so without this the next camera open repeats the crash forever. Blur init is
-/// lazy (first camera frame / editor render), so running this during setup is
-/// early enough. Windows-only at runtime (matching graphics recovery) but
-/// compiled everywhere so non-Windows builds keep it honest.
-fn configure_camera_blur_recovery(
-    app: &AppHandle,
-    previous_termination: Option,
-) {
-    if !cfg!(target_os = "windows") {
-        return;
-    }
-
-    let current_version = env!("CARGO_PKG_VERSION");
-    let stored = GeneralSettingsStore::get(app)
-        .ok()
-        .flatten()
-        .and_then(|settings| settings.camera_blur_disabled_by_crash);
-    let next =
-        next_camera_blur_disabled_version(stored.as_deref(), previous_termination, current_version);
-
-    if next != stored {
-        let value = next.clone();
-        if let Err(error) = GeneralSettingsStore::update(app, |settings| {
-            settings.camera_blur_disabled_by_crash = value;
-        }) {
-            warn!(%error, "Failed to persist camera blur crash-recovery state");
-        }
-    }
-
-    if next.is_some() {
-        cap_camera_effects::set_blur_disabled(true);
-        crash_sentinel::mark_blur_recovery();
-        if stored.is_none() {
-            error!(
-                "Previous Cap session died with camera background blur active; disabling blur until the next app update"
-            );
-        } else {
-            warn!("Camera background blur remains disabled by crash recovery for this launch");
-        }
-    } else if stored.is_some() {
-        info!(
-            prev_version = stored.as_deref(),
-            "App version changed; re-enabling camera background blur for one retry"
-        );
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-fn animated_gradient_catalog() -> cap_project::AnimatedGradientCatalog {
-    cap_project::animated_gradient_catalog()
-}
-
-#[tauri::command]
-#[specta::specta]
-fn random_animated_gradient() -> cap_project::AnimatedGradientConfig {
-    cap_project::AnimatedGradientConfig::random()
-}
-
-#[cfg(any(debug_assertions, test))]
-fn typescript_exporter() -> specta_typescript::Typescript {
-    specta_typescript::Typescript::default().formatter(|path| {
-        let source = std::fs::read_to_string(path)?;
-        let formatted = source
-            .lines()
-            .map(str::trim_end)
-            .collect::>()
-            .join("\n");
-        std::fs::write(path, format!("{formatted}\n"))
-    })
-}
-
-fn specta_builder() -> tauri_specta::Builder {
-    tauri_specta::Builder::new()
-        .commands(tauri_specta::collect_commands![
-            linux_instant_camera::submit_camera_presentation,
-            clean_capture::get_clean_capture_state,
-            clean_capture::reveal_capture_window,
-            animated_gradient_catalog,
-            random_animated_gradient,
-            set_mic_input,
-            set_camera_input,
-            set_native_camera_preview_enabled,
-            gpui_app::gpui_app_available,
-            gpui_app::switch_to_gpui_app,
-            recording_settings::set_recording_mode,
-            upload_logs,
-            get_system_diagnostics,
-            diagnostics::run_diagnostic,
-            diagnostics::upload_diagnostic_report,
-            diagnostics::reveal_diagnostic_report,
-            cli::get_cli_install_status,
-            cli::install_cli,
-            cli::uninstall_cli,
-            recording::start_recording,
-            recording::stop_recording,
-            recording::pause_recording,
-            recording::get_recording_pause_state,
-            recording::resume_recording,
-            recording::toggle_pause_recording,
-            recording::set_mic_recording_muted,
-            recording::restart_recording,
-            recording::delete_recording,
-            recording::take_screenshot,
-            recording::import_current_desktop_background,
-            recording::get_default_project_config,
-            recording::list_cameras,
-            recording::get_camera_formats,
-            recording::get_microphone_info,
-            recording::list_capture_windows,
-            recording::list_capture_displays,
-            recording::list_displays_with_thumbnails,
-            recording::list_windows_with_thumbnails,
-            windows::refresh_window_content_protection,
-            windows::restore_main_window_geometry,
-            general_settings::get_default_excluded_windows,
-            list_audio_devices,
-            list_system_fonts,
-            close_recordings_overlay_window,
-            fake_window::set_fake_window_bounds,
-            fake_window::remove_fake_window,
-            focus_captures_panel,
-            get_current_recording,
-            export::begin_export_session,
-            export::end_export_session,
-            export::cancel_export,
-            export::cancel_current_window_exports,
-            export::export_video,
-            export::export_video_with_id,
-            export::export_video_to_file,
-            export::get_export_estimates,
-            export::cancel_export_estimates,
-            export::generate_export_preview,
-            export::generate_export_preview_fast,
-            import::start_video_import,
-            import::add_existing_recording_to_editor,
-            import::start_image_import,
-            import::check_import_ready,
-            copy_file_to_path,
-            copy_video_to_clipboard,
-            copy_screenshot_to_clipboard,
-            copy_image_to_clipboard,
-            copy_rendered_screenshot_to_clipboard,
-            open_file_path,
-            reveal_item_in_dir,
-            get_video_metadata,
-            create_editor_instance,
-            editor_preparing::create_preparing_editor_frame,
-            editor_preparing::get_preparing_editor_state,
-            editor_preparing::seek_preparing_editor,
-            editor_preparing::set_preparing_editor_playing,
-            editor_preparing::stop_preparing_editor_frame,
-            get_editor_project_path,
-            get_mic_waveforms,
-            get_system_audio_waveforms,
-            audio_library::list_audio_library,
-            audio_library::add_audio_library_track,
-            audio_library::import_audio_track_file,
-            start_playback,
-            stop_playback,
-            commit_editor_preparing_frame,
-            start_editor_handoff_playback,
-            stop_editor_handoff_playback,
-            set_playhead_position,
-            set_project_config,
-            update_project_config_in_memory,
-            generate_zoom_segments_from_clicks,
-            generate_keyboard_segments,
-            render_screenshot_for_export,
-            render_screenshot_project_for_export,
-            get_screenshot_project_share_state,
-            permissions::open_permission_settings,
-            permissions::do_permissions_check,
-            permissions::request_permission,
-            get_devices_snapshot,
-            upload_exported_video,
-            copy_current_screenshot_share_link,
-            upload_screenshot,
-            upload_rendered_screenshot,
-            create_screenshot_editor_instance,
-            update_screenshot_config,
-            prewarm_screenshot_background,
-            recognize_screenshot_text,
-            get_recording_meta,
-            save_file_dialog,
-            list_recordings,
-            list_recent_recordings,
-            list_screenshots,
-            list_recent_screenshots,
-            check_upgraded_and_update,
-            open_external_link,
-            hotkeys::set_hotkey,
-            reset_camera_permissions,
-            reset_microphone_permissions,
-            clear_presets,
-            is_camera_window_open,
-            seek_to,
-            get_display_frame_for_cropping,
-            clip_thumbnails::get_clip_thumbnail,
-            windows::position_traffic_lights,
-            windows::set_theme,
-            windows::set_teleprompter_window_level,
-            windows::set_teleprompter_window_opacity,
-            windows::apply_macos_liquid_glass_background,
-            global_message_dialog,
-            show_window,
-            write_clipboard_string,
-            platform::perform_haptic_feedback,
-            platform::is_system_audio_capture_supported,
-            list_fails,
-            set_fail,
-            update_auth_plan,
-            set_window_transparent,
-            get_editor_meta,
-            get_recording_meta_by_path,
-            editor_recording::open_editor_recording_main,
-            editor_recording::cancel_editor_recording_flow,
-            editor_recording::get_editor_recording_target,
-            delete_recording_directory,
-            set_pretty_name,
-            set_server_url,
-            pick_recordings_folder,
-            reset_recordings_folder,
-            recordings_locations::count_recordings_to_migrate,
-            recordings_locations::migrate_recordings_to_current_dir,
-            set_camera_preview_state,
-            set_camera_window_position,
-            ignore_camera_window_position,
-            await_camera_preview_ready,
-            destroy_camera_window,
-            refresh_camera_feed,
-            captions::create_dir,
-            captions::save_model_file,
-            captions::transcribe_audio,
-            captions::save_captions,
-            captions::load_captions,
-            captions::get_model_download_status,
-            captions::download_whisper_model,
-            captions::check_model_exists,
-            captions::delete_whisper_model,
-            captions::download_parakeet_model,
-            captions::check_parakeet_model_exists,
-            captions::delete_parakeet_model,
-            captions::export_captions_srt,
-            target_select_overlay::open_target_select_overlays,
-            target_select_overlay::close_target_select_overlays,
-            target_select_overlay::target_select_overlay_ready,
-            target_select_overlay::suspend_target_select_overlays,
-            target_select_overlay::update_camera_overlay_bounds,
-            target_select_overlay::display_information,
-            target_select_overlay::get_window_icon,
-            target_select_overlay::focus_window,
-            editor_delete_project,
-            format_project_name,
-            recovery::find_incomplete_recordings,
-            recovery::recover_recording,
-            recovery::discard_incomplete_recording,
-            automation::get_automations,
-            automation::set_automations,
-            automation::test_automation,
-            automation::automation_should_open_screenshot_editor,
-            automation::list_automation_capabilities,
-            updates::updates_check,
-            updates::updates_download_and_install,
-            restart_app,
-            updates::updates_channel_changed,
-        ])
-        .events(tauri_specta::collect_events![
-            linux_instant_camera::CameraPresentationRequested,
-            RecordingOptionsChanged,
-            NewStudioRecordingAdded,
-            EditorRecordingAdded,
-            editor_recording::EditorRecordingFlowChanged,
-            NewScreenshotAdded,
-            RenderFrameEvent,
-            EditorStateChanged,
-            editor_preparing::PreparingEditorChanged,
-            FrameLayoutEvent,
-            CurrentRecordingChanged,
-            RecordingStarted,
-            RecordingStopped,
-            RequestStartRecording,
-            RequestOpenRecordingPicker,
-            RequestSetTargetMode,
-            RequestOpenSettings,
-            RequestScrollToSettingsSection,
-            RequestScreenCapturePrewarm,
-            NewNotification,
-            audio_meter::AudioInputLevelChange,
-            captions::DownloadProgress,
-            recording::RecordingEvent,
-            RecordingDeleted,
-            recordings_locations::RecordingsMigrationProgress,
-            target_select_overlay::TargetUnderCursor,
-            hotkeys::OnEscapePress,
-            upload::UploadProgressEvent,
-            import::VideoImportProgress,
-            SetCaptureAreaPending,
-            DevicesUpdated,
-            updates::UpdateDownloadProgress,
-            updates::UpdateReady,
-            diagnostics::DiagnosticProgress,
-        ])
-        .error_handling(tauri_specta::ErrorHandlingMode::Throw)
-        .typ::()
-        .typ::()
-        .typ::()
-        .typ::()
-        .typ::()
-        .typ::()
-        .typ::()
-        .typ::()
-        .typ::()
-        .typ::()
-        .typ::()
-        .typ::()
-        .typ::()
-        .typ::()
-        .typ::()
-        .typ::()
-        .typ::()
-        .typ::()
-        .typ::()
-        .typ::()
-        .typ::()
-        .typ::()
-}
-
-#[cfg_attr(mobile, tauri::mobile_entry_point)]
-pub async fn run(recording_logging_handle: LoggingHandle, logs_dir: Option) {
-    let startup = startup::Startup::default();
-    // Arm the unexpected-termination sentinel before anything else can crash, and
-    // report any previous session that died without a clean shutdown.
-    let previous_termination = crash_sentinel::init(logs_dir.as_deref(), env!("CARGO_PKG_VERSION"));
-    configure_windows_graphics_recovery(previous_termination);
-
-    // Keep the sentinel's blur marker in sync with live BlurProcessor instances
-    // (camera preview and editor render alike), so a native blur crash is
-    // attributable on the next launch.
-    cap_camera_effects::set_blur_session_observer(|active| {
-        if active {
-            crash_sentinel::enter_blur_session();
-        } else {
-            crash_sentinel::exit_blur_session();
-        }
-    });
-
-    ffmpeg::init()
-        .map_err(|e| {
-            error!("Failed to initialize ffmpeg: {e}");
-        })
-        .ok();
-
-    // Detect the camera-preview quality profile once from total RAM. On low-RAM
-    // machines (<= 8GB) this opts the preview into a cheaper profile (smaller
-    // textures, 30fps, no background blur); higher-spec machines keep the exact
-    // current behaviour. Only the preview is affected — recording is untouched.
-    {
-        let mut system = sysinfo::System::new();
-        system.refresh_memory();
-        camera::init_preview_profile(system.total_memory());
-    }
-
-    telemetry::init();
-
-    let tauri_context = tauri::generate_context!();
-
-    let specta_builder = specta_builder();
-
-    #[cfg(debug_assertions)]
-    {
-        let bindings_path = std::path::Path::new("../src/utils/tauri.ts");
-        if bindings_path.parent().is_some_and(|parent| parent.exists()) {
-            if let Err(err) = specta_builder.export(typescript_exporter(), bindings_path) {
-                warn!(error = %err, "Failed to export TypeScript bindings");
-            }
-        } else {
-            debug!("Skipping TypeScript bindings export outside source checkout");
-        }
-    }
-
-    let (camera_preview_state_tx, camera_preview_state_rx) =
-        tokio::sync::watch::channel(CameraPreviewState::default());
-    let camera_preview_ws = camera_legacy::create_camera_preview_ws(camera_preview_state_rx).await;
-    let camera_tx = camera_preview_ws.sender;
-    let camera_ws_port = camera_preview_ws.port;
-    let _shutdown = camera_preview_ws.shutdown;
-    #[cfg(target_os = "linux")]
-    let camera_processing = camera_preview_ws.processing;
-    let camera_ws_sender = camera_tx.clone();
-
-    let (mic_samples_tx, mic_samples_rx) = flume::bounded(8);
-    let mic_meter_sender = mic_samples_tx.clone();
-
-    let camera_feed = CameraFeed::spawn(CameraFeed::default());
-    let _ = camera_feed.ask(feeds::camera::AddSender(camera_tx)).await;
-
-    let (mic_error_tx, mic_error_rx) = flume::bounded(1);
-
-    let mic_feed = {
-        let mic_feed = MicrophoneFeed::spawn(MicrophoneFeed::new(mic_error_tx));
-
-        if let Err(err) = mic_feed
-            .ask(feeds::microphone::AddSender(mic_samples_tx))
-            .await
-        {
-            error!("Failed to attach audio meter sender: {err}");
-        }
-
-        mic_feed
-    };
-
-    tauri::async_runtime::set(tokio::runtime::Handle::current());
-
-    let builder =
-        tauri::Builder::default().plugin(tauri_plugin_single_instance::init(|app, args, _cwd| {
-            #[cfg(target_os = "linux")]
-            {
-                let handle = app.clone();
-                if let Err(error) = app.run_on_main_thread(move || {
-                    handle_single_instance(&handle, args);
-                }) {
-                    warn!(%error, "Could not queue Cap activation");
-                }
-            }
-            #[cfg(not(target_os = "linux"))]
-            handle_single_instance(app, args);
-        }));
-
-    #[cfg(target_os = "macos")]
-    let builder = builder
-        .manage(StartupOpenGate::default())
-        .menu(build_macos_app_menu)
-        .on_menu_event(|app, event| {
-            if event.id() == APP_MENU_QUIT_ID {
-                let app = app.clone();
-                tokio::spawn(async move {
-                    request_app_exit(app).await;
-                });
-            }
-        })
-        .plugin(tauri_nspanel::init());
-
-    let builder = builder
-        .manage(startup)
-        .on_page_load(|webview, payload| {
-            if webview.label() == "onboarding"
-                && matches!(payload.event(), tauri::webview::PageLoadEvent::Finished)
-            {
-                webview.app_handle().state::().mark_ready();
-            }
-        })
-        .plugin(tauri_plugin_shell::init())
-        .plugin(tauri_plugin_dialog::init())
-        .plugin(tauri_plugin_store::Builder::new().build())
-        .plugin(tauri_plugin_os::init())
-        .plugin(tauri_plugin_process::init())
-        .plugin(tauri_plugin_oauth::init())
-        .plugin(tauri_plugin_http::init())
-        .plugin(tauri_plugin_updater::Builder::new().build())
-        .plugin(tauri_plugin_notification::init())
-        .plugin(flags::plugin::init())
-        .plugin(tauri_plugin_deep_link::init())
-        .plugin(tauri_plugin_clipboard_manager::init())
-        .plugin(tauri_plugin_fs::init())
-        .plugin(tauri_plugin_opener::init())
-        .plugin(
-            tauri_plugin_window_state::Builder::new()
-                .with_state_flags({
-                    use tauri_plugin_window_state::StateFlags;
-                    let mut flags = StateFlags::all();
-                    flags.remove(StateFlags::VISIBLE);
-                    flags
-                })
-                .with_denylist(&[
-                    CapWindowId::Onboarding.label().as_str(),
-                    CapWindowId::Main.label().as_str(),
-                    CapWindowId::Settings.label().as_str(),
-                    "window-capture-occluder",
-                    "target-select-overlay",
-                    CapWindowId::CaptureArea.label().as_str(),
-                    CapWindowId::Camera.label().as_str(),
-                    CapWindowId::RecordingsOverlay.label().as_str(),
-                    CapWindowId::RecordingControls.label().as_str(),
-                    CapWindowId::Upgrade.label().as_str(),
-                    "editor",
-                    "screenshot-editor",
-                ])
-                .map_label(|label| match label {
-                    label if label.starts_with("camera-") => "camera",
-                    label if label.starts_with("editor-") => "editor",
-                    label if label.starts_with("screenshot-editor-") => "screenshot-editor",
-                    label if label.starts_with("window-capture-occluder-") => {
-                        "window-capture-occluder"
-                    }
-                    label if label.starts_with("target-select-overlay") => "target-select-overlay",
-                    _ => label,
-                })
-                .build(),
-        )
-        .invoke_handler({
-            let public_commands = specta_builder.invoke_handler();
-            let recovery_commands: fn(tauri::ipc::Invoke) -> bool = tauri::generate_handler![recovery::get_recording_recovery_success];
-            move |invoke| {
-                if invoke.message.command() == "get_recording_recovery_success" {
-                    recovery_commands(invoke)
-                } else {
-                    public_commands(invoke)
-                }
-            }
-        })
-        .setup(move |app| {
-            let app = app.handle().clone();
-            #[cfg(debug_assertions)]
-            stop_editor_benchmark::validate_app_identifier(&app.config().identifier)?;
-            #[cfg(target_os = "macos")]
-            let _startup_open_guard = app
-                .try_state::()
-                .map(|state| StartupOpenGuard((*state).clone()));
-
-            if let Err(err) = update_project_names::migrate_if_needed(&app) {
-                tracing::error!("Failed to migrate project file names: {}", err);
-            }
-
-            specta_builder.mount_events(&app);
-            general_settings::init(&app);
-            // Before anything shows a window or initialises further state: when
-            // the native app owns the session, this one only exists to start it.
-            if gpui_app::redirect_at_startup_if_enabled(&app)? {
-                // Nothing is managed yet, so `ExitRequested` would otherwise
-                // spawn a cleanup with no `AppExitState` to guard it. Marking
-                // the exit as already begun takes the plain runtime-exit path.
-                let exit_state = AppExitState::default();
-                exit_state.begin();
-                app.manage(exit_state);
-                crash_sentinel::mark_clean_exit();
-
-                #[cfg(target_os = "macos")]
-                {
-                    if app.try_state::().is_none() {
-                        app.manage(gpui_app::StartupRedirectState::default());
-                    }
-                    finish_macos_startup_opens(&app, StartupOpenDestination::Gpui);
-                    gpui_app::retire_foreground_parent_for_handoff(&app);
-                    let app = app.clone();
-                    tokio::spawn(async move {
-                        tokio::time::sleep(Duration::from_millis(750)).await;
-                        let Some(reopen_pid) = app
-                            .try_state::()
-                            .and_then(|state| state.exit_if_pending())
-                        else {
-                            return;
-                        };
-                        if let Some(pid) = reopen_pid
-                        {
-                            match tokio::task::spawn_blocking(move || gpui_app::request_gpui_reopen(pid)).await {
-                                Ok(Ok(())) => info!(pid, "Queued a request to reopen Cap GPUI"),
-                                Ok(Err(error)) => warn!(pid, %error, "Could not confirm Cap GPUI reopening; the existing instance remains unchanged"),
-                                Err(error) => warn!(pid, %error, "Cap GPUI reopen forwarding did not finish"),
-                            }
-                        }
-                        app.exit(0);
-                    });
-                }
-
-                #[cfg(not(target_os = "macos"))]
-                app.exit(0);
-
-                return Ok(());
-            }
-            app.manage(clean_capture::State::default());
-            hotkeys::init(&app);
-            configure_camera_blur_recovery(&app, previous_termination);
-            fake_window::init(&app);
-            app.manage(target_select_overlay::WindowFocusManager::default());
-            app.manage(EditorWindowIds::default());
-            app.manage(ScreenshotEditorWindowIds::default());
-            app.manage(EditorRecordingTarget::default());
-            app.manage(editor_recording::EditorRecordingFlowState::default());
-            #[cfg(target_os = "macos")]
-            app.manage(crate::platform::ScreenCapturePrewarmer::default());
-            #[cfg(target_os = "macos")]
-            app.manage(panel_manager::PanelManager::new());
-            app.manage(http_client::HttpClient::default());
-            app.manage(http_client::RetryableHttpClient::default());
-            app.manage(PendingScreenshots::default());
-            app.manage(FinalizingRecordings::default());
-            app.manage(editor_preparing::PreparingConsumers::default());
-            app.manage(updates::UpdatesState::default());
-            updates::spawn_background_loop(app.clone());
-
-            #[cfg(unix)]
-            {
-                let app_for_signal = app.clone();
-                tokio::spawn(async move {
-                    use tokio::signal::unix::{SignalKind, signal};
-                    let Ok(mut term) = signal(SignalKind::terminate()) else {
-                        tracing::warn!("Failed to register SIGTERM handler");
-                        return;
-                    };
-                    let Ok(mut hup) = signal(SignalKind::hangup()) else {
-                        tracing::warn!("Failed to register SIGHUP handler");
-                        return;
-                    };
-                    loop {
-                        tokio::select! {
-                            signal = term.recv() => {
-                                if signal.is_none() {
-                                    return;
-                                }
-                                tracing::info!("Received SIGTERM; requesting graceful shutdown");
-                            }
-                            signal = hup.recv() => {
-                                if signal.is_none() {
-                                    return;
-                                }
-                                tracing::info!("Received SIGHUP; requesting graceful shutdown");
-                            }
-                        }
-                        request_app_exit(app_for_signal.clone()).await;
-                        if app_is_exiting(&app_for_signal) {
-                            return;
-                        }
-                    }
-                });
-            }
-
-            tokio::spawn({
-                let camera_feed = camera_feed.clone();
-                let app = app.clone();
-                async move {
-                    camera_feed
-                        .tell(feeds::camera::OnFeedDisconnect(Box::new({
-                            move || {
-                                if app_is_exiting(&app) {
-                                    return;
-                                }
-
-                                if let Some(win) = CapWindowId::Camera.get(&app) {
-                                    win.hide().ok();
-                                }
-                            }
-                        })))
-                        .send()
-                        .await
-                        .map_err(|err| error!("Error registering on camera feed disconnect: {err}"))
-                        .ok();
-                }
-            });
-
-            if let Ok(Some(auth)) = AuthStore::load(&app) {
-                sentry::configure_scope(|scope| {
-                    scope.set_user(auth.user_id.map(|id| sentry::User {
-                        id: Some(id),
-                        ..Default::default()
-                    }));
-                });
-            }
-
-            {
-                let (server_url, should_update) = if cfg!(debug_assertions)
-                    && let Ok(url) = std::env::var("VITE_SERVER_URL")
-                {
-                    (url, true)
-                } else if let Some(url) = GeneralSettingsStore::get(&app)
-                    .ok()
-                    .flatten()
-                    .map(|v| v.server_url.clone())
-                {
-                    (url, false)
-                } else {
-                    (
-                        option_env!("VITE_SERVER_URL")
-                            .unwrap_or("https://cap.so")
-                            .to_string(),
-                        true,
-                    )
-                };
-
-                // This ensures settings reflects the correct value if it's set at startup
-                if should_update {
-                    GeneralSettingsStore::update(&app, |s| {
-                        s.server_url = server_url.clone();
-                    })
-                    .map_err(|err| warn!("Error updating server URL into settings store: {err}"))
-                    .ok();
-                }
-
-                telemetry::set_server_url(&server_url);
-
-                let camera_preview = CameraPreviewManager::new(&app);
-                let camera_session_id_handle = camera_preview.session_id_handle();
-
-                let requested_settings = match RecordingSettingsStore::get(&app) {
-                    Ok(settings) => settings.unwrap_or_default(),
-                    Err(error) => {
-                        warn!(%error, "Failed to load recording settings during startup");
-                        RecordingSettingsStore::default()
-                    }
-                };
-                app.manage(linux_instant_camera::PresentationBroker::default());
-                app.manage(RequestedInputsState::new(
-                    requested_settings.mic_name,
-                    requested_settings.camera_id,
-                ));
-
-                app.manage(Arc::new(RwLock::new(App {
-                    camera_ws_port,
-                    camera_ws_sender,
-                    #[cfg(target_os = "linux")]
-                    camera_processing,
-                    handle: app.clone(),
-                    camera_preview,
-                    camera_preview_state_tx,
-                    recording_state: RecordingState::None,
-                    recording_logging_handle,
-                    mic_feed,
-                    mic_meter_sender,
-                    selected_mic_label: None,
-                    applied_mic_input: AppliedMicrophoneInput::default(),
-                    selected_camera_id: None,
-                    camera_in_use: false,
-                    camera_cleanup_done: false,
-                    camera_feed,
-                    server_url,
-                    logs_dir: logs_dir.clone(),
-                    disconnected_inputs: HashSet::new(),
-                    was_camera_only_recording: false,
-                })));
-
-                app.manage(camera_session_id_handle);
-                app.manage(CameraWindowCloseGate::default());
-                app.manage(CameraWindowPositionGuard::default());
-                app.manage(CameraWindowOperationLock::default());
-                app.manage(AppExitState::default());
-                app.manage(MainWindowReadyState::default());
-                app.manage(deeplink_actions::DeepLinkActionExecutor::new(&app));
-                #[cfg(target_os = "macos")]
-                install_macos_native_terminate_handler(&app);
-                spawn_process_memory_sampler(app.clone());
-
-                #[cfg(target_os = "linux")]
-                let clipboard = ClipboardContext::new(&app)
-                    .expect("Failed to create clipboard context");
-                #[cfg(not(target_os = "linux"))]
-                let clipboard = ClipboardContext::new()
-                    .expect("Failed to create clipboard context");
-                app.manage(Arc::new(RwLock::new(clipboard)));
-            }
-
-            app.listen_any("main-window-ready", {
-                let app = app.clone();
-                move |_| {
-                    app.state::().set_ready(true);
-                    tracing::info!("Main window frontend ready");
-                    app.state::().mark_ready();
-                    #[cfg(debug_assertions)]
-                    stop_editor_benchmark::run(app.clone());
-                    #[cfg(debug_assertions)]
-                    picker_benchmark::run(app.clone());
-                    gpu_context::prewarm_gpu();
-                    tokio::task::spawn_blocking(cap_rendering::prewarm_fonts);
-                    tokio::spawn(screenshot_editor::prewarm_screenshot_renderer());
-
-                    #[cfg(target_os = "macos")]
-                    {
-                        let app = app.clone();
-                        tokio::spawn(async move {
-                            if let Some(prewarmer) =
-                                app.try_state::()
-                            {
-                                prewarmer.request(false).await;
-                            } else {
-                                warn!("ScreenCapturePrewarmer state unavailable after main window ready");
-                            }
-                        });
-                    }
-                }
-            });
-
-            upload::lifecycle::init(app.clone());
-
-            spawn_mic_error_handler(app.clone(), mic_error_rx);
-            spawn_device_watchers(app.clone());
-            spawn_devices_snapshot_emitter(app.clone());
-            spawn_system_resume_detector(app.clone());
-            power_observer::install(&app);
-            window_position_persistence::install(&app);
-
-            tokio::spawn(check_notification_permissions(app.clone()));
-
-            tokio::spawn({
-                let app = app.clone();
-                async move {
-                    let startup_window = if should_show_onboarding(&app) {
-                        ShowCapWindow::Onboarding
-                    } else {
-                        ShowCapWindow::Main {
-                            init_target_mode: None,
-                        }
-                    };
-                    match startup_window.show(&app).await {
-                        Ok(window) => {
-                            tracing::info!(label = window.label(), "Startup window created");
-                        }
-                        Err(error) => {
-                            tracing::error!(%error, "Failed to open startup window");
-                        }
-                    }
-                }
-            });
-
-            audio_meter::spawn_event_emitter(app.clone(), mic_samples_rx);
-
-            if let Err(err) = tray::create_tray(&app) {
-                error!("Failed to create tray: {err}");
-            }
-
-            RequestStartRecording::listen_any_spawn(&app, async |event, app| {
-                let settings = RecordingSettingsStore::get(&app)
-                    .ok()
-                    .flatten()
-                    .unwrap_or_default();
-
-                let _ = start_recording(app.clone(), app.state(), {
-                    recording::StartRecordingInputs {
-                        capture_target: settings.target.unwrap_or_else(|| {
-                            ScreenCaptureTarget::Display {
-                                id: Display::primary().id(),
-                            }
-                        }),
-                        mode: event.mode,
-                        capture_system_audio: settings.system_audio,
-                        organization_id: settings.organization_id,
-                    }
-                })
-                .await;
-            });
-
-            RequestOpenRecordingPicker::listen_any_spawn(&app, async |event, app| {
-                if let Some(target_mode) = event.target_mode {
-                    open_target_picker(&app, target_mode).await;
-                } else {
-                    let _ = ShowCapWindow::Main {
-                        init_target_mode: None,
-                    }
-                    .show(&app)
-                    .await;
-                }
-            });
-
-            RequestOpenSettings::listen_any_spawn(&app, async |payload, app| {
-                let _ = ShowCapWindow::Settings {
-                    page: Some(payload.page),
-                }
-                .show(&app)
-                .await;
-            });
-
-            #[cfg(target_os = "macos")]
-            RequestScreenCapturePrewarm::listen_any_spawn(&app, async |event, app| {
-                if let Some(prewarmer) = app.try_state::()
-                {
-                    prewarmer.request(event.force).await;
-                } else {
-                    warn!("ScreenCapturePrewarmer state unavailable during prewarm request");
-                }
-            });
-
-            RecordingStarted::listen_any_spawn(&app, async |_event, app| {
-                crate::automation::run_recording_started_automations(app);
-            });
-
-            RecordingDeleted::listen_any_spawn(&app, async |event, app| {
-                crate::automation::run_recording_deleted_automations(app, event.path);
-            });
-
-            import::VideoImportProgress::listen_any_spawn(&app, async |event, app| {
-                if matches!(event.stage, import::ImportStage::Complete) {
-                    crate::automation::run_video_imported_automations(
-                        app,
-                        std::path::PathBuf::from(event.project_path),
-                    );
-                }
-            });
-
-            let app_handle = app.clone();
-            app.deep_link().on_open_url(move |event| {
-                deeplink_actions::handle(&app_handle, event.urls());
-            });
-
-            #[cfg(target_os = "macos")]
-            finish_macos_startup_opens(&app, StartupOpenDestination::Desktop);
-
-            Ok(())
-        })
-        .on_window_event(|window, event| {
-            let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
-                let label = window.label();
-                let app = window.app_handle();
-
-                if matches!(
-                    event,
-                    WindowEvent::CloseRequested { .. }
-                        | WindowEvent::Moved(_)
-                        | WindowEvent::Focused(_)
-                ) && app_is_exiting(app)
-                {
-                    return;
-                }
-
-                match event {
-                    WindowEvent::CloseRequested { api, .. } => {
-                        let window_id = CapWindowId::from_str(label).ok();
-                        if !matches!(
-                            window_id,
-                            Some(CapWindowId::Editor { .. })
-                                | Some(CapWindowId::ScreenshotEditor { .. })
-                        ) && export::export_session_active()
-                        {
-                            api.prevent_close();
-                            warn!(
-                                window = label,
-                                "Preventing window close request during active export"
-                            );
-                            return;
-                        }
-
-                        if let Some(window_id) = window_id {
-                            match window_id {
-                                CapWindowId::Camera => {
-                                    if app
-                                        .try_state::()
-                                        .is_some_and(|close_gate| close_gate.allow_close())
-                                    {
-                                        return;
-                                    }
-
-                                    api.prevent_close();
-                                    let _ = window.hide();
-                                    tracing::warn!("Camera window CloseRequested event received!");
-                                    let session_id = app
-                                        .try_state::>()
-                                        .map(|state| state.load(Ordering::Acquire))
-                                        .unwrap_or(0);
-                                    let app = app.clone();
-                                    spawn_on_runtime(async move {
-                                        cleanup_camera_window(app, session_id).await;
-                                    });
-                                }
-                                CapWindowId::Main => {
-                                    api.prevent_close();
-                                    dismiss_main_window(app);
-                                }
-                                _ => {}
-                        }
-                    }
-                }
-                WindowEvent::Destroyed => {
-                    fake_window::cancel_fake_window_listener(app, label);
-                    let window_id = CapWindowId::from_str(label).ok();
-                    if let Some(window_id) = &window_id {
-                        retire_project_window(window, window_id);
-                    }
-                    if app_is_exiting(app) {
-                        return;
-                    }
-                    if export::export_session_active() {
-                        warn!(
-                            window = label,
-                            "Skipping window restoration during active export"
-                        );
-                        return;
-                    }
-                    if let Some(window_id) = window_id {
-                        if matches!(window_id, CapWindowId::Camera) {
-                            tracing::warn!("Camera window Destroyed event received!");
-                        }
-                        match window_id {
-                            CapWindowId::Main => {
-                                let app = app.clone();
-
-                                close_target_select_overlays(&app);
-
-                                if let Some(camera) = CapWindowId::Camera.get(&app) {
-                                    let _ = camera.hide();
-                                }
-
-                                spawn_on_runtime(async move {
-                                    let Some(state) = app.try_state::>() else {
-                                        warn!("App state unavailable during main window destroyed cleanup");
-                                        return;
-                                    };
-
-                                    let feeds = {
-                                        let mut app_state = state.write().await;
-                                        if app_state.is_recording_active_or_pending() {
-                                            None
-                                        } else {
-                                            app_state.applied_mic_input.invalidate();
-                                            Some((
-                                                app_state.mic_feed.clone(),
-                                                app_state.camera_feed.clone(),
-                                            ))
-                                        }
-                                    };
-
-                                    if let Some((mic_feed, camera_feed)) = feeds {
-                                        let _ = tokio::time::timeout(
-                                            APP_EXIT_STEP_TIMEOUT,
-                                            mic_feed.ask(microphone::RemoveInput),
-                                        )
-                                        .await;
-                                        let _ = tokio::time::timeout(
-                                            APP_EXIT_STEP_TIMEOUT,
-                                            camera_feed.ask(feeds::camera::RemoveInput),
-                                        )
-                                        .await;
-
-                                        let mut app_state = state.write().await;
-                                        if !app_state.is_recording_active_or_pending() {
-                                            app_state.selected_mic_label = None;
-                                            app_state.selected_camera_id = None;
-                                            app_state.camera_in_use = false;
-                                        }
-                                    }
-                                });
-                            }
-                            CapWindowId::Editor { .. } | CapWindowId::ScreenshotEditor { .. } => {
-                                editor_recording::abort_if_editor_gone(app);
-                                restore_main_windows_if_no_editors(app);
-                            }
-                            CapWindowId::Settings => {
-                                restore_main_and_target_select_windows(app);
-
-                                restore_camera_window(app);
-
-                                #[cfg(target_os = "windows")]
-                                if !has_open_editor_window(app) {
-                                    reopen_main_window(app);
-                                }
-
-                                #[cfg(target_os = "macos")]
-                                return;
-                            }
-                            CapWindowId::Upgrade | CapWindowId::ModeSelect => {
-                                restore_main_and_target_select_windows(app);
-                                restore_camera_window(app);
-                                #[cfg(target_os = "macos")]
-                                return;
-                            }
-                            CapWindowId::TargetSelectOverlay { display_id } => {
-                                if let Some(focus_manager) =
-                                    app.try_state::()
-                                {
-                                    focus_manager.destroy(&display_id, app.global_shortcut());
-                                }
-                                let session_id = app
-                                    .try_state::>()
-                                    .map(|state| state.load(Ordering::Acquire))
-                                    .unwrap_or(0);
-                                spawn_on_runtime(cleanup_camera_after_overlay_close(
-                                    app.clone(),
-                                    session_id,
-                                ));
-                            }
-                            CapWindowId::Camera => {
-                                tracing::info!(
-                                    "Camera window Destroyed event - resetting panel state"
-                                );
-                                let session_id = app
-                                    .try_state::>()
-                                    .map(|state| state.load(Ordering::Acquire))
-                                    .unwrap_or(0);
-                                let app = app.clone();
-                                spawn_on_runtime(async move {
-                                    #[cfg(target_os = "macos")]
-                                    {
-                                        if let Some(panel_manager) =
-                                            app.try_state::()
-                                        {
-                                            panel_manager
-                                                .force_reset(panel_manager::PanelWindowType::Camera)
-                                                .await;
-                                        }
-                                    }
-                                    cleanup_camera_window(app, session_id).await;
-                                });
-                            }
-                            _ => {}
-                        };
-                    }
-
-                    #[cfg(target_os = "macos")]
-                    crate::permissions::sync_macos_dock_visibility(app);
-                }
-                #[cfg(target_os = "macos")]
-                WindowEvent::Focused(focused) => {
-                    let window_id = CapWindowId::from_str(label);
-
-                    if matches!(window_id, Ok(CapWindowId::Upgrade)) {
-                        for (label, window) in app.webview_windows() {
-                            if let Ok(id) = CapWindowId::from_str(&label)
-                                && matches!(id, CapWindowId::TargetSelectOverlay { .. })
-                            {
-                                hide_overlay(&window);
-                            }
-                        }
-                    }
-
-                    if *focused
-                        && let Ok(window_id) = window_id
-                        && window_id.activates_dock()
-                    {
-                        crate::permissions::sync_macos_dock_visibility(app);
-                    }
-                }
-                WindowEvent::DragDrop(tauri::DragDropEvent::Drop { paths, .. }) => {
-                    let window_id = CapWindowId::from_str(label).ok();
-                    for path in paths {
-                        let result = if matches!(window_id, Some(CapWindowId::Main)) {
-                            open_importable_from_path(path, app.clone())
-                        } else {
-                            open_project_from_path(path, app.clone())
-                        };
-
-                        if let Err(err) = result {
-                            warn!(path = %path.display(), error = %err, "Failed to open dropped path");
-                        }
-                    }
-                }
-                WindowEvent::Moved(position) => {
-                    let window_id = CapWindowId::from_str(label);
-
-                    #[cfg(target_os = "macos")]
-                    if matches!(&window_id, Ok(CapWindowId::Main))
-                        && let Some(constrained_position) =
-                            platform::constrain_main_window_to_visible_top(window, *position)
-                    {
-                        match window.set_position(constrained_position) {
-                            Ok(()) => {
-                                let scale_factor = window
-                                    .current_monitor()
-                                    .ok()
-                                    .flatten()
-                                    .map(|monitor| monitor.scale_factor())
-                                    .unwrap_or_else(|| window.scale_factor().unwrap_or(1.0));
-                                let logical_pos =
-                                    constrained_position.to_logical::(scale_factor);
-                                let display_id = display_for_position(logical_pos.x, logical_pos.y)
-                                    .map(|display| display.id());
-                                window_position_persistence::queue_main_position(
-                                    app,
-                                    general_settings::WindowPosition {
-                                        x: logical_pos.x,
-                                        y: logical_pos.y,
-                                        display_id,
-                                    },
-                                );
-                                return;
-                            }
-                            Err(error) => warn!(
-                                %error,
-                                "Failed to constrain main window to the visible screen area"
-                            ),
-                        }
-                    }
-
-                    if let Ok(window_id) = window_id {
-                        let scale_factor = window.scale_factor().unwrap_or(1.0);
-                        let logical_pos = position.to_logical::(scale_factor);
-
-                        // Resolve which display the window landed on. On Windows this
-                        // must use the physical position: mixed-DPI logical rects
-                        // overlap, so logical containment can pick the wrong display.
-                        #[cfg(windows)]
-                        let moved_display =
-                            display_for_physical_position(position.x as f64, position.y as f64);
-                        #[cfg(not(windows))]
-                        let moved_display = display_for_position(logical_pos.x, logical_pos.y);
-
-                        match window_id {
-                            CapWindowId::Main => {
-                                let display_id =
-                                    moved_display.as_ref().map(|display| display.id());
-                                window_position_persistence::queue_main_position(
-                                    app,
-                                    general_settings::WindowPosition {
-                                        x: logical_pos.x,
-                                        y: logical_pos.y,
-                                        display_id,
-                                    },
-                                );
-                            }
-                            CapWindowId::Camera => {
-                                if app
-                                    .try_state::()
-                                    .is_some_and(|guard| guard.should_ignore())
-                                {
-                                    return;
-                                }
-                                window_position_persistence::queue_camera_position(
-                                    app,
-                                    logical_pos.x,
-                                    logical_pos.y,
-                                    moved_display.map(|display| display.id()),
-                                );
-                            }
-                            _ => {}
-                        }
-                    }
-                }
-                WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
-                    if let Some(webview_window) = app.get_webview_window(label) {
-                        windows::update_window_rasterization_scale(
-                            &webview_window,
-                            *scale_factor,
-                        );
-                    }
-                }
-                _ => {}
-                }
-            }));
-
-            if let Err(panic) = result {
-                let message = panic_payload_message(&panic);
-                tracing::error!(panic = %message, "Suppressed panic in Tauri WindowEvent handler");
-                sentry::capture_message(
-                    &format!("Tauri WindowEvent panic suppressed: {message}"),
-                    sentry::Level::Error,
-                );
-            }
-        });
-
-    run_tauri_event_loop(move || {
-        builder
-            .build(tauri_context)
-            .expect("error while running tauri application")
-            .run(move |handle, event| {
-                let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
-                    handle_run_event(handle, event);
-                }));
-
-                if let Err(panic) = result {
-                    let message = panic_payload_message(&panic);
-                    tracing::error!(panic = %message, "Suppressed panic in Tauri RunEvent handler");
-                    sentry::capture_message(
-                        &format!("Tauri RunEvent panic suppressed: {message}"),
-                        sentry::Level::Error,
-                    );
-                }
-            });
-    });
-}
-
-fn run_tauri_event_loop(run: impl FnOnce() -> R) -> R {
-    #[cfg(target_os = "linux")]
-    {
-        // zbus blocks on its own runtime during plugin setup and shutdown; keep GTK on this thread.
-        tokio::task::block_in_place(run)
-    }
-    #[cfg(not(target_os = "linux"))]
-    run()
-}
-
-fn handle_single_instance(app: &AppHandle, args: Vec) {
-    trace!(arg_count = args.len(), "Single instance invoked");
-
-    #[cfg(target_os = "linux")]
-    if app
-        .try_state::()
-        .is_some_and(|state| state.is_exiting())
-    {
-        return;
-    }
-
-    if gpui_app::handle_update_handoff(app) {
-        return;
-    }
-
-    #[cfg(any(target_os = "macos", windows))]
-    if gpui_app::forward_deep_links_to_active_gpui(app, &args) {
-        return;
-    }
-
-    let action_urls = args
-        .iter()
-        .filter(|arg| arg.starts_with("cap-desktop://"))
-        .filter_map(|arg| tauri::Url::parse(arg).ok())
-        .collect::>();
-    if !action_urls.is_empty() {
-        deeplink_actions::handle(app, action_urls);
-        return;
-    }
-
-    let Some(cap_file) = args
-        .iter()
-        .find(|arg| arg.ends_with(".cap"))
-        .map(PathBuf::from)
-    else {
-        let app = app.clone();
-        tauri::async_runtime::spawn(async move {
-            if let Err(error) = (ShowCapWindow::Main {
-                init_target_mode: None,
-            })
-            .show(&app)
-            .await
-            {
-                warn!(%error, "Could not show Cap recording controls");
-            }
-        });
-        return;
-    };
-
-    let _ = open_project_from_path(&cap_file, app.clone());
-}
-
-pub(crate) fn panic_payload_message(payload: &(dyn std::any::Any + Send)) -> String {
-    if let Some(s) = payload.downcast_ref::<&'static str>() {
-        (*s).to_string()
-    } else if let Some(s) = payload.downcast_ref::() {
-        s.clone()
-    } else {
-        "".to_string()
-    }
-}
-
-// Catches panics inside an async Tauri command body so a single bad code path can't
-// unwind through the IPC dispatcher and terminate the whole desktop process. This is
-// particularly important for commands that participate in the export flow because the
-// sidecar architecture relies on the desktop app remaining alive to babysit the worker.
-async fn run_command_safely(command_name: &'static str, fut: F) -> Result
-where
-    F: std::future::Future>,
-{
-    match AssertUnwindSafe(fut).catch_unwind().await {
-        Ok(result) => result,
-        Err(panic) => {
-            let message = panic_payload_message(&*panic);
-            error!(
-                command = command_name,
-                panic = %message,
-                "Suppressed panic in Tauri command"
-            );
-            sentry::capture_message(
-                &format!("Tauri command '{command_name}' panicked: {message}"),
-                sentry::Level::Error,
-            );
-            Err(format!("{command_name} failed unexpectedly"))
-        }
-    }
-}
-
-fn emit_app_event_safely(app: &AppHandle, event: E)
-where
-    E: Event + Serialize + Clone,
-{
-    let event_name = std::any::type_name::();
-    match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| event.emit(app))) {
-        Ok(Ok(())) => {}
-        Ok(Err(error)) => warn!(event = event_name, %error, "Failed to emit app event"),
-        Err(panic) => {
-            let message = panic_payload_message(&panic);
-            error!(event = event_name, panic = %message, "Suppressed panic while emitting app event");
-        }
-    }
-}
-
-#[cfg(any(target_os = "macos", test))]
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-enum StartupOpenDestination {
-    Desktop,
-    Gpui,
-}
-
-#[cfg(any(target_os = "macos", test))]
-struct StartupOpenDispatch {
-    destination: StartupOpenDestination,
-    urls: Vec,
-}
-
-#[cfg(any(target_os = "macos", test))]
-#[derive(Default)]
-struct StartupOpenQueue {
-    destination: Option,
-    cancelled: bool,
-    urls: Vec,
-    gpui_forwarding: bool,
-    gpui_dispatched: Vec,
-}
-
-#[cfg(any(target_os = "macos", test))]
-impl StartupOpenQueue {
-    fn request(&mut self, urls: Vec) -> Result, String> {
-        if self.cancelled {
-            return Err("Cap startup stopped before the project could be opened".into());
-        }
-        if self.destination == Some(StartupOpenDestination::Desktop) {
-            return Ok(Some(StartupOpenDispatch {
-                destination: StartupOpenDestination::Desktop,
-                urls,
-            }));
-        }
-        let mut additions = Vec::new();
-        for url in urls {
-            if self.urls.contains(&url)
-                || self.gpui_dispatched.contains(&url)
-                || additions.contains(&url)
-            {
-                continue;
-            }
-            if self.urls.len() + self.gpui_dispatched.len() + additions.len() >= 64 {
-                return Err("Too many projects were requested while Cap was starting".into());
-            }
-            additions.push(url);
-        }
-        self.urls.extend(additions);
-        if self.destination == Some(StartupOpenDestination::Gpui) && !self.gpui_forwarding {
-            return Ok(self.take_queued());
-        }
-        Ok(None)
-    }
-
-    fn finish(&mut self, destination: StartupOpenDestination) -> Option {
-        if self.cancelled || self.destination.is_some() {
-            return None;
-        }
-        self.destination = Some(destination);
-        self.take_queued()
-    }
-
-    fn take_queued(&mut self) -> Option {
-        let destination = self.destination?;
-        if self.urls.is_empty() {
-            return None;
-        }
-        let urls = std::mem::take(&mut self.urls);
-        if destination == StartupOpenDestination::Gpui {
-            self.gpui_forwarding = true;
-            self.gpui_dispatched.extend(urls.iter().cloned());
-        }
-        Some(StartupOpenDispatch { destination, urls })
-    }
-
-    fn next_gpui_batch(&mut self) -> Option {
-        if self.cancelled
-            || self.destination != Some(StartupOpenDestination::Gpui)
-            || !self.gpui_forwarding
-        {
-            return None;
-        }
-        if let Some(dispatch) = self.take_queued() {
-            return Some(dispatch);
-        }
-        self.cancel();
-        None
-    }
-
-    fn cancel(&mut self) {
-        self.cancelled = true;
-        self.urls.clear();
-        self.gpui_dispatched.clear();
-        self.gpui_forwarding = false;
-    }
-}
-
-#[cfg(any(target_os = "macos", test))]
-#[derive(Clone, Default)]
-struct StartupOpenGate(Arc>);
-
-#[cfg(any(target_os = "macos", test))]
-struct StartupOpenGuard(StartupOpenGate);
-
-#[cfg(any(target_os = "macos", test))]
-impl Drop for StartupOpenGuard {
-    fn drop(&mut self) {
-        if let Ok(mut queue) = self.0.0.lock()
-            && queue.destination.is_none()
-        {
-            queue.cancel();
-        }
-    }
-}
-
-#[cfg(target_os = "macos")]
-fn queue_macos_startup_urls(app: &AppHandle, urls: Vec) -> Result<(), String> {
-    let gate = app
-        .try_state::()
-        .ok_or_else(|| "Cap startup is not ready to receive projects".to_string())?;
-    let dispatch = gate
-        .0
-        .lock()
-        .map_err(|_| "Cap startup file-open state is unavailable".to_string())?
-        .request(urls)?;
-    if let Some(dispatch) = dispatch {
-        dispatch_macos_startup_urls(app, dispatch);
-    }
-    Ok(())
-}
-
-#[cfg(target_os = "macos")]
-fn finish_macos_startup_opens(app: &AppHandle, destination: StartupOpenDestination) {
-    let Some(gate) = app.try_state::() else {
-        return;
-    };
-    let dispatch = match gate.0.lock() {
-        Ok(mut queue) => queue.finish(destination),
-        Err(error) => {
-            warn!(%error, "Could not release startup project requests");
-            return;
-        }
-    };
-    if let Some(dispatch) = dispatch {
-        dispatch_macos_startup_urls(app, dispatch);
-    }
-}
-
-#[cfg(target_os = "macos")]
-fn cancel_macos_startup_opens(app: &AppHandle) {
-    if let Some(gate) = app.try_state::()
-        && let Ok(mut queue) = gate.0.lock()
-    {
-        queue.cancel();
-    }
-}
-
-#[cfg(target_os = "macos")]
-fn dispatch_macos_startup_urls(app: &AppHandle, dispatch: StartupOpenDispatch) {
-    let urls = dispatch.urls;
-    let arguments = urls
-        .iter()
-        .map(|url| url.as_str().to_string())
-        .collect::>();
-
-    if dispatch.destination == StartupOpenDestination::Gpui {
-        let Some(redirect) = app.try_state::() else {
-            warn!("Cap GPUI startup forwarding state is unavailable");
-            return;
-        };
-        if redirect.begin_forwarding() {
-            let app = app.clone();
-            tokio::spawn(async move {
-                let mut arguments = arguments;
-                let mut forwarded_pid = None;
-                loop {
-                    let forwarded = tokio::task::spawn_blocking(move || {
-                        gpui_app::forward_deep_links_to_gpui_when_ready(&arguments)
-                    })
-                    .await
-                    .ok()
-                    .flatten();
-                    if let Some(pid) = forwarded {
-                        forwarded_pid = Some(pid);
-                    } else {
-                        warn!("Could not forward the requested project batch to Cap GPUI");
-                    }
-                    let next = app.try_state::().and_then(|gate| {
-                        gate.0
-                            .lock()
-                            .ok()
-                            .and_then(|mut queue| queue.next_gpui_batch())
-                    });
-                    let Some(next) = next else {
-                        break;
-                    };
-                    arguments = next
-                        .urls
-                        .iter()
-                        .map(|url| url.as_str().to_string())
-                        .collect();
-                }
-
-                if let Some(pid) = forwarded_pid
-                    && let Err(error) = app.run_on_main_thread(move || {
-                        gpui_app::activate_instance(pid);
-                    })
-                {
-                    warn!(%error, "Could not activate Cap GPUI after forwarding a project");
-                }
-                if app
-                    .try_state::()
-                    .is_some_and(|state| state.exit_after_forwarding())
-                {
-                    app.exit(0);
-                }
-            });
-        } else {
-            cancel_macos_startup_opens(app);
-            warn!("Cap GPUI handoff already finished before the project could be forwarded");
-        }
-        return;
-    }
-
-    if gpui_app::forward_deep_links_to_active_gpui(app, &arguments) {
-        return;
-    }
-
-    for url in urls {
-        if url.scheme() == "file"
-            && let Ok(path) = url.to_file_path()
-            && let Err(error) = open_project_from_path(&path, app.clone())
-        {
-            warn!(path = %path.display(), %error, "Could not open the requested project");
-        }
-    }
-}
-
-fn handle_run_event(_handle: &AppHandle, event: tauri::RunEvent) {
-    match event {
-        #[cfg(target_os = "macos")]
-        tauri::RunEvent::Opened { urls } => {
-            if let Err(error) = queue_macos_startup_urls(_handle, urls) {
-                warn!(%error, "Could not receive the requested startup project");
-            }
-        }
-        #[cfg(target_os = "macos")]
-        tauri::RunEvent::Reopen { .. } => {
-            if _handle
-                .try_state::()
-                .is_some()
-            {
-                return;
-            }
-
-            if gpui_app::handle_update_handoff(_handle) {
-                return;
-            }
-
-            let should_focus_onboarding = should_show_onboarding(_handle);
-
-            if should_focus_onboarding
-                && let Some(onboarding) = CapWindowId::Onboarding.get(_handle)
-            {
-                onboarding.show().ok();
-                onboarding.set_focus().ok();
-                return;
-            }
-
-            let has_window = _handle.webview_windows().iter().any(|(label, _)| {
-                label.starts_with("editor-")
-                    || label.starts_with("screenshot-editor-")
-                    || label.as_str() == "settings"
-                    || label.as_str() == "signin"
-                    || (should_focus_onboarding && label.as_str() == "onboarding")
-            });
-
-            if has_window {
-                if let Some(window) = _handle
-                    .webview_windows()
-                    .iter()
-                    .find(|(label, _)| {
-                        label.starts_with("editor-")
-                            || label.starts_with("screenshot-editor-")
-                            || label.as_str() == "settings"
-                            || label.as_str() == "signin"
-                            || (should_focus_onboarding && label.as_str() == "onboarding")
-                    })
-                    .map(|(_, window)| window.clone())
-                {
-                    window.set_focus().ok();
-                }
-            } else {
-                let handle = _handle.clone();
-                spawn_on_runtime(async move {
-                    let _ = ShowCapWindow::Main {
-                        init_target_mode: None,
-                    }
-                    .show(&handle)
-                    .await;
-                });
-            }
-        }
-        tauri::RunEvent::ExitRequested { code, api, .. } => {
-            info!(?code, "App exit requested");
-
-            match handle_exit_requested(
-                _handle
-                    .try_state::()
-                    .is_some_and(|state| state.is_exiting()),
-                export::export_session_active() || upload::upload_session_active(),
-                code.is_some(),
-                code == Some(tauri::RESTART_EXIT_CODE),
-                || api.prevent_exit(),
-            ) {
-                ExitRequestDecision::StartCleanup => {
-                    let handle = _handle.clone();
-                    spawn_on_runtime(async move {
-                        request_app_exit(handle).await;
-                    });
-                }
-                ExitRequestDecision::AlreadyExiting => {}
-                ExitRequestDecision::ExportActive => {
-                    warn!("Preventing app exit request during an active export or upload");
-                }
-                ExitRequestDecision::AllowRuntimeExit => {}
-                ExitRequestDecision::AllowRuntimeRestart => {
-                    if let Some(state) = _handle.try_state::() {
-                        state.begin_restart();
-                    }
-                    crash_sentinel::mark_clean_exit();
-                    info!("Allowing Tauri to restart the app");
-                }
-            }
-        }
-        tauri::RunEvent::Exit => {
-            #[cfg(target_os = "macos")]
-            cancel_macos_startup_opens(_handle);
-            #[cfg(target_os = "macos")]
-            {
-                // This arm runs on the AppKit main thread, so reverse the Liquid Glass
-                // SPI inline before restart or a hard _exit. This is the last-chance
-                // teardown for terminal paths that skip cleanup_app_resources_for_exit;
-                // touching the NSWindow/NSView here is safe because we are on main.
-                let torn_down = crate::platform::teardown_all_liquid_glass_on_main(_handle);
-                if _handle
-                    .try_state::()
-                    .is_some_and(|state| state.is_restarting())
-                {
-                    info!(
-                        windows = torn_down,
-                        "macOS runtime exit reached; allowing Tauri to restart"
-                    );
-                    return;
-                }
-                warn!(
-                    windows = torn_down,
-                    "macOS runtime exit reached; tore down liquid glass, forcing process exit"
-                );
-                force_exit(0);
-            }
-
-            #[cfg(not(target_os = "macos"))]
-            {
-                let already_exiting = match _handle.try_state::() {
-                    Some(state) => !state.begin(),
-                    None => false,
-                };
-                if already_exiting {
-                    return;
-                }
-
-                let handle = _handle.clone();
-                spawn_on_runtime(async move {
-                    let _ = tokio::time::timeout(
-                        Duration::from_secs(2),
-                        cleanup_app_resources_for_exit(&handle),
-                    )
-                    .await;
-                });
-            }
-        }
-        _ => {}
-    }
-}
-
-fn spawn_on_runtime(future: F)
-where
-    F: Future + Send + 'static,
-{
-    match tokio::runtime::Handle::try_current() {
-        Ok(handle) => {
-            handle.spawn(future);
-        }
-        Err(err) => {
-            tracing::warn!(error = %err, "No tokio runtime available; dropping background task");
-        }
-    }
-}
-
-fn retire_project_window(window: &Window, window_id: &CapWindowId) {
-    let app = window.app_handle();
-    match window_id {
-        CapWindowId::Editor { id } => {
-            app.state::()
-                .cancel_window(*id, None);
-            let window_ids = EditorWindowIds::get(app);
-            match window_ids.ids.lock() {
-                Ok(mut ids) => ids.retain(|(_, current_id)| current_id != id),
-                Err(err) => warn!(error = %err, "Editor window ids lock poisoned"),
-            }
-            export::cancel_exports_for_window(window.label());
-            let label = window.label().to_string();
-            let pending = PendingEditorInstances::get(app);
-            spawn_on_runtime(async move {
-                pending.cancel_prewarm(&label).await;
-            });
-            spawn_on_runtime(EditorInstances::remove(window.clone()));
-        }
-        CapWindowId::ScreenshotEditor { id } => {
-            let window_ids = ScreenshotEditorWindowIds::get(app);
-            match window_ids.ids.lock() {
-                Ok(mut ids) => ids.retain(|(_, current_id)| current_id != id),
-                Err(err) => warn!(error = %err, "Screenshot editor window ids lock poisoned"),
-            }
-            export::cancel_exports_for_window(window.label());
-            let label = window.label().to_string();
-            let pending = PendingScreenshotEditorInstances::get(app);
-            spawn_on_runtime(async move {
-                pending.cancel_prewarm(&label).await;
-            });
-            spawn_on_runtime(ScreenshotEditorInstances::remove(window.clone()));
-        }
-        _ => {}
-    }
-}
-
-#[cfg(target_os = "windows")]
-fn has_open_editor_window(app: &AppHandle) -> bool {
-    app.webview_windows()
-        .keys()
-        .any(|label| matches!(CapWindowId::from_str(label), Ok(CapWindowId::Editor { .. })))
-}
-
-fn restore_main_windows_if_no_editors(app: &AppHandle) {
-    let has_other_editors = app.webview_windows().keys().any(|label| {
-        matches!(
-            CapWindowId::from_str(label),
-            Ok(CapWindowId::Editor { .. } | CapWindowId::ScreenshotEditor { .. })
-        )
-    });
-
-    if !has_other_editors {
-        if CapWindowId::Settings.get(app).is_none() {
-            if let Some(main) = CapWindowId::Main.get(app) {
-                let generation = clean_capture::generation(app);
-                let _ = clean_capture::reveal_now(&main, generation);
-            }
-
-            restore_main_window_inputs(app);
-            restore_camera_window(app);
-        }
-
-        spawn_on_runtime(captions::release_ml_models());
-    }
-}
-
-fn restore_main_and_target_select_windows(app: &AppHandle) {
-    let target_select_overlays_hidden_for_restore = app
-        .try_state::()
-        .map(|focus_manager| focus_manager.take_overlay_restore_labels())
-        .unwrap_or_default();
-
-    for (label, window) in app.webview_windows() {
-        if let Ok(id) = CapWindowId::from_str(&label) {
-            match id {
-                CapWindowId::TargetSelectOverlay { .. } => {
-                    if window.is_visible().unwrap_or(false)
-                        || target_select_overlays_hidden_for_restore.contains(label.as_str())
-                    {
-                        show_overlay(&window);
-                    }
-                }
-                CapWindowId::Main => {
-                    let generation = clean_capture::generation(app);
-                    let _ = clean_capture::reveal_now(&window, generation);
-                    restore_main_window_inputs(app);
-                }
-                _ => {}
-            }
-        }
-    }
-}
-
-fn restore_main_window_inputs(app: &AppHandle) {
-    let handle = app.clone();
-    spawn_on_runtime(async move {
-        windows::restore_main_window_inputs(&handle).await;
-    });
-}
-
-fn restore_camera_window(app: &AppHandle) {
-    let snapshot = app.state::().snapshot();
-    if snapshot.camera.value.is_none() || snapshot.camera.pending || snapshot.camera.error.is_some()
-    {
-        return;
-    }
-    let app = app.clone();
-    spawn_on_runtime(async move {
-        let requested = app.state::();
-        let _input_operation = requested.operation.lock().await;
-        let operation_lock = app.state::();
-        let _operation_guard = operation_lock.lock().await;
-        let state = app.state::>();
-        let can_restore = {
-            let state = state.read().await;
-            requested.is_current(&snapshot)
-                && !state.is_recording_active_or_pending()
-                && !state.camera_cleanup_done
-                && state.selected_camera_id == snapshot.camera.value
-        };
-        if can_restore {
-            let _ = show_requested_camera_window(&app, snapshot.camera.revision).await;
-        }
-    });
-}
-
-fn close_target_select_overlays(app: &AppHandle) {
-    target_select_overlay::close_target_select_overlay_windows(app);
-}
-
-#[cfg(target_os = "windows")]
-fn reopen_main_window(app: &AppHandle) {
-    #[cfg(target_os = "linux")]
-    if let Some(attempt) = recording::linux_instant::current(app)
-        && attempt.has_capture()
-        && !attempt.ui_ready()
-    {
-        let app = app.clone();
-        drop(tauri::async_runtime::spawn(async move {
-            if recording::linux_instant::control(app.clone(), attempt, false)
-                .await
-                .is_ok()
-            {
-                let _ = ShowCapWindow::Main {
-                    init_target_mode: None,
-                }
-                .show(&app)
-                .await;
-            }
-        }));
-        return;
-    }
-    if let Some(main) = CapWindowId::Main.get(app) {
-        let _ = main.show();
-        let _ = main.set_focus();
-        restore_main_window_inputs(app);
-    } else {
-        let handle = app.clone();
-        tokio::spawn(async move {
-            let _ = ShowCapWindow::Main {
-                init_target_mode: None,
-            }
-            .show(&handle)
-            .await;
-        });
-    }
-}
-
-fn instant_upload_may_resume(inner: &RecordingMetaInner) -> bool {
-    !matches!(
-        inner,
-        RecordingMetaInner::Instant(
-            InstantRecordingMeta::InProgress { .. } | InstantRecordingMeta::Failed { .. }
-        )
-    )
-}
-
-#[cfg(test)]
-fn load_instant_resume_candidate(path: &std::path::Path) -> Result, String> {
-    load_upload_resume_candidate(path, true).map(|candidate| candidate.map(|(meta, _lock)| meta))
-}
-
-fn load_upload_resume_candidate(
-    path: &std::path::Path,
-    mark_crashed: bool,
-) -> Result, String> {
-    load_upload_resume_candidate_at(path, mark_crashed, SystemTime::now())
-}
-
-fn load_upload_resume_candidate_at(
-    path: &std::path::Path,
-    mark_crashed: bool,
-    now: SystemTime,
-) -> Result, String> {
-    if !mark_crashed && !upload::recovery_age::eligible(path, now) {
-        return Ok(None);
-    }
-    let lock = match upload::acquire_upload_lock(path) {
-        Ok(lock) => lock,
-        Err(_) => return Ok(None),
-    };
-    let mut meta = RecordingMeta::load_for_project(path).map_err(|error| error.to_string())?;
-    if mark_crashed {
-        let changed = match &mut meta.inner {
-            RecordingMetaInner::Instant(InstantRecordingMeta::InProgress { .. }) => {
-                meta.inner = RecordingMetaInner::Instant(InstantRecordingMeta::Failed {
-                    error: "Recording crashed".into(),
-                });
-                true
-            }
-            RecordingMetaInner::Studio(studio) => {
-                if let StudioRecordingMeta::MultipleSegments { inner } = &mut **studio
-                    && matches!(inner.status, Some(StudioRecordingStatus::InProgress))
-                {
-                    inner.status = Some(StudioRecordingStatus::Failed {
-                        error: "Recording crashed".into(),
-                    });
-                    true
-                } else {
-                    false
-                }
-            }
-            _ => false,
-        };
-        if changed {
-            meta.save_for_project().map_err(|error| error.to_string())?;
-        }
-    }
-    if !upload::recovery_age::eligible(path, now) {
-        return Ok(None);
-    }
-    upload::lifecycle::reconcile_reupload(&mut meta).map_err(|error| error.to_string())?;
-    Ok(instant_upload_may_resume(&meta.inner).then_some((meta, lock)))
-}
-
-async fn resume_uploads(app: AppHandle, mark_crashed: bool) -> Result<(), String> {
-    upload::lifecycle::reap().await;
-    if app_is_exiting(&app) || !upload::lifecycle::has_capacity() {
-        return Ok(());
-    }
-    let scan_app = app.clone();
-    let paths = tokio::task::spawn_blocking(move || {
-        let mut paths = Vec::new();
-        for directory in recordings_locations::known_recordings_dirs(&scan_app) {
-            let Ok(entries) = std::fs::read_dir(directory) else {
-                continue;
-            };
-            for entry in entries.flatten() {
-                if app_is_exiting(&scan_app) {
-                    return paths;
-                }
-                let path = entry.path();
-                if path.extension().and_then(|value| value.to_str()) == Some("cap")
-                    && (mark_crashed || upload::recovery_age::eligible(&path, SystemTime::now()))
-                {
-                    paths.push(path);
-                }
-            }
-        }
-        paths
-    })
-    .await
-    .map_err(|error| error.to_string())?;
-    for path in paths {
-        if app_is_exiting(&app) || !upload::lifecycle::has_capacity() {
-            break;
-        }
-        let candidate_path = path.clone();
-        let candidate_app = app.clone();
-        let candidate = tokio::task::spawn_blocking(move || {
-            let mark_crashed = mark_crashed
-                && candidate_app
-                    .state::()
-                    .predates_launch(&candidate_path);
-            load_upload_resume_candidate(&candidate_path, mark_crashed)
-        })
-        .await
-        .map_err(|error| error.to_string())?;
-        let (meta, lock) = match candidate {
-            Ok(Some(candidate)) => candidate,
-            Ok(None) => continue,
-            Err(error) => {
-                warn!(%error, recording = %path.display(), "Recording upload state could not be read; files retained");
-                continue;
-            }
-        };
-        if matches!(
-            meta.upload,
-            None | Some(UploadMeta::Complete | UploadMeta::Failed { .. })
-        ) {
-            continue;
-        }
-        let fallback_audio = matches!(
-            &meta.inner,
-            RecordingMetaInner::Instant(InstantRecordingMeta::Complete {
-                sample_rate: Some(_),
-                ..
-            })
-        );
-        let required_audio =
-            match upload::lifecycle::resume_audio(&app, &path, fallback_audio).await {
-                Ok(Some(required_audio)) => required_audio,
-                Ok(None) => continue,
-                Err(error) => {
-                    warn!(%error, "Recording upload intent could not be read; files retained");
-                    continue;
-                }
-            };
-        if let Err(error) =
-            upload::lifecycle::resume_existing(app.clone(), meta, lock, required_audio).await
-        {
-            warn!(%error, "Upload retry remains local");
-        }
-    }
-    Ok(())
-}
-
-async fn create_editor_instance_impl(
-    app: &AppHandle,
-    path: PathBuf,
-    frame_cb: cap_editor::EditorFrameCallback,
-) -> Result<(Arc, tauri::EventId), String> {
-    let app = app.clone();
-
-    wait_for_recording_ready(&app, &path).await?;
-
-    recording::spawn_heal_oversized_desktop_background_snapshots(path.clone());
-
-    let shared_device =
-        gpu_context::get_shared_gpu()
-            .await
-            .map(|shared| cap_rendering::SharedWgpuDevice {
-                instance: (*shared.instance).clone(),
-                adapter: (*shared.adapter).clone(),
-                device: (*shared.device).clone(),
-                queue: (*shared.queue).clone(),
-                is_software_adapter: shared.is_software_adapter,
-            });
-
-    #[cfg(debug_assertions)]
-    let frame_cb: cap_editor::EditorFrameCallback =
-        if stop_editor_benchmark::frame_capture_requested() {
-            let capture_path = path.clone();
-            let mut frame_cb = frame_cb;
-            Box::new(move |output, layout| {
-                stop_editor_benchmark::capture_output(
-                    stop_editor_benchmark::CaptureKind::Ordinary,
-                    &capture_path,
-                    &output,
-                );
-                frame_cb(output, layout);
-            })
-        } else {
-            frame_cb
-        };
-
-    let (audio_output, startup, live_handoff) = app
-        .state::()
-        .take_startup(&path)
-        .await?;
-    let instance = {
-        let app = app.clone();
-        EditorInstance::new_with_startup_inputs(
-            path,
-            move |state| {
-                let _ = EditorStateChanged::new(state).emit(&app);
-            },
-            frame_cb,
-            shared_device,
-            cap_editor::EditorFrameFormat::Rgba,
-            audio_output,
-            startup,
-        )
-        .await?
-    };
-
-    if let Some(handoff) = &live_handoff {
-        instance.install_preparing_handoff(handoff).await?;
-    }
-
-    let event_id = RenderFrameEvent::listen_checked(&app, {
-        let preview_tx = instance.preview_tx.clone();
-        move |e| {
-            preview_tx.send_modify(|v| {
-                *v = Some((e.frame_number, e.fps, e.resolution_base));
-            });
-        }
-    });
-
-    let started = match instance
-        .start_preparing_handoff(EDITOR_PREVIEW_FPS, default_editor_preview_resolution())
-        .await
-    {
-        Ok(started) => started,
-        Err(error) => {
-            app.unlisten(event_id);
-            let cleanup_failed = if let Some(handoff) = &live_handoff {
-                handoff.stop_and_wait().await.cleanup_failed
-            } else {
-                false
-            };
-            instance.dispose().await;
-            return Err(if cleanup_failed {
-                format!(
-                    "Preparing handoff start failed: {error:?}; preparing playback cleanup failed"
-                )
-            } else {
-                format!("Preparing handoff start failed: {error:?}")
-            });
-        }
-    };
-    if !started {
-        let frame = instance
-            .preparing_adoption()
-            .and_then(|adoption| adoption.frame_number(EDITOR_PREVIEW_FPS))
-            .unwrap_or(0);
-        instance.preview_tx.send_modify(|v| {
-            *v = Some((
-                frame,
-                EDITOR_PREVIEW_FPS,
-                default_editor_preview_resolution(),
-            ))
-        });
-    }
-
-    Ok((instance, event_id))
-}
-
-pub(crate) async fn wait_for_recording_ready(app: &AppHandle, path: &Path) -> Result<(), String> {
-    let result = wait_for_recording_ready_inner(app, path).await;
-    if result.is_err() {
-        let cleanup = editor_preparing::join_before_ordinary(app, path).await;
-        return result.and(cleanup);
-    }
-    result
-}
-
-async fn await_finalization_before_ordinary(
-    app: &AppHandle,
-    path: &Path,
-    result: watch::Receiver,
-) -> Result<(), String> {
-    let finalization = await_finalization_result(result).await;
-    let cleanup = editor_preparing::join_before_ordinary(app, path).await;
-    finalization.and(cleanup)
-}
-
-async fn wait_for_recording_ready_inner(app: &AppHandle, path: &Path) -> Result<(), String> {
-    let display_path = path;
-    let project = FinalizationProject::observe(path.to_path_buf()).await?;
-    let path = project.work_path();
-    let finalizing_state = app.state::();
-
-    if let Some(result) = finalizing_state.is_finalizing(&project) {
-        info!("Recording is being finalized, waiting for completion...");
-        await_finalization_before_ordinary(app, display_path, result).await?;
-        project.validate_async().await?;
-        info!("Recording finalization completed");
-        let meta = RecordingMeta::load_for_project(path)
-            .map_err(|e| format!("Failed to reload recording meta: {e}"))?;
-        if let Some(studio_meta) = meta.studio_meta() {
-            studio_meta.ensure_ordinary_media_access(path)?;
-        }
-        return Ok(());
-    }
-
-    editor_preparing::join_before_ordinary(app, display_path).await?;
-
-    let meta = match RecordingMeta::load_for_project(path) {
-        Ok(meta) => meta,
-        Err(e) => {
-            return Err(format!("Failed to load recording meta: {e}"));
-        }
-    };
-
-    if let Some(studio_meta) = meta.studio_meta()
-        && matches!(studio_meta.status(), StudioRecordingStatus::InProgress)
-    {
-        info!("Recording/import is in progress, waiting for completion...");
-        const POLL_INTERVAL: std::time::Duration = std::time::Duration::from_millis(250);
-        const MAX_WAIT: std::time::Duration = std::time::Duration::from_secs(600);
-        let start = std::time::Instant::now();
-
-        loop {
-            if start.elapsed() > MAX_WAIT {
-                return Err("Timed out waiting for import to complete".to_string());
-            }
-
-            tokio::time::sleep(POLL_INTERVAL).await;
-
-            project.validate_async().await?;
-            if let Some(result) = finalizing_state.is_finalizing(&project) {
-                await_finalization_before_ordinary(app, display_path, result).await?;
-                break;
-            }
-
-            let current_meta = match RecordingMeta::load_for_project(path) {
-                Ok(m) => m,
-                Err(_) => continue,
-            };
-
-            if let Some(current_studio) = current_meta.studio_meta() {
-                match current_studio.status() {
-                    StudioRecordingStatus::Complete => {
-                        info!("Recording/import completed");
-                        break;
-                    }
-                    StudioRecordingStatus::Failed { error } => {
-                        return Err(format!("Import failed: {error}"));
-                    }
-                    StudioRecordingStatus::InProgress => continue,
-                    StudioRecordingStatus::NeedsRemux => break,
-                }
-            }
-        }
-    }
-
-    project.validate_async().await?;
-    if let Some(result) = finalizing_state.is_finalizing(&project) {
-        await_finalization_before_ordinary(app, display_path, result).await?;
-        project.validate_async().await?;
-    }
-
-    let meta = RecordingMeta::load_for_project(path)
-        .map_err(|e| format!("Failed to reload recording meta: {e}"))?;
-    if let Some(studio_meta) = meta.studio_meta() {
-        studio_meta.ensure_ordinary_media_access(path)?;
-    }
-
-    if let Some(studio_meta) = meta.studio_meta()
-        && recording::needs_fragment_remux(path, studio_meta)
-    {
-        info!("Recording needs remux (crash recovery), starting remux...");
-        let work_project = FinalizationProject::admit(project.display_path().to_path_buf()).await?;
-        if work_project.identity != project.identity {
-            return Err(FinalizationProject::identity_error(
-                project.display_path(),
-                "Recording directory changed before recovery",
-            ));
-        }
-        match finalizing_state.request(work_project, false, FinalizationOrigin::Recording, false)? {
-            FinalizationRequest::Started(token) => {
-                run_finalization_worker(token, recording::remux_fragmented_recording).await?;
-            }
-            FinalizationRequest::Existing(result) => {
-                await_finalization_before_ordinary(app, display_path, result).await?
-            }
-        }
-        project.validate_async().await?;
-        info!("Crash recovery remux completed");
-    }
-
-    if meta.studio_meta().is_some() {
-        // Repair video tracks that were stamped at the wrong rate by older
-        // recorders (slow-motion display on high-refresh Windows monitors,
-        // 2x-length camera). Non-fatal: the editor still opens with the
-        // unhealed files if this fails.
-        let path = path.to_path_buf();
-        match tokio::task::spawn_blocking(move || {
-            cap_recording::track_heal::heal_stretched_tracks(&path)
-        })
-        .await
-        {
-            Ok(Ok(true)) => info!("Healed stretched video track(s)"),
-            Ok(Ok(false)) => {}
-            Ok(Err(e)) => warn!("Track heal check failed: {e:#}"),
-            Err(e) => warn!("Track heal task panicked: {e}"),
-        }
-    }
-
-    project.validate_async().await?;
-    Ok(())
-}
-
-fn recordings_path(app: &AppHandle) -> PathBuf {
-    general_settings::GeneralSettingsStore::recordings_dir(app)
-}
-
-// fn recording_path(app: &AppHandle, recording_id: &str) -> PathBuf {
-//     recordings_path(app).join(format!("{recording_id}.cap"))
-// }
-
-fn screenshots_path(app: &AppHandle) -> PathBuf {
-    let path = app.path().app_data_dir().unwrap().join("screenshots");
-    std::fs::create_dir_all(&path).unwrap_or_default();
-    path
-}
-
-// fn screenshot_path(app: &AppHandle, screenshot_id: &str) -> PathBuf {
-//     screenshots_path(app).join(format!("{screenshot_id}.cap"))
-// }
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-fn global_message_dialog(app: AppHandle, message: String) {
-    app.dialog().message(message).show(|_| {});
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(clipboard))]
-async fn write_clipboard_string(
-    clipboard: MutableState<'_, ClipboardContext>,
-    text: String,
-) -> Result<(), String> {
-    let writer = clipboard
-        .try_write()
-        .map_err(|e| format!("Failed to acquire lock on clipboard state: {e}"))?;
-    writer
-        .set_text(text)
-        .map_err(|e| format!("Failed to write text to clipboard: {e}"))
-}
-
-#[tauri::command(async)]
-#[specta::specta]
-fn format_project_name(
-    template: Option,
-    target_name: String,
-    target_kind: String,
-    recording_mode: RecordingMode,
-    datetime: Option>,
-) -> String {
-    recording::format_project_name(
-        template.as_deref(),
-        target_name.as_str(),
-        target_kind.as_str(),
-        recording_mode,
-        datetime,
-    )
-}
-
-trait EventExt: tauri_specta::Event {
-    fn listen_any_spawn(
-        app: &AppHandle,
-        handler: impl Fn(Self, AppHandle) -> Fut + Send + 'static + Clone,
-    ) -> tauri::EventId
-    where
-        Fut: Future + Send,
-        Self: serde::de::DeserializeOwned + Send + 'static,
-    {
-        let app = app.clone();
-        Self::listen_any(&app.clone(), move |e| {
-            let app = app.clone();
-            let handler = handler.clone();
-            tokio::spawn(async move {
-                (handler)(e.payload, app).await;
-            });
-        })
-    }
-}
-
-impl EventExt for T {}
-
-fn show_import_error_dialog(app: &AppHandle, message: String) {
-    app.dialog()
-        .message(message)
-        .title("Import Error")
-        .kind(tauri_plugin_dialog::MessageDialogKind::Error)
-        .show(|_| {});
-}
-
-/// Everything a close request on the main window does -- hide it, drop the
-/// preview inputs when nothing is recording, and hand the foreground back to
-/// the editor that started a "Record a new clip" flow.
-pub(crate) fn dismiss_main_window(app: &AppHandle) {
-    clean_capture::cancel_closed_preflight(app);
-    hide_main_window(app);
-
-    #[cfg(target_os = "macos")]
-    crate::permissions::schedule_macos_dock_visibility_sync(app);
-
-    let Some(state) = app.try_state::>() else {
-        warn!("App state unavailable during main window close request");
-        return;
-    };
-    let is_recording = state
-        .try_read()
-        .map(|s| s.is_recording_active_or_pending())
-        .unwrap_or(true);
-
-    if !is_recording {
-        if let Some(camera_window) = CapWindowId::Camera.get(app) {
-            let _ = camera_window.hide();
-        }
-
-        close_target_select_overlays(app);
-
-        let app_for_cleanup = app.clone();
-        spawn_on_runtime(async move {
-            let app = app_for_cleanup;
-            let Some(state) = app.try_state::>() else {
-                warn!("App state unavailable during main window close cleanup");
-                return;
-            };
-
-            let (mic_feed, camera_feed) = {
-                let mut app_state = state.write().await;
-                app_state.camera_preview.pause();
-                app_state.applied_mic_input.invalidate();
-                (app_state.mic_feed.clone(), app_state.camera_feed.clone())
-            };
-
-            let _ =
-                tokio::time::timeout(APP_EXIT_STEP_TIMEOUT, mic_feed.ask(microphone::RemoveInput))
-                    .await;
-            let _ = tokio::time::timeout(
-                APP_EXIT_STEP_TIMEOUT,
-                camera_feed.ask(feeds::camera::RemoveInput),
-            )
-            .await;
-
-            let mut app_state = state.write().await;
-            app_state.selected_mic_label = None;
-            app_state.camera_in_use = false;
-        });
-
-        if let Some(editor_path) = editor_recording::abort(app) {
-            editor_recording::reveal_editor(app, &editor_path);
-        }
-    }
-}
-
-pub(crate) fn hide_main_window(app: &AppHandle) {
-    if let Some(main_window) = CapWindowId::Main.get(app)
-        && main_window.hide().is_ok()
-    {
-        let _ = main_window.emit_to(CapWindowId::Main.label(), "main-window-hidden", ());
-    }
-}
-
-fn open_importable_from_path(path: &Path, app: AppHandle) -> Result<(), String> {
-    if import::is_supported_video_import_path(path) {
-        let source_path = path.to_path_buf();
-        tokio::spawn(async move {
-            match import::start_video_import(app.clone(), source_path).await {
-                Ok(project_path) => {
-                    if let Err(err) = (ShowCapWindow::Editor { project_path }).show(&app).await {
-                        error!("Failed to show imported video editor: {err}");
-                        show_import_error_dialog(
-                            &app,
-                            format!("Failed to open imported video: {err}"),
-                        );
-                        return;
-                    }
-
-                    hide_main_window(&app);
-                }
-                Err(err) => {
-                    error!("Failed to import dropped video: {err}");
-                    show_import_error_dialog(&app, format!("Failed to import video: {err}"));
-                }
-            }
-        });
-        return Ok(());
-    }
-
-    if import::is_supported_image_import_path(path) {
-        let source_path = path.to_path_buf();
-        tokio::spawn(async move {
-            match import::start_image_import(app.clone(), source_path).await {
-                Ok(path) => {
-                    if let Err(err) = (ShowCapWindow::ScreenshotEditor { path }).show(&app).await {
-                        error!("Failed to show imported image editor: {err}");
-                        show_import_error_dialog(
-                            &app,
-                            format!("Failed to open imported image: {err}"),
-                        );
-                        return;
-                    }
-
-                    hide_main_window(&app);
-                }
-                Err(err) => {
-                    error!("Failed to import dropped image: {err}");
-                    show_import_error_dialog(&app, format!("Failed to import image: {err}"));
-                }
-            }
-        });
-        return Ok(());
-    }
-
-    open_project_from_path(path, app)
-}
-
-fn open_project_from_path(path: &Path, app: AppHandle) -> Result<(), String> {
-    #[cfg(target_os = "macos")]
-    {
-        let gate = app
-            .try_state::()
-            .ok_or_else(|| "Cap startup is not ready to receive projects".to_string())?;
-        let ready = {
-            let queue = gate
-                .0
-                .lock()
-                .map_err(|_| "Cap startup file-open state is unavailable".to_string())?;
-            !queue.cancelled && queue.destination == Some(StartupOpenDestination::Desktop)
-        };
-        if !ready {
-            let path = if path.is_absolute() {
-                path.to_path_buf()
-            } else {
-                std::env::current_dir()
-                    .map_err(|error| error.to_string())?
-                    .join(path)
-            };
-            let url = tauri::Url::from_file_path(path)
-                .map_err(|_| "The requested project path is invalid".to_string())?;
-            return queue_macos_startup_urls(&app, vec![url]);
-        }
-    }
-
-    let meta = RecordingMeta::load_for_project(path).map_err(|v| v.to_string())?;
-
-    match &meta.inner {
-        RecordingMetaInner::Studio(meta) => {
-            let status = meta.status();
-            if let StudioRecordingStatus::Failed { .. } = status {
-                return Err("Unable to open failed recording".to_string());
-            } else if let StudioRecordingStatus::InProgress = status {
-                return Err("Recording in progress".to_string());
-            }
-
-            let project_path = path.to_path_buf();
-            tokio::spawn(async move {
-                if let Err(error) = (ShowCapWindow::Editor { project_path }).show(&app).await {
-                    warn!(%error, "Could not show the requested project editor");
-                }
-            });
-        }
-        RecordingMetaInner::Instant(_) => {
-            let mp4_path = path.join("content/output.mp4");
-
-            if mp4_path.exists() && mp4_path.is_file() {
-                let _ = app
-                    .opener()
-                    .open_path(mp4_path.to_str().unwrap_or_default(), None::);
-                hide_main_window(&app);
-            }
-        }
-    }
-
-    Ok(())
-}
-
-#[cfg(test)]
-mod startup_project_open_tests {
-    use super::{StartupOpenDestination, StartupOpenGate, StartupOpenGuard, StartupOpenQueue};
-
-    fn project(name: &str) -> tauri::Url {
-        tauri::Url::parse(&format!("file:///recordings/{name}.cap")).unwrap()
-    }
-
-    #[test]
-    fn early_file_opens_wait_for_full_desktop_startup() {
-        let mut queue = StartupOpenQueue::default();
-        let urls = vec![project("first"), project("second")];
-        assert!(queue.request(urls.clone()).unwrap().is_none());
-        let dispatch = queue.finish(StartupOpenDestination::Desktop).unwrap();
-        assert_eq!(dispatch.destination, StartupOpenDestination::Desktop);
-        assert_eq!(dispatch.urls, urls);
-        assert!(queue.urls.is_empty());
-        assert!(queue.finish(StartupOpenDestination::Desktop).is_none());
-    }
-
-    #[test]
-    fn queued_files_follow_gpui_handoff_without_opening_classic_editors() {
-        let mut queue = StartupOpenQueue::default();
-        let url = project("handoff");
-        assert!(queue.request(vec![url.clone()]).unwrap().is_none());
-        let dispatch = queue.finish(StartupOpenDestination::Gpui).unwrap();
-        assert_eq!(dispatch.destination, StartupOpenDestination::Gpui);
-        assert_eq!(dispatch.urls, [url]);
-        assert!(queue.request(vec![project("later")]).unwrap().is_none());
-        let dispatch = queue.next_gpui_batch().unwrap();
-        assert_eq!(dispatch.destination, StartupOpenDestination::Gpui);
-        assert_eq!(dispatch.urls, [project("later")]);
-    }
-
-    #[test]
-    fn normal_post_ready_file_opens_dispatch_immediately() {
-        let mut queue = StartupOpenQueue::default();
-        assert!(queue.finish(StartupOpenDestination::Desktop).is_none());
-        let url = project("ready");
-        let dispatch = queue.request(vec![url.clone()]).unwrap().unwrap();
-        assert_eq!(dispatch.destination, StartupOpenDestination::Desktop);
-        assert_eq!(dispatch.urls, [url]);
-    }
-
-    #[test]
-    fn failed_or_cancelled_setup_discards_pending_opens() {
-        let gate = StartupOpenGate::default();
-        let guard = StartupOpenGuard(gate.clone());
-        assert!(
-            gate.0
-                .lock()
-                .unwrap()
-                .request(vec![project("pending")])
-                .unwrap()
-                .is_none()
-        );
-        drop(guard);
-        let mut queue = gate.0.lock().unwrap();
-        assert!(queue.urls.is_empty());
-        assert!(queue.request(vec![project("later")]).is_err());
-        assert!(queue.finish(StartupOpenDestination::Desktop).is_none());
-        assert!(queue.finish(StartupOpenDestination::Gpui).is_none());
-    }
-
-    #[test]
-    fn completed_setup_guard_preserves_selected_destination() {
-        for destination in [
-            StartupOpenDestination::Desktop,
-            StartupOpenDestination::Gpui,
-        ] {
-            let gate = StartupOpenGate::default();
-            let guard = StartupOpenGuard(gate.clone());
-            assert!(gate.0.lock().unwrap().finish(destination).is_none());
-            drop(guard);
-            let dispatch = gate
-                .0
-                .lock()
-                .unwrap()
-                .request(vec![project("ready")])
-                .unwrap()
-                .unwrap();
-            assert_eq!(dispatch.destination, destination);
-        }
-    }
-
-    #[test]
-    fn pending_file_open_queue_is_bounded_and_deduplicates() {
-        let mut queue = StartupOpenQueue::default();
-        for _ in 0..100 {
-            assert!(queue.request(vec![project("same")]).unwrap().is_none());
-        }
-        assert_eq!(queue.urls.len(), 1);
-        let urls = (0..100).map(|index| project(&index.to_string())).collect();
-        assert!(queue.request(urls).is_err());
-        assert_eq!(queue.urls, [project("same")]);
-        let urls = (0..63).map(|index| project(&index.to_string())).collect();
-        assert!(queue.request(urls).unwrap().is_none());
-        assert_eq!(queue.urls.len(), 64);
-        assert!(queue.request(vec![project("overflow")]).is_err());
-    }
-
-    #[test]
-    fn gpui_handoff_drains_later_batches_without_duplicate_dispatches() {
-        let mut queue = StartupOpenQueue::default();
-        assert!(queue.finish(StartupOpenDestination::Gpui).is_none());
-        let first = queue.request(vec![project("first")]).unwrap().unwrap();
-        assert_eq!(first.urls, [project("first")]);
-        assert!(
-            queue
-                .request(vec![project("first"), project("second")])
-                .unwrap()
-                .is_none()
-        );
-        assert!(queue.request(vec![project("second")]).unwrap().is_none());
-        let second = queue.next_gpui_batch().unwrap();
-        assert_eq!(second.urls, [project("second")]);
-        assert_eq!(second.destination, StartupOpenDestination::Gpui);
-        assert!(queue.request(vec![project("third")]).unwrap().is_none());
-        assert_eq!(queue.next_gpui_batch().unwrap().urls, [project("third")]);
-        assert!(queue.next_gpui_batch().is_none());
-        assert!(queue.request(vec![project("after-exit")]).is_err());
-    }
-
-    #[test]
-    fn cancellation_stops_desktop_dispatch_and_gpui_pending_batches() {
-        for destination in [
-            StartupOpenDestination::Desktop,
-            StartupOpenDestination::Gpui,
-        ] {
-            let mut queue = StartupOpenQueue::default();
-            assert!(queue.finish(destination).is_none());
-            assert!(queue.request(vec![project("first")]).unwrap().is_some());
-            let _ = queue.request(vec![project("pending")]).unwrap();
-            queue.cancel();
-            assert!(queue.request(vec![project("after-exit")]).is_err());
-            assert!(queue.next_gpui_batch().is_none());
-            assert!(queue.urls.is_empty());
-            assert!(queue.gpui_dispatched.is_empty());
-        }
-    }
-}
-
-#[cfg(test)]
-mod editor_title_save_tests {
-    use super::{AppExitState, EditorTitleSaveResponse, wait_for_editor_title_saves};
-    use std::{collections::HashSet, time::Duration};
-    use tokio::sync::mpsc;
-
-    fn response(request: &str, window: &str, error: Option<&str>) -> EditorTitleSaveResponse {
-        EditorTitleSaveResponse {
-            request_id: request.into(),
-            window_label: window.into(),
-            error: error.map(str::to_string),
-        }
-    }
-
-    #[test]
-    fn failed_title_flush_releases_admission_without_stopping_device_watchers() {
-        let state = AppExitState::default();
-        let pending = state.begin_title_flush().unwrap();
-        assert!(state.exit_pending());
-        assert!(!state.is_exiting());
-        assert!(state.begin_title_flush().is_none());
-        drop(pending);
-        assert!(!state.exit_pending());
-        assert!(!state.is_exiting());
-        let pending = state.begin_title_flush().unwrap();
-        assert!(state.begin());
-        drop(pending);
-        assert!(state.is_exiting());
-        assert!(state.exit_pending());
-    }
-
-    #[tokio::test]
-    async fn quit_waits_for_every_editor_and_ignores_stale_or_duplicate_responses() {
-        let (sender, responses) = mpsc::unbounded_channel();
-        let pending = HashSet::from(["editor-1".into(), "editor-2".into()]);
-        sender.send(response("previous", "editor-1", None)).unwrap();
-        sender.send(response("current", "unknown", None)).unwrap();
-        sender.send(response("current", "editor-1", None)).unwrap();
-        sender.send(response("current", "editor-1", None)).unwrap();
-        let waiting =
-            wait_for_editor_title_saves("current", pending, responses, Duration::from_secs(1));
-        tokio::pin!(waiting);
-        assert!(futures::poll!(&mut waiting).is_pending());
-        sender.send(response("current", "editor-2", None)).unwrap();
-        assert_eq!(waiting.await, Ok(()));
-    }
-
-    #[tokio::test]
-    async fn one_editor_save_failure_prevents_quit() {
-        let (sender, responses) = mpsc::unbounded_channel();
-        sender
-            .send(response("current", "editor-1", Some("disk full")))
-            .unwrap();
-        let result = wait_for_editor_title_saves(
-            "current",
-            HashSet::from(["editor-1".into(), "editor-2".into()]),
-            responses,
-            Duration::from_secs(1),
-        )
-        .await;
-        assert!(result.unwrap_err().contains("disk full"));
-    }
-
-    #[tokio::test]
-    async fn missing_editor_acknowledgement_does_not_authorize_quit() {
-        let (_sender, responses) = mpsc::unbounded_channel();
-        let result = wait_for_editor_title_saves(
-            "current",
-            HashSet::from(["editor-1".into()]),
-            responses,
-            Duration::from_millis(1),
-        )
-        .await;
-        assert!(result.unwrap_err().contains("Could not confirm"));
-    }
-
-    #[tokio::test]
-    async fn closed_response_channel_does_not_authorize_quit() {
-        let (sender, responses) = mpsc::unbounded_channel();
-        drop(sender);
-        let result = wait_for_editor_title_saves(
-            "current",
-            HashSet::from(["editor-1".into()]),
-            responses,
-            Duration::from_secs(1),
-        )
-        .await;
-        assert!(result.unwrap_err().contains("connection closed"));
-    }
-
-    #[tokio::test]
-    async fn no_editor_requires_no_acknowledgement() {
-        let (_sender, responses) = mpsc::unbounded_channel();
-        assert_eq!(
-            wait_for_editor_title_saves(
-                "current",
-                HashSet::new(),
-                responses,
-                Duration::from_millis(1),
-            )
-            .await,
-            Ok(())
-        );
-    }
-}
-
-#[cfg(test)]
-mod studio_microphone_ownership_tests {
-    use super::{
-        MicrophoneRemovalError, RequestedInputsState, acknowledge_studio_microphone,
-        replace_owned_microphone, wait_for_microphone_removal,
-    };
-    use std::{
-        path::{Path, PathBuf},
-        sync::{
-            Arc, Mutex,
-            atomic::{AtomicBool, AtomicUsize, Ordering},
-        },
-        time::Duration,
-    };
-    use tokio::sync::oneshot;
-
-    struct Lock {
-        drops: Arc,
-        unlock: Option>,
-    }
-
-    impl Drop for Lock {
-        fn drop(&mut self) {
-            self.drops.fetch_add(1, Ordering::SeqCst);
-            if let Some(unlock) = self.unlock.take() {
-                let _ = unlock.send(());
-            }
-        }
-    }
-
-    #[tokio::test]
-    async fn detach_drops_app_lock_after_ack_and_waits_for_unlock_and_removal() {
-        let drops = Arc::new(AtomicUsize::new(0));
-        let (unlock_tx, unlock_rx) = oneshot::channel();
-        let lock = Arc::new(Lock {
-            drops: drops.clone(),
-            unlock: Some(unlock_tx),
-        });
-        let app_slot = Mutex::new(Some(lock.clone()));
-        let actor_slot = Mutex::new(Some(lock));
-        let (ack_tx, ack_rx) = oneshot::channel();
-        let unlocked = AtomicBool::new(false);
-        let removed = AtomicBool::new(false);
-        let attempts = AtomicUsize::new(0);
-        let transition = async {
-            acknowledge_studio_microphone(
-                async {
-                    ack_rx.await.unwrap();
-                    drop(actor_slot.lock().unwrap().take());
-                    Ok(())
-                },
-                async {
-                    replace_owned_microphone(
-                        Path::new("owner"),
-                        Some((Path::new("owner"), &mut *app_slot.lock().unwrap())),
-                        None,
-                    )
-                },
-                "detaching",
-            )
-            .await
-            .unwrap();
-            assert_eq!(drops.load(Ordering::SeqCst), 1);
-            wait_for_microphone_removal(|| async {
-                attempts.fetch_add(1, Ordering::SeqCst);
-                if unlocked.load(Ordering::SeqCst) {
-                    removed.store(true, Ordering::SeqCst);
-                    Ok(())
-                } else {
-                    Err(MicrophoneRemovalError::Locked)
-                }
-            })
-            .await
-            .unwrap();
-        };
-        tokio::join!(
-            biased;
-            transition,
-            async {
-                assert!(app_slot.lock().unwrap().is_some());
-                assert_eq!(drops.load(Ordering::SeqCst), 0);
-                ack_tx.send(()).unwrap();
-                unlock_rx.await.unwrap();
-                assert!(!removed.load(Ordering::SeqCst));
-                tokio::time::sleep(Duration::from_millis(10)).await;
-                unlocked.store(true, Ordering::SeqCst);
-            }
-        );
-        assert!(removed.load(Ordering::SeqCst));
-        assert!(attempts.load(Ordering::SeqCst) >= 2);
-    }
-
-    #[tokio::test]
-    async fn failed_detach_keeps_app_ownership() {
-        let drops = Arc::new(AtomicUsize::new(0));
-        let mut slot = Some(Arc::new(Lock {
-            drops: drops.clone(),
-            unlock: None,
-        }));
-        let result = acknowledge_studio_microphone(
-            async { Err("Pause before changing input".into()) },
-            async {
-                replace_owned_microphone(
-                    Path::new("owner"),
-                    Some((Path::new("owner"), &mut slot)),
-                    None,
-                )
-            },
-            "detaching",
-        )
-        .await;
-        assert!(result.is_err());
-        assert!(slot.is_some());
-        assert_eq!(drops.load(Ordering::SeqCst), 0);
-    }
-
-    #[tokio::test]
-    async fn timed_out_detach_keeps_app_ownership() {
-        let mut slot = Some(Arc::new(1));
-        let result = acknowledge_studio_microphone(
-            std::future::pending(),
-            async {
-                replace_owned_microphone(
-                    Path::new("owner"),
-                    Some((Path::new("owner"), &mut slot)),
-                    None,
-                )
-            },
-            "detaching",
-        )
-        .await;
-        assert!(result.unwrap_err().contains("Timed out"));
-        assert!(slot.is_some());
-    }
-
-    #[tokio::test]
-    async fn stale_successful_attachment_retains_actual_arc_for_next_request() {
-        let requests = RequestedInputsState::new(Some("A".into()), None);
-        let revision = requests
-            .inner
-            .lock()
-            .unwrap()
-            .microphone
-            .begin(Some("B".into()));
-        let lock = Arc::new(42);
-        let actor_slot = Mutex::new(None);
-        let app_slot = Mutex::new(None);
-        let (tx, rx) = oneshot::channel();
-        let (result, ()) = tokio::join!(
-            biased;
-            acknowledge_studio_microphone(
-                async { rx.await.unwrap(); *actor_slot.lock().unwrap() = Some(lock.clone()); Ok(()) },
-                async { replace_owned_microphone(Path::new("owner"), Some((Path::new("owner"), &mut *app_slot.lock().unwrap())), Some(lock.clone())) },
-                "attaching",
-            ),
-            async {
-                assert!(app_slot.lock().unwrap().is_none());
-                let _revision = requests.inner.lock().unwrap().microphone.begin(None);
-                tx.send(()).unwrap();
-            }
-        );
-        result.unwrap();
-        assert!(!requests.mic_is_current(revision));
-        assert!(Arc::ptr_eq(
-            app_slot.lock().unwrap().as_ref().unwrap(),
-            actor_slot.lock().unwrap().as_ref().unwrap()
-        ));
-    }
-
-    #[tokio::test]
-    async fn failed_attachment_does_not_retain_new_lock() {
-        let mut slot: Option> = None;
-        let result = acknowledge_studio_microphone(
-            async { Err("Studio stopped".into()) },
-            async {
-                replace_owned_microphone(
-                    Path::new("owner"),
-                    Some((Path::new("owner"), &mut slot)),
-                    Some(Arc::new(42)),
-                )
-            },
-            "attaching",
-        )
-        .await;
-        assert!(result.is_err());
-        assert!(slot.is_none());
-    }
-
-    #[tokio::test]
-    async fn stop_or_replacement_during_ack_does_not_overwrite_another_owner() {
-        for next_owner in [None, Some(PathBuf::from("new-owner"))] {
-            let requests = RequestedInputsState::new(None, None);
-            let _operation = requests.operation.lock().await;
-            let owner = Mutex::new(Some(PathBuf::from("old-owner")));
-            let new_lock = Arc::new(9);
-            let slot = Mutex::new(Some(new_lock.clone()));
-            let (tx, rx) = oneshot::channel();
-            let (result, ()) = tokio::join!(
-                biased;
-                acknowledge_studio_microphone(
-                    async { rx.await.unwrap(); Ok(()) },
-                    async {
-                        let owner = owner.lock().unwrap();
-                        let mut slot = slot.lock().unwrap();
-                        replace_owned_microphone(Path::new("old-owner"), owner.as_deref().map(|owner| (owner, &mut *slot)), Some(Arc::new(42)))
-                    },
-                    "attaching",
-                ),
-                async { *owner.lock().unwrap() = next_owner; tx.send(()).unwrap(); }
-            );
-            assert!(result.is_err());
-            assert!(Arc::ptr_eq(
-                slot.lock().unwrap().as_ref().unwrap(),
-                &new_lock
-            ));
-        }
-    }
-
-    #[tokio::test]
-    async fn locked_input_is_not_reported_removed_at_the_deadline() {
-        let result = tokio::time::timeout(
-            Duration::from_secs(2),
-            wait_for_microphone_removal(|| async { Err(MicrophoneRemovalError::Locked) }),
-        )
-        .await
-        .unwrap();
-        assert!(result.is_err());
-    }
-
-    #[tokio::test]
-    async fn unresponsive_remove_ask_is_bounded() {
-        let result = tokio::time::timeout(
-            Duration::from_secs(2),
-            wait_for_microphone_removal(std::future::pending),
-        )
-        .await
-        .unwrap();
-        assert!(result.unwrap_err().contains("Timed out"));
-    }
-
-    #[tokio::test]
-    async fn pending_microphone_change_blocks_resume() {
-        let requests = RequestedInputsState::new(Some("A".into()), None);
-        let _revision = requests
-            .inner
-            .lock()
-            .unwrap()
-            .microphone
-            .begin(Some("B".into()));
-        let error = requests.try_resume_guard().unwrap_err();
-        assert!(error.contains("still being configured"));
-    }
-
-    #[tokio::test]
-    async fn failed_microphone_change_blocks_resume_until_reselected() {
-        let requests = RequestedInputsState::new(Some("A".into()), None);
-        let revision = requests
-            .inner
-            .lock()
-            .unwrap()
-            .microphone
-            .begin(Some("B".into()));
-        requests
-            .inner
-            .lock()
-            .unwrap()
-            .microphone
-            .finish(revision, &Err("B unavailable".into()));
-        assert!(
-            requests
-                .try_resume_guard()
-                .unwrap_err()
-                .contains("B unavailable")
-        );
-        let none = requests.inner.lock().unwrap().microphone.begin(None);
-        requests
-            .inner
-            .lock()
-            .unwrap()
-            .microphone
-            .finish(none, &Ok(()));
-        assert!(requests.try_resume_guard().is_ok());
-    }
-
-    #[tokio::test]
-    async fn camera_setup_also_blocks_resume() {
-        let requests = RequestedInputsState::new(None, None);
-        let _revision = requests.inner.lock().unwrap().camera.begin(None);
-        assert!(requests.try_resume_guard().unwrap_err().contains("camera"));
-    }
-
-    #[tokio::test]
-    async fn resume_rejects_busy_operation_without_waiting_for_it() {
-        let requests = RequestedInputsState::new(None, None);
-        let _operation = requests.operation.lock().await;
-        assert!(
-            requests
-                .try_resume_guard()
-                .unwrap_err()
-                .contains("Input change in progress")
-        );
-    }
-
-    #[tokio::test]
-    async fn healthy_resume_holds_operation_until_actor_acknowledgement() {
-        let requests = RequestedInputsState::new(Some("A".into()), None);
-        let (tx, rx) = oneshot::channel();
-        tokio::join!(
-            biased;
-            async {
-                let _guard = requests.try_resume_guard().unwrap();
-                rx.await.unwrap();
-            },
-            async {
-                assert!(requests.operation.try_lock().is_err());
-                tx.send(()).unwrap();
-            }
-        );
-        assert!(requests.operation.try_lock().is_ok());
-    }
-
-    #[tokio::test]
-    async fn non_lock_failure_is_not_retried() {
-        let attempts = AtomicUsize::new(0);
-        let result = wait_for_microphone_removal(|| async {
-            attempts.fetch_add(1, Ordering::SeqCst);
-            Err(MicrophoneRemovalError::Failed("Actor unavailable".into()))
-        })
-        .await;
-        assert_eq!(result.unwrap_err(), "Actor unavailable");
-        assert_eq!(attempts.load(Ordering::SeqCst), 1);
-    }
-}
-
-#[cfg(test)]
-mod applied_microphone_tests {
-    use super::{
-        AppliedMicrophoneInput, RequestedInputsState, finish_microphone_input_change,
-        wait_for_microphone_setup,
-    };
-    use std::sync::Mutex;
-    use tokio::sync::oneshot;
-
-    #[tokio::test]
-    async fn microphone_configuration_accepts_native_startup_longer_than_legacy_deadline() {
-        let result = wait_for_microphone_setup(async {
-            tokio::time::sleep(std::time::Duration::from_millis(1600)).await;
-            Ok(())
-        })
-        .await;
-        assert_eq!(result, Ok(()));
-    }
-
-    #[tokio::test]
-    async fn microphone_configuration_preserves_backend_failure() {
-        let result = wait_for_microphone_setup(async { Err("device disconnected".into()) }).await;
-        assert_eq!(result, Err("device disconnected".into()));
-    }
-
-    #[derive(Default)]
-    struct Feed {
-        applied: AppliedMicrophoneInput,
-        selected: Option,
-        actual: Option,
-        attached: Option,
-        active: bool,
-        set_count: usize,
-        remove_count: usize,
-        detach_count: usize,
-        attach_count: usize,
-    }
-
-    impl Feed {
-        fn healthy_active() -> Self {
-            Self {
-                applied: AppliedMicrophoneInput {
-                    valid: true,
-                    generation: 0,
-                    settings: None,
-                },
-                selected: Some("A".into()),
-                actual: Some("A".into()),
-                attached: Some("A".into()),
-                active: true,
-                ..Default::default()
-            }
-        }
-    }
-
-    async fn apply(
-        feed: &Mutex,
-        requests: &RequestedInputsState,
-        label: Option<&str>,
-        revision: u64,
-        ready: oneshot::Receiver<()>,
-        fail: bool,
-    ) -> Result<(), String> {
-        let generation = {
-            let mut feed = feed.lock().unwrap();
-            let active = feed.active;
-            let selected = feed.selected.clone();
-            if !feed
-                .applied
-                .prepare_change(active, label, selected.as_deref())
-            {
-                return Ok(());
-            }
-            feed.applied.generation
-        };
-        let result = finish_microphone_input_change(
-            async {
-                {
-                    let mut feed = feed.lock().unwrap();
-                    if feed.active {
-                        feed.detach_count += 1;
-                        feed.attached = None;
-                    }
-                }
-                ready.await.unwrap();
-                let mut feed = feed.lock().unwrap();
-                if label.is_some() {
-                    feed.set_count += 1;
-                } else {
-                    feed.remove_count += 1;
-                }
-                feed.actual = if fail {
-                    None
-                } else {
-                    label.map(str::to_string)
-                };
-                if fail {
-                    Err("Setup failed".into())
-                } else {
-                    Ok(())
-                }
-            },
-            || requests.mic_is_current(revision),
-            async {
-                let mut feed = feed.lock().unwrap();
-                if feed.active && label.is_some() {
-                    feed.attach_count += 1;
-                    feed.attached = feed.actual.clone();
-                }
-                Ok(())
-            },
-        )
-        .await;
-        if result.is_ok() {
-            let mut confirmed = false;
-            requests.publish_mic_if_current(revision, || {
-                let mut feed = feed.lock().unwrap();
-                if feed.applied.confirm_if_current(generation) {
-                    feed.selected = label.map(str::to_string);
-                    confirmed = true;
-                }
-            });
-            if !confirmed {
-                return Err("Input changed during setup".into());
-            }
-        }
-        result
-    }
-
-    fn ready() -> oneshot::Receiver<()> {
-        let (tx, rx) = oneshot::channel();
-        tx.send(()).unwrap();
-        rx
-    }
-
-    #[tokio::test]
-    async fn stale_a_then_none_removes_actual_input_even_when_metadata_is_none() {
-        let feed = Mutex::new(Feed::default());
-        let requests = RequestedInputsState::new(None, None);
-        let a = requests
-            .inner
-            .lock()
-            .unwrap()
-            .microphone
-            .begin(Some("A".into()));
-        let (tx, rx) = oneshot::channel();
-        let (old, none) = tokio::join!(apply(&feed, &requests, Some("A"), a, rx, false), async {
-            let none = requests.inner.lock().unwrap().microphone.begin(None);
-            tx.send(()).unwrap();
-            none
-        });
-        assert!(old.is_err());
-        {
-            let feed = feed.lock().unwrap();
-            assert_eq!(feed.actual.as_deref(), Some("A"));
-            assert!(feed.selected.is_none());
-            assert!(!feed.applied.valid);
-        }
-        apply(&feed, &requests, None, none, ready(), false)
-            .await
-            .unwrap();
-        let feed = feed.lock().unwrap();
-        assert!(feed.actual.is_none());
-        assert_eq!(feed.remove_count, 1);
-    }
-
-    #[tokio::test]
-    async fn stale_b_then_a_restores_actual_feed_and_studio_attachment() {
-        let feed = Mutex::new(Feed::healthy_active());
-        let requests = RequestedInputsState::new(Some("A".into()), None);
-        let b = requests
-            .inner
-            .lock()
-            .unwrap()
-            .microphone
-            .begin(Some("B".into()));
-        let (tx, rx) = oneshot::channel();
-        let (old, a) = tokio::join!(apply(&feed, &requests, Some("B"), b, rx, false), async {
-            let a = requests
-                .inner
-                .lock()
-                .unwrap()
-                .microphone
-                .begin(Some("A".into()));
-            tx.send(()).unwrap();
-            a
-        });
-        assert!(old.is_err());
-        assert!(feed.lock().unwrap().attached.is_none());
-        apply(&feed, &requests, Some("A"), a, ready(), false)
-            .await
-            .unwrap();
-        let feed = feed.lock().unwrap();
-        assert_eq!(feed.actual.as_deref(), Some("A"));
-        assert_eq!(feed.attached.as_deref(), Some("A"));
-        assert_eq!(feed.set_count, 2);
-        assert_eq!(feed.detach_count, 2);
-        assert_eq!(feed.attach_count, 1);
-    }
-
-    #[tokio::test]
-    async fn failed_b_leaves_dirty_state_and_a_cannot_reuse_metadata() {
-        let feed = Mutex::new(Feed::healthy_active());
-        let requests = RequestedInputsState::new(Some("A".into()), None);
-        let b = requests
-            .inner
-            .lock()
-            .unwrap()
-            .microphone
-            .begin(Some("B".into()));
-        assert!(
-            apply(&feed, &requests, Some("B"), b, ready(), true)
-                .await
-                .is_err()
-        );
-        {
-            let feed = feed.lock().unwrap();
-            assert_eq!(feed.selected.as_deref(), Some("A"));
-            assert!(feed.actual.is_none());
-            assert!(feed.attached.is_none());
-            assert!(!feed.applied.valid);
-        }
-        let a = requests
-            .inner
-            .lock()
-            .unwrap()
-            .microphone
-            .begin(Some("A".into()));
-        apply(&feed, &requests, Some("A"), a, ready(), false)
-            .await
-            .unwrap();
-        let feed = feed.lock().unwrap();
-        assert_eq!(feed.actual.as_deref(), Some("A"));
-        assert_eq!(feed.attached.as_deref(), Some("A"));
-        assert_eq!(feed.set_count, 2);
-        assert_eq!(feed.attach_count, 1);
-    }
-
-    #[tokio::test]
-    async fn disconnect_during_setup_cannot_restore_validity() {
-        let feed = Mutex::new(Feed::healthy_active());
-        let requests = RequestedInputsState::new(Some("A".into()), None);
-        let b = requests
-            .inner
-            .lock()
-            .unwrap()
-            .microphone
-            .begin(Some("B".into()));
-        let (tx, rx) = oneshot::channel();
-        let (result, ()) = tokio::join!(
-            biased;
-            apply(&feed, &requests, Some("B"), b, rx, false),
-            async {
-                feed.lock().unwrap().applied.invalidate();
-                tx.send(()).unwrap();
-            }
-        );
-        assert!(result.is_err());
-        let feed = feed.lock().unwrap();
-        assert!(!feed.applied.valid);
-        assert_eq!(feed.selected.as_deref(), Some("A"));
-    }
-
-    #[tokio::test]
-    async fn healthy_active_same_input_has_zero_setup_or_detach() {
-        let feed = Mutex::new(Feed::healthy_active());
-        let requests = RequestedInputsState::new(Some("A".into()), None);
-        let a = requests
-            .inner
-            .lock()
-            .unwrap()
-            .microphone
-            .begin(Some("A".into()));
-        apply(&feed, &requests, Some("A"), a, ready(), false)
-            .await
-            .unwrap();
-        let feed = feed.lock().unwrap();
-        assert_eq!(feed.set_count, 0);
-        assert_eq!(feed.detach_count, 0);
-        assert_eq!(feed.attach_count, 0);
-        assert_eq!(feed.attached.as_deref(), Some("A"));
-    }
-}
-
-#[cfg(test)]
-mod microphone_permission_tests {
-    use super::{RequestedInput, check_requested_microphone_permission};
-
-    #[test]
-    fn disabled_microphone_bypasses_permission() {
-        check_requested_microphone_permission(None, || {
-            panic!("turning the microphone off must not require permission")
-        })
-        .unwrap();
-    }
-
-    #[test]
-    fn saved_microphone_permission_failure_retains_intent_and_blocks_start() {
-        let mut input = RequestedInput::new(Some("Saved microphone".to_string()));
-        let revision = input.revision;
-        let result = check_requested_microphone_permission(input.value.as_deref(), || {
-            Err("Allow microphone access in System Settings".into())
-        });
-        assert!(input.prepare_restore(revision));
-        input.finish(revision, &result);
-        assert_eq!(input.value.as_deref(), Some("Saved microphone"));
-        assert!(!input.pending);
-        assert!(
-            input
-                .validate("microphone")
-                .unwrap_err()
-                .contains("System Settings")
-        );
-    }
-
-    #[test]
-    fn revoked_access_blocks_current_selection_until_reselected_after_grant() {
-        let mut input = RequestedInput::new(Some("Saved microphone".to_string()));
-        let denied = input.begin(Some("Saved microphone".into()));
-        let result = check_requested_microphone_permission(input.value.as_deref(), || {
-            Err("Microphone access is blocked".into())
-        });
-        input.finish(denied, &result);
-        assert!(input.validate("microphone").is_err());
-        let granted = input.begin(Some("Saved microphone".into()));
-        let result = check_requested_microphone_permission(input.value.as_deref(), || Ok(()));
-        input.finish(granted, &result);
-        assert!(input.validate("microphone").is_ok());
-        assert_eq!(input.value.as_deref(), Some("Saved microphone"));
-    }
-
-    #[test]
-    fn stale_permission_failure_cannot_replace_a_newer_selection() {
-        let mut input = RequestedInput::::new(None);
-        let old = input.begin(Some("Old microphone".into()));
-        let current = input.begin(Some("New microphone".into()));
-        let result = check_requested_microphone_permission(Some("Old microphone"), || {
-            Err("Microphone access is blocked".into())
-        });
-        input.finish(old, &result);
-        assert!(input.pending);
-        assert!(input.error.is_none());
-        input.finish(current, &Ok(()));
-        assert_eq!(input.value.as_deref(), Some("New microphone"));
-        assert!(input.validate("microphone").is_ok());
-    }
-
-    #[test]
-    fn explicit_off_clears_permission_failure_and_ignores_old_completion() {
-        let mut input = RequestedInput::new(Some("Saved microphone".to_string()));
-        let old = input.begin(Some("Saved microphone".into()));
-        input.finish(old, &Err("Microphone access is blocked".into()));
-        let off = input.begin(None);
-        let result = check_requested_microphone_permission(input.value.as_deref(), || {
-            panic!("turning the microphone off must not require permission")
-        });
-        input.finish(off, &result);
-        input.finish(old, &Err("Old permission failure".into()));
-        assert!(input.value.is_none());
-        assert!(input.validate("microphone").is_ok());
-    }
-}
-
-#[cfg(test)]
-mod requested_inputs_tests {
-    use super::{RequestedInput, RequestedInputsState, wait_for_existing_input};
-
-    #[test]
-    fn matching_pending_requests_share_setup_but_changed_configuration_supersedes_it() {
-        let mut input = RequestedInput::new(None::);
-        let settings = serde_json::json!({ "sampleRate": 48_000 });
-        let (first, joined) = input.begin_or_join(Some("mic".into()), settings.clone(), false);
-        assert!(!joined);
-        assert_eq!(
-            input.begin_or_join(Some("mic".into()), settings.clone(), false),
-            (first, true)
-        );
-        let (second, joined) = input.begin_or_join(
-            Some("mic".into()),
-            serde_json::json!({ "sampleRate": 44_100 }),
-            false,
-        );
-        assert!(!joined);
-        assert_ne!(first, second);
-        input.finish(first, &Ok(()));
-        assert!(input.pending);
-        input.finish(second, &Err("disconnected".into()));
-        let (retry, joined) = input.begin_or_join(Some("mic".into()), settings, false);
-        assert!(!joined);
-        assert_ne!(retry, second);
-    }
-
-    #[tokio::test]
-    async fn restoring_identical_inputs_during_startup_keeps_recording_publishable() {
-        let state = RequestedInputsState::new(None, None);
-        let mic = Some("MacBook Pro Microphone".to_string());
-        let camera = Some(super::DeviceOrModelID::DeviceID(
-            "MacBook Pro Camera".into(),
-        ));
-        let mic_settings = serde_json::json!(null);
-        let camera_settings = serde_json::json!((None::, false));
-        let (mic_revision, camera_revision) = {
-            let mut inputs = state.inner.lock().unwrap();
-            let (mic_revision, _) =
-                inputs
-                    .microphone
-                    .begin_or_join(mic.clone(), mic_settings.clone(), false);
-            inputs.microphone.finish(mic_revision, &Ok(()));
-            let (camera_revision, _) =
-                inputs
-                    .camera
-                    .begin_or_join(camera.clone(), camera_settings.clone(), false);
-            inputs.camera.finish(camera_revision, &Ok(()));
-            (mic_revision, camera_revision)
-        };
-        let snapshot = state.ready_snapshot().unwrap();
-        let _startup = state.operation.lock().await;
-        {
-            let mut inputs = state.inner.lock().unwrap();
-            assert_eq!(
-                inputs.microphone.begin_or_join(mic, mic_settings, true),
-                (mic_revision, true)
-            );
-            assert_eq!(
-                inputs.camera.begin_or_join(camera, camera_settings, true),
-                (camera_revision, true)
-            );
-        }
-        for (revision, kind) in [(mic_revision, "Microphone"), (camera_revision, "Camera")] {
-            let result = tokio::time::timeout(std::time::Duration::from_millis(100), async {
-                if kind == "Microphone" {
-                    wait_for_existing_input(revision, kind, || state.snapshot().microphone).await
-                } else {
-                    wait_for_existing_input(revision, kind, || state.snapshot().camera).await
-                }
-            })
-            .await
-            .unwrap();
-            assert_eq!(result, Ok(()));
-        }
-        assert!(state.ready_snapshot().is_ok());
-        assert!(state.is_current(&snapshot));
-        let mut published = false;
-        assert!(state.publish_if_current(&snapshot, || published = true));
-        assert!(published);
-    }
-
-    #[test]
-    fn startup_still_rejects_changed_devices_settings_and_disabled_inputs() {
-        for (value, settings) in [
-            (Some("other".to_string()), serde_json::json!(48_000)),
-            (Some("mic".to_string()), serde_json::json!(44_100)),
-            (None, serde_json::json!(48_000)),
-        ] {
-            let state = RequestedInputsState::new(None, None);
-            {
-                let mut inputs = state.inner.lock().unwrap();
-                let (revision, _) = inputs.microphone.begin_or_join(
-                    Some("mic".into()),
-                    serde_json::json!(48_000),
-                    false,
-                );
-                inputs.microphone.finish(revision, &Ok(()));
-            }
-            let snapshot = state.ready_snapshot().unwrap();
-            let (_, joined) = state
-                .inner
-                .lock()
-                .unwrap()
-                .microphone
-                .begin_or_join(value, settings, true);
-            assert!(!joined);
-            assert!(!state.is_current(&snapshot));
-            assert!(!state.publish_if_current(&snapshot, || panic!("changed input published")));
-        }
-    }
-
-    #[test]
-    fn completed_requests_are_retried_when_idle_or_previously_failed() {
-        for (recording_starting, result) in
-            [(false, Ok(())), (true, Err("disconnected".to_string()))]
-        {
-            let mut input = RequestedInput::new(None::);
-            let (first, _) =
-                input.begin_or_join(Some("mic".into()), serde_json::json!(null), false);
-            input.finish(first, &result);
-            let (retry, joined) = input.begin_or_join(
-                Some("mic".into()),
-                serde_json::json!(null),
-                recording_starting,
-            );
-            assert!(!joined);
-            assert_ne!(retry, first);
-            assert!(input.pending);
-            assert!(input.error.is_none());
-        }
-    }
-
-    #[tokio::test]
-    async fn joined_input_requests_report_completion_failure_and_supersession() {
-        for result in [Ok(()), Err("device unavailable".to_string())] {
-            let input = std::sync::Mutex::new(RequestedInput::new(None::));
-            let revision = input.lock().unwrap().begin(Some("mic".into()));
-            let waiter =
-                wait_for_existing_input(revision, "Microphone", || input.lock().unwrap().clone());
-            let finish = async {
-                tokio::task::yield_now().await;
-                input.lock().unwrap().finish(revision, &result);
-            };
-            let (observed, ()) = tokio::join!(waiter, finish);
-            assert_eq!(observed, result);
-            input.lock().unwrap().begin(Some("different".into()));
-            assert!(
-                wait_for_existing_input(revision, "Microphone", || input.lock().unwrap().clone())
-                    .await
-                    .unwrap_err()
-                    .contains("superseded")
-            );
-        }
-    }
-
-    #[test]
-    fn persisted_intent_is_available_before_preview_setup() {
-        let state = RequestedInputsState::new(Some("Missing microphone".into()), None);
-        let snapshot = state.ready_snapshot().unwrap();
-        assert_eq!(
-            snapshot.microphone.value.as_deref(),
-            Some("Missing microphone")
-        );
-        assert!(snapshot.camera.value.is_none());
-    }
-
-    #[test]
-    fn failed_change_retains_requested_device_and_blocks_start() {
-        let mut input = RequestedInput::new(Some("A".to_string()));
-        let revision = input.begin(Some("B".to_string()));
-        input.finish(revision, &Err("B unavailable".into()));
-        assert_eq!(input.value.as_deref(), Some("B"));
-        assert!(
-            input
-                .validate("microphone")
-                .unwrap_err()
-                .contains("B unavailable")
-        );
-    }
-
-    #[test]
-    fn stale_completion_cannot_finish_newer_request() {
-        let mut input = RequestedInput::new(None);
-        let old = input.begin(Some("A".to_string()));
-        let current = input.begin(Some("B".to_string()));
-        input.finish(old, &Err("A failed".into()));
-        assert!(input.pending);
-        assert!(input.error.is_none());
-        assert_eq!(input.value.as_deref(), Some("B"));
-        input.finish(current, &Ok(()));
-        assert!(input.validate("microphone").is_ok());
-    }
-
-    #[test]
-    fn rapid_requests_preserve_explicit_none() {
-        let mut input = RequestedInput::new(None);
-        let first = input.begin(Some("A".to_string()));
-        let second = input.begin(Some("B".to_string()));
-        let none = input.begin(None);
-        input.finish(none, &Ok(()));
-        input.finish(first, &Ok(()));
-        input.finish(second, &Err("B unavailable".into()));
-        assert!(input.value.is_none());
-        assert!(input.validate("microphone").is_ok());
-    }
-
-    #[test]
-    fn restore_cannot_replace_newer_or_pending_request() {
-        let mut input = RequestedInput::new(Some("A".to_string()));
-        let old = input.revision;
-        let current = input.begin(None);
-        assert!(!input.prepare_restore(old));
-        assert!(!input.prepare_restore(current));
-        input.finish(current, &Ok(()));
-        assert!(input.prepare_restore(current));
-        assert!(input.value.is_none());
-    }
-
-    #[test]
-    fn start_is_blocked_while_setup_is_pending_or_failed() {
-        let state = RequestedInputsState::new(None, None);
-        let revision = state
-            .inner
-            .lock()
-            .unwrap()
-            .microphone
-            .begin(Some("A".into()));
-        assert!(state.ready_snapshot().is_err());
-        state
-            .inner
-            .lock()
-            .unwrap()
-            .microphone
-            .finish(revision, &Err("Unavailable".into()));
-        assert!(state.ready_snapshot().is_err());
-        let none = state.inner.lock().unwrap().microphone.begin(None);
-        state.inner.lock().unwrap().microphone.finish(none, &Ok(()));
-        assert!(state.ready_snapshot().is_ok());
-    }
-
-    #[test]
-    fn changed_request_prevents_recording_publication() {
-        let state = RequestedInputsState::new(Some("A".into()), None);
-        let snapshot = state.ready_snapshot().unwrap();
-        let _revision = state
-            .inner
-            .lock()
-            .unwrap()
-            .microphone
-            .begin(Some("B".into()));
-        let mut published = false;
-        assert!(!state.publish_if_current(&snapshot, || published = true));
-        assert!(!published);
-    }
-
-    #[test]
-    fn stale_camera_restore_cannot_publish_runtime_state() {
-        let state = RequestedInputsState::new(None, None);
-        let revision = state.snapshot().camera.revision;
-        let _new_revision = state.inner.lock().unwrap().camera.begin(None);
-        let mut published = false;
-        assert!(!state.publish_camera_if_current(revision, || published = true));
-        assert!(!published);
-    }
-
-    #[test]
-    fn stale_microphone_completion_cannot_publish_runtime_state() {
-        let state = RequestedInputsState::new(None, None);
-        let revision = state.snapshot().microphone.revision;
-        let _new_revision = state.inner.lock().unwrap().microphone.begin(None);
-        let mut published = false;
-        assert!(!state.publish_mic_if_current(revision, || published = true));
-        assert!(!published);
-    }
-
-    #[test]
-    fn unchanged_request_can_publish_recording() {
-        let state = RequestedInputsState::new(None, None);
-        let snapshot = state.ready_snapshot().unwrap();
-        let mut published = false;
-        assert!(state.publish_if_current(&snapshot, || published = true));
-        assert!(published);
-    }
-}
-
-#[cfg(test)]
-mod screenshot_share_cache_tests {
-    use super::*;
-
-    fn sharing(content_hash: Option<&str>) -> SharingMeta {
-        SharingMeta {
-            id: String::from("video-id"),
-            link: String::from("https://cap.so/s/video-id"),
-            content_hash: content_hash.map(str::to_string),
-        }
-    }
-
-    #[test]
-    fn reuses_link_when_content_hash_matches() {
-        let link =
-            screenshot_share_link_for_hash(Some(&sharing(Some("hash-a"))), "hash-a").unwrap();
-
-        assert_eq!(link, "https://cap.so/s/video-id");
-    }
-
-    #[test]
-    fn does_not_reuse_link_when_content_hash_changed() {
-        let link = screenshot_share_link_for_hash(Some(&sharing(Some("hash-a"))), "hash-b");
-
-        assert!(link.is_none());
-    }
-
-    #[test]
-    fn does_not_reuse_legacy_link_without_content_hash() {
-        let link = screenshot_share_link_for_hash(Some(&sharing(None)), "hash-a");
-
-        assert!(link.is_none());
-    }
-}
-
-#[cfg(test)]
-mod recording_delete_path_tests {
-    use super::recording_delete_target;
-
-    #[test]
-    fn delete_target_rejects_an_allowed_root_nested_in_another_allowed_root() {
-        let temp = tempfile::tempdir().unwrap();
-        let recordings = temp.path().join("recordings");
-        let nested = recordings.join("nested");
-        let bundle = nested.join("keep-me.cap");
-        std::fs::create_dir_all(&bundle).unwrap();
-        let dirs = [recordings, nested.clone()];
-
-        for path in [&nested, &nested.canonicalize().unwrap()] {
-            assert_eq!(
-                recording_delete_target(&dirs, path),
-                Err("Path is not inside a recordings directory".to_string())
-            );
-            assert!(bundle.is_dir());
-        }
-        assert_eq!(
-            recording_delete_target(&dirs, &bundle),
-            Ok(Some(bundle.canonicalize().unwrap()))
-        );
-    }
-
-    #[test]
-    fn delete_target_accepts_only_strict_children_of_a_recordings_root() {
-        let temp = tempfile::tempdir().unwrap();
-        let recordings = temp.path().join("recordings");
-        let bundle = recordings.join("delete-me.cap");
-        let outside = temp.path().join("outside.cap");
-        std::fs::create_dir_all(&bundle).unwrap();
-        std::fs::create_dir_all(&outside).unwrap();
-
-        assert_eq!(
-            recording_delete_target(std::slice::from_ref(&recordings), &bundle),
-            Ok(Some(bundle.canonicalize().unwrap()))
-        );
-        assert_eq!(
-            recording_delete_target(std::slice::from_ref(&recordings), &recordings),
-            Err("Path is not inside a recordings directory".to_string())
-        );
-        assert_eq!(
-            recording_delete_target(std::slice::from_ref(&recordings), &outside),
-            Err("Path is not inside a recordings directory".to_string())
-        );
-        assert_eq!(
-            recording_delete_target(
-                std::slice::from_ref(&recordings),
-                &recordings.join("..").join("outside.cap"),
-            ),
-            Err("Invalid path".to_string())
-        );
-        assert_eq!(
-            recording_delete_target(
-                std::slice::from_ref(&recordings),
-                &recordings.join("already-gone.cap"),
-            ),
-            Ok(None)
-        );
-    }
-
-    #[cfg(unix)]
-    #[test]
-    fn delete_target_rejects_a_symlink_escape() {
-        let temp = tempfile::tempdir().unwrap();
-        let recordings = temp.path().join("recordings");
-        let victim = temp.path().join("victim");
-        let escape = recordings.join("escape.cap");
-        std::fs::create_dir_all(&recordings).unwrap();
-        std::fs::create_dir_all(&victim).unwrap();
-        std::fs::write(victim.join("keep.txt"), b"keep").unwrap();
-        std::os::unix::fs::symlink(&victim, &escape).unwrap();
-
-        assert_eq!(
-            recording_delete_target(&[recordings], &escape),
-            Err("Path is not inside a recordings directory".to_string())
-        );
-        assert!(victim.join("keep.txt").is_file());
-    }
-
-    #[cfg(windows)]
-    #[test]
-    fn delete_target_accepts_a_canonical_windows_project_under_a_raw_root() {
-        let temp = tempfile::tempdir().unwrap();
-        let recordings = temp.path().join("recordings");
-        let bundle = recordings.join("delete-me.cap");
-        std::fs::create_dir_all(&bundle).unwrap();
-        let canonical_bundle = bundle.canonicalize().unwrap();
-
-        assert_eq!(
-            recording_delete_target(std::slice::from_ref(&recordings), &canonical_bundle),
-            Ok(Some(canonical_bundle.clone()))
-        );
-        std::fs::remove_dir_all(&canonical_bundle).unwrap();
-        assert_eq!(
-            recording_delete_target(&[recordings], &canonical_bundle),
-            Ok(None)
-        );
-    }
-}
-
-#[cfg(test)]
-mod typescript_bindings_tests {
-    #[test]
-    fn export_typescript_bindings() {
-        let bindings_path = std::path::Path::new("../src/utils/tauri.ts");
-        if bindings_path.parent().is_some_and(|parent| parent.exists()) {
-            super::specta_builder()
-                .export(super::typescript_exporter(), bindings_path)
-                .expect("failed to export TypeScript bindings");
-        }
-    }
-}
-
-#[cfg(test)]
-mod instant_resume_safety_tests {
-    use super::*;
-
-    #[test]
-    fn old_recordings_are_reconciled_once_but_skipped_before_periodic_metadata_reads() {
-        let path = project("old", InstantRecordingMeta::InProgress { recording: true });
-        let later = path.metadata().unwrap().created().unwrap() + Duration::from_secs(25 * 60 * 60);
-        assert!(
-            load_upload_resume_candidate_at(&path, true, later)
-                .unwrap()
-                .is_none()
-        );
-        assert!(matches!(
-            RecordingMeta::load_for_project(&path).unwrap().inner,
-            RecordingMetaInner::Instant(InstantRecordingMeta::Failed { .. })
-        ));
-        std::fs::write(path.join("recording-meta.json"), b"invalid").unwrap();
-        assert!(
-            load_upload_resume_candidate_at(&path, false, later)
-                .unwrap()
-                .is_none()
-        );
-        assert_eq!(
-            std::fs::read(path.join("recording-meta.json")).unwrap(),
-            b"invalid"
-        );
-        std::fs::remove_dir_all(path).unwrap();
-    }
-    fn project(tag: &str, inner: InstantRecordingMeta) -> PathBuf {
-        static NEXT: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
-        let path = std::env::temp_dir().join(format!(
-            "cap-instant-recovery-{tag}-{}-{}",
-            std::process::id(),
-            NEXT.fetch_add(1, std::sync::atomic::Ordering::AcqRel)
-        ));
-        std::fs::create_dir_all(&path).unwrap();
-        let meta = RecordingMeta {
-            platform: None,
-            project_path: path.clone(),
-            pretty_name: "Synthetic recovery".into(),
-            sharing: None,
-            inner: RecordingMetaInner::Instant(inner),
-            upload: Some(UploadMeta::SegmentUpload {
-                video_id: "synthetic".into(),
-                recording_dir: path.clone(),
-                pre_created_video: VideoUploadInfo {
-                    id: "synthetic".into(),
-                    link: "https://example.invalid/s/synthetic".into(),
-                    config: cap_project::S3UploadMeta {
-                        id: "synthetic".into(),
-                    },
-                },
-            }),
-        };
-        meta.save_for_project().unwrap();
-        path
-    }
-    #[test]
-    fn crashed_and_failed_projects_never_become_automatic_upload_candidates() {
-        for inner in [
-            InstantRecordingMeta::InProgress { recording: true },
-            InstantRecordingMeta::Failed {
-                error: "required audio failed".into(),
-            },
-        ] {
-            let path = project("failed", inner);
-            assert!(load_instant_resume_candidate(&path).unwrap().is_none());
-            let meta = RecordingMeta::load_for_project(&path).unwrap();
-            assert!(matches!(
-                meta.inner,
-                RecordingMetaInner::Instant(InstantRecordingMeta::Failed { .. })
-            ));
-            assert!(matches!(
-                meta.upload,
-                Some(UploadMeta::SegmentUpload { .. })
-            ));
-            assert!(path.is_dir());
-            std::fs::remove_dir_all(path).unwrap();
-        }
-    }
-    #[test]
-    fn positively_complete_project_remains_resumable_without_media_deletion() {
-        let path = project(
-            "complete",
-            InstantRecordingMeta::Complete {
-                fps: 30,
-                sample_rate: Some(48000),
-            },
-        );
-        assert!(load_instant_resume_candidate(&path).unwrap().is_some());
-        assert!(path.is_dir());
-        std::fs::remove_dir_all(path).unwrap();
-    }
-    #[test]
-    fn invalid_recovery_metadata_cannot_authorize_upload() {
-        let path = project(
-            "invalid",
-            InstantRecordingMeta::Complete {
-                fps: 30,
-                sample_rate: None,
-            },
-        );
-        std::fs::write(path.join("recording-meta.json"), b"invalid").unwrap();
-        assert!(load_instant_resume_candidate(&path).is_err());
-        assert!(path.is_dir());
-        std::fs::remove_dir_all(path).unwrap();
-    }
-    #[test]
-    fn periodic_reconciliation_does_not_mark_an_active_recording_failed() {
-        let path = project(
-            "periodic",
-            InstantRecordingMeta::InProgress { recording: true },
-        );
-        assert!(
-            load_upload_resume_candidate(&path, false)
-                .unwrap()
-                .is_none()
-        );
-        assert!(matches!(
-            RecordingMeta::load_for_project(&path).unwrap().inner,
-            RecordingMetaInner::Instant(InstantRecordingMeta::InProgress { recording: true })
-        ));
-        std::fs::remove_dir_all(path).unwrap();
-    }
-
-    #[test]
-    fn another_upload_owner_prevents_startup_metadata_mutation() {
-        let path = project(
-            "owned",
-            InstantRecordingMeta::InProgress { recording: true },
-        );
-        let lock = cap_recording::upload_resume::UploadLock::acquire(&path).unwrap();
-        let before = std::fs::read(path.join("recording-meta.json")).unwrap();
-        assert!(load_upload_resume_candidate(&path, true).unwrap().is_none());
-        assert_eq!(
-            std::fs::read(path.join("recording-meta.json")).unwrap(),
-            before
-        );
-        drop(lock);
-        std::fs::remove_dir_all(path).unwrap();
-    }
-    #[test]
-    fn explicit_delete_accepts_idle_gpui_recordings_while_resume_defers_them() {
-        let path = project(
-            "gpui-delete",
-            InstantRecordingMeta::Complete {
-                fps: 30,
-                sample_rate: None,
-            },
-        );
-        std::fs::write(path.join("instant-upload.json"), b"{}").unwrap();
-        assert!(upload::acquire_upload_lock(&path).is_err());
-        let ownership = acquire_recording_delete_lock(&path).unwrap();
-        assert!(acquire_recording_delete_lock(&path).is_err());
-        std::fs::remove_dir_all(&path).unwrap();
-        drop(ownership);
-        assert!(!path.exists());
-    }
-
-    #[test]
-    fn explicit_delete_cannot_bypass_another_clients_active_upload_lock() {
-        let path = project(
-            "active-delete",
-            InstantRecordingMeta::Complete {
-                fps: 30,
-                sample_rate: None,
-            },
-        );
-        let ownership = cap_recording::upload_resume::UploadLock::acquire(&path).unwrap();
-        let original = std::fs::read(path.join("recording-meta.json")).unwrap();
-        assert!(acquire_recording_delete_lock(&path).is_err());
-        assert_eq!(
-            std::fs::read(path.join("recording-meta.json")).unwrap(),
-            original
-        );
-        drop(ownership);
-        std::fs::remove_dir_all(path).unwrap();
-    }
-}
-
-#[cfg(test)]
-mod recent_media_tests {
-    use super::*;
-
-    #[test]
-    fn limited_history_matches_the_full_list_with_invalid_metadata_and_timestamp_ties() {
-        let candidates = vec![
-            ("old", 1.0),
-            ("first tie", 4.0),
-            ("broken", 5.0),
-            ("second tie", 4.0),
-            ("middle", 2.0),
-        ];
-        let load = |path, timestamp| (path != "broken").then_some((path, timestamp));
-        let full = newest_valid_media(candidates.clone(), usize::MAX, load);
-        let recent = newest_valid_media(candidates, 2, load);
-        assert_eq!(recent, full[..2]);
-        assert_eq!(recent, vec![("first tie", 4.0), ("second tie", 4.0)]);
-    }
-
-    #[test]
-    fn a_large_library_only_loads_metadata_for_the_requested_recent_items() {
-        let mut loads = 0;
-        let recent = newest_valid_media(
-            (0..10_000).map(|id| (id, f64::from(id))).collect(),
-            9,
-            |id, _| {
-                loads += 1;
-                Some(id)
-            },
-        );
-        assert_eq!(loads, 9);
-        assert_eq!(recent, (9991..10_000).rev().collect::>());
-    }
-}
-
-#[cfg(test)]
-mod camera_permission_tests {
-    use super::{
-        DeviceOrModelID, RequestedInput, RequestedInputsState, await_current_camera_request,
-        check_requested_camera_permission,
-    };
-
-    fn camera(name: &str) -> DeviceOrModelID {
-        DeviceOrModelID::DeviceID(name.into())
-    }
-
-    #[test]
-    fn disabled_camera_bypasses_permission() {
-        check_requested_camera_permission(None, || {
-            panic!("turning the camera off must not require permission")
-        })
-        .unwrap();
-    }
-
-    #[test]
-    fn saved_camera_permission_failure_preserves_intent_and_retry() {
-        let mut input = RequestedInput::new(Some(camera("Saved camera")));
-        let revision = input.revision;
-        assert!(input.prepare_restore(revision));
-        let result = check_requested_camera_permission(input.value.as_ref(), || {
-            Err("Allow camera access in System Settings".into())
-        });
-        input.finish(revision, &result);
-        assert_eq!(input.value, Some(camera("Saved camera")));
-        assert!(!input.pending);
-        assert!(
-            input
-                .validate("camera")
-                .unwrap_err()
-                .contains("System Settings")
-        );
-        assert!(input.prepare_restore(revision));
-        let result = check_requested_camera_permission(input.value.as_ref(), || Ok(()));
-        input.finish(revision, &result);
-        assert!(input.validate("camera").is_ok());
-    }
-
-    #[test]
-    fn revoked_camera_access_requires_successful_reselection() {
-        let mut input = RequestedInput::new(Some(camera("Saved camera")));
-        let denied = input.begin(Some(camera("Saved camera")));
-        let result = check_requested_camera_permission(input.value.as_ref(), || {
-            Err("Camera access is blocked".into())
-        });
-        input.finish(denied, &result);
-        assert!(input.validate("camera").is_err());
-        let granted = input.begin(Some(camera("Saved camera")));
-        let result = check_requested_camera_permission(input.value.as_ref(), || Ok(()));
-        input.finish(granted, &result);
-        input.finish(denied, &Err("Stale denial".into()));
-        assert!(input.validate("camera").is_ok());
-        assert_eq!(input.value, Some(camera("Saved camera")));
-    }
-
-    #[test]
-    fn camera_off_clears_permission_failure_without_requesting_access() {
-        let mut input = RequestedInput::new(Some(camera("Saved camera")));
-        let old = input.begin(Some(camera("Saved camera")));
-        input.finish(old, &Err("Camera access is blocked".into()));
-        let off = input.begin(None);
-        let result = check_requested_camera_permission(input.value.as_ref(), || {
-            panic!("camera off must not request permission")
-        });
-        input.finish(off, &result);
-        input.finish(old, &Err("Old failure".into()));
-        assert!(input.value.is_none());
-        assert!(input.validate("camera").is_ok());
-    }
-
-    #[tokio::test]
-    async fn current_camera_setup_keeps_success_and_device_failure() {
-        assert_eq!(
-            await_current_camera_request(async { Ok::<_, String>(()) }, || true).await,
-            Ok(Ok(()))
-        );
-        assert_eq!(
-            await_current_camera_request(
-                async { Err::<(), _>("CameraTimeout".to_string()) },
-                || true
-            )
-            .await,
-            Ok(Err("CameraTimeout".into()))
-        );
-    }
-
-    #[tokio::test]
-    async fn stale_camera_ready_failure_does_not_publish_or_retry() {
-        let requested = RequestedInputsState::new(None, Some(camera("Saved camera")));
-        let revision = requested
-            .inner
-            .lock()
-            .unwrap()
-            .camera
-            .begin(Some(camera("Saved camera")));
-        let result = await_current_camera_request(
-            async {
-                let mut current = requested.inner.lock().unwrap();
-                let latest = current.camera.begin(Some(camera("New camera")));
-                current.camera.finish(latest, &Ok(()));
-                Err::<(), _>("CameraTimeout".to_string())
-            },
-            || requested.camera_is_current(revision),
-        )
-        .await;
-        assert!(result.unwrap_err().contains("superseded"));
-        let mut published = false;
-        assert!(!requested.publish_camera_if_current(revision, || published = true));
-        assert!(!published);
-        assert!(requested.snapshot().camera.validate("camera").is_ok());
-        assert_eq!(
-            requested.snapshot().camera.value,
-            Some(camera("New camera"))
-        );
-    }
-
-    #[tokio::test]
-    async fn stale_camera_ready_success_cannot_clear_newer_failure() {
-        let requested = RequestedInputsState::new(None, Some(camera("Saved camera")));
-        let revision = requested
-            .inner
-            .lock()
-            .unwrap()
-            .camera
-            .begin(Some(camera("Saved camera")));
-        let result = await_current_camera_request(
-            async {
-                let mut current = requested.inner.lock().unwrap();
-                let latest = current.camera.begin(Some(camera("Saved camera")));
-                current
-                    .camera
-                    .finish(latest, &Err("New selection failed".into()));
-                Ok::<(), String>(())
-            },
-            || requested.camera_is_current(revision),
-        )
-        .await;
-        assert!(result.unwrap_err().contains("superseded"));
-        assert_eq!(
-            requested.snapshot().camera.error.as_deref(),
-            Some("New selection failed")
-        );
-    }
-
-    #[tokio::test]
-    async fn superseded_camera_retry_wait_cannot_start_another_attempt() {
-        let requested = RequestedInputsState::new(None, Some(camera("Saved camera")));
-        let revision = requested
-            .inner
-            .lock()
-            .unwrap()
-            .camera
-            .begin(Some(camera("Saved camera")));
-        let mut attempts = 1;
-        let retry = await_current_camera_request(
-            async {
-                requested.inner.lock().unwrap().camera.begin(None);
-            },
-            || requested.camera_is_current(revision),
-        )
-        .await;
-        if retry.is_ok() {
-            attempts += 1;
-        }
-        assert!(retry.unwrap_err().contains("superseded"));
-        assert_eq!(attempts, 1);
-        assert!(requested.snapshot().camera.value.is_none());
-    }
-
-    #[test]
-    fn superseded_camera_cleanup_cannot_mark_a_newer_camera_disconnected() {
-        let requested = RequestedInputsState::new(None, Some(camera("Old camera")));
-        let old = requested
-            .inner
-            .lock()
-            .unwrap()
-            .camera
-            .begin(Some(camera("Old camera")));
-        let latest = requested
-            .inner
-            .lock()
-            .unwrap()
-            .camera
-            .begin(Some(camera("New camera")));
-        requested
-            .inner
-            .lock()
-            .unwrap()
-            .camera
-            .finish(latest, &Ok(()));
-        let mut connected = true;
-        let mut notification = None;
-        assert!(!requested.publish_camera_if_current(old, || {
-            connected = false;
-            notification = Some("Camera unavailable");
-        }));
-        assert!(connected);
-        assert!(notification.is_none());
-    }
-}
diff --git a/apps/desktop/src-tauri/src/linux_instant_camera.rs b/apps/desktop/src-tauri/src/linux_instant_camera.rs
deleted file mode 100644
index ff9fa79d111..00000000000
--- a/apps/desktop/src-tauri/src/linux_instant_camera.rs
+++ /dev/null
@@ -1,1144 +0,0 @@
-use std::{
-    sync::{Arc, Mutex},
-    time::Duration,
-};
-
-use serde::{Deserialize, Serialize};
-use specta::Type;
-#[cfg(target_os = "linux")]
-use std::time::Instant;
-use tauri::{AppHandle, Manager, WebviewWindow};
-use tauri_specta::Event;
-
-use crate::{camera::CameraPreviewState, windows::CapWindowId};
-
-#[cfg(target_os = "linux")]
-use crate::camera::CameraPreviewShape;
-
-#[derive(Clone)]
-struct SelectionGuard {
-    inputs: Arc>,
-    revision: u64,
-    selected: cap_recording::feeds::camera::DeviceOrModelID,
-}
-
-impl SelectionGuard {
-    fn current(&self) -> bool {
-        let inputs = self.inputs.lock().unwrap();
-        inputs.camera.revision == self.revision
-            && inputs.camera.value.as_ref() == Some(&self.selected)
-            && !inputs.camera.pending
-            && inputs.camera.error.is_none()
-    }
-}
-
-#[derive(Clone, Debug, Deserialize, Serialize, Type)]
-#[serde(rename_all = "camelCase")]
-pub struct CameraPresentationInput {
-    pub viewport_width: f64,
-    pub viewport_height: f64,
-    pub left: f64,
-    pub top: f64,
-    pub width: f64,
-    pub height: f64,
-    pub radius: f64,
-    pub layout_revision: u32,
-    pub state: CameraPreviewState,
-}
-
-#[derive(Clone, Serialize, Type, Event)]
-#[serde(rename_all = "camelCase")]
-pub struct CameraPresentationRequested {
-    pub nonce: String,
-    pub generation: u32,
-    pub camera_revision: String,
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub struct PhysicalRect {
-    pub x: i32,
-    pub y: i32,
-    pub width: u32,
-    pub height: u32,
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-struct NativeSnapshot {
-    id: u64,
-    rect: PhysicalRect,
-}
-
-impl NativeSnapshot {
-    #[cfg(target_os = "linux")]
-    fn read(window: &WebviewWindow) -> Result {
-        use wgpu::rwh::{HasWindowHandle, RawWindowHandle};
-        let id = match window
-            .window_handle()
-            .map_err(|error| error.to_string())?
-            .as_raw()
-        {
-            RawWindowHandle::Xlib(handle) => handle.window,
-            RawWindowHandle::Xcb(handle) => u64::from(handle.window.get()),
-            _ => return Err("Camera presentation requires a native X11 window".into()),
-        };
-        let position = window.inner_position().map_err(|error| error.to_string())?;
-        let size = window.inner_size().map_err(|error| error.to_string())?;
-        Ok(Self {
-            id,
-            rect: PhysicalRect {
-                x: position.x,
-                y: position.y,
-                width: size.width,
-                height: size.height,
-            },
-        })
-    }
-
-    #[cfg(not(target_os = "linux"))]
-    fn read(_window: &WebviewWindow) -> Result {
-        Err("Processed camera presentation is only available on Linux X11".into())
-    }
-}
-
-async fn native_snapshot(window: WebviewWindow) -> Result {
-    let (tx, rx) = tokio::sync::oneshot::channel();
-    let handle = window.clone();
-    window
-        .run_on_main_thread(move || {
-            let _ = tx.send(NativeSnapshot::read(&handle));
-        })
-        .map_err(|error| error.to_string())?;
-    tokio::time::timeout(Duration::from_secs(2), rx)
-        .await
-        .map_err(|_| "Camera window geometry timed out".to_string())?
-        .map_err(|_| "Camera window geometry was cancelled".to_string())?
-}
-
-#[derive(Clone)]
-struct PresentationOwner {
-    nonce: String,
-    generation: u32,
-    native: NativeSnapshot,
-    selection: SelectionGuard,
-    state: tokio::sync::watch::Receiver,
-}
-
-impl PresentationOwner {
-    fn validate(
-        &self,
-        app: &AppHandle,
-        native: NativeSnapshot,
-        input: &CameraPresentationInput,
-    ) -> Result<(), String> {
-        if !crate::clean_capture::is_current(app, self.generation)
-            || !self.selection.current()
-            || self.native != native
-            || *self.state.borrow() != input.state
-        {
-            return Err(
-                "Camera selection, appearance, or window changed. Start again to confirm it."
-                    .into(),
-            );
-        }
-        Ok(())
-    }
-}
-
-struct PendingPresentation {
-    owner: PresentationOwner,
-    reply: tokio::sync::oneshot::Sender>,
-}
-
-#[derive(Default)]
-pub struct PresentationBroker {
-    pending: Arc>>,
-}
-
-#[cfg(target_os = "linux")]
-struct PendingGuard {
-    pending: Arc>>,
-    nonce: String,
-}
-
-#[cfg(target_os = "linux")]
-impl Drop for PendingGuard {
-    fn drop(&mut self) {
-        let mut pending = self.pending.lock().unwrap();
-        if pending
-            .as_ref()
-            .is_some_and(|pending| pending.owner.nonce == self.nonce)
-        {
-            *pending = None;
-        }
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn submit_camera_presentation(
-    window: WebviewWindow,
-    nonce: String,
-    input: Option,
-    error: Option,
-) -> Result<(), String> {
-    if !cfg!(target_os = "linux")
-        || !matches!(
-            window.label().parse::(),
-            Ok(CapWindowId::Camera)
-        )
-    {
-        return Err(
-            "Only the current Linux camera window may answer a presentation request".into(),
-        );
-    }
-    let app = window.app_handle();
-    let broker = app.state::();
-    let owner = broker
-        .pending
-        .lock()
-        .unwrap()
-        .as_ref()
-        .filter(|pending| pending.owner.nonce == nonce)
-        .map(|pending| pending.owner.clone())
-        .ok_or("Camera presentation request expired")?;
-    let native = native_snapshot(window.clone()).await?;
-    if native.id != owner.native.id
-        || !crate::clean_capture::is_current(app, owner.generation)
-        || !owner.selection.current()
-    {
-        return Err("Camera presentation owner changed".into());
-    }
-    let result = match (input, error) {
-        (Some(input), None) => owner.validate(app, native, &input).map(|()| input),
-        (None, Some(error)) => Err(error),
-        _ => return Err("Camera presentation requires either pixels geometry or an error".into()),
-    };
-    let mut pending = broker.pending.lock().unwrap();
-    if pending
-        .as_ref()
-        .is_none_or(|pending| pending.owner.nonce != nonce)
-    {
-        return Err("Camera presentation request was superseded".into());
-    }
-    let _ = pending.take().unwrap().reply.send(result);
-    Ok(())
-}
-
-#[cfg(target_os = "linux")]
-pub struct PreparedPresentation {
-    owner: PresentationOwner,
-    actor: kameo::actor::ActorRef,
-    input: CameraPresentationInput,
-    pub presentation: cap_recording::instant_recording::LinuxCameraPresentation,
-    pub reference_size: (u32, u32),
-    pub processing: cap_recording::instant_recording::LinuxCameraProcessing,
-}
-
-#[cfg(target_os = "linux")]
-impl PreparedPresentation {
-    pub fn validate_before_hide(&self, window: &WebviewWindow) -> Result<(), String> {
-        if !matches!(
-            window.label().parse::(),
-            Ok(CapWindowId::Camera)
-        ) {
-            return Err("Camera presentation window changed".into());
-        }
-        self.owner.validate(
-            window.app_handle(),
-            NativeSnapshot::read(window)?,
-            &self.input,
-        )
-    }
-}
-
-#[cfg(target_os = "linux")]
-pub async fn request_presentation(
-    app: &AppHandle,
-    generation: u32,
-    capture: PhysicalRect,
-) -> Result {
-    let requested = app.state::();
-    let snapshot = requested.ready_snapshot()?;
-    let selected = snapshot
-        .camera
-        .value
-        .clone()
-        .ok_or("Select a camera before requesting its presentation")?;
-    let selection = SelectionGuard {
-        inputs: requested.inner.clone(),
-        revision: snapshot.camera.revision,
-        selected,
-    };
-    let window = CapWindowId::Camera
-        .get(app)
-        .ok_or("Open the selected camera preview before recording")?;
-    if !window.is_visible().map_err(|error| error.to_string())? {
-        return Err("Open the selected camera preview before recording".into());
-    }
-    let native = native_snapshot(window.clone()).await?;
-    let (actor, state) = {
-        let state = app.state::>();
-        let state = state.read().await;
-        (
-            state.camera_feed.clone(),
-            state.camera_preview_state_tx.subscribe(),
-        )
-    };
-    if !selection.current() || !crate::clean_capture::is_current(app, generation) {
-        return Err("Recording or camera selection changed".into());
-    }
-    let nonce = uuid::Uuid::new_v4().to_string();
-    let owner = PresentationOwner {
-        nonce: nonce.clone(),
-        generation,
-        native,
-        selection,
-        state,
-    };
-    let broker = app.state::();
-    let (reply, rx) = tokio::sync::oneshot::channel();
-    {
-        let mut pending = broker.pending.lock().unwrap();
-        if pending.is_some() {
-            return Err("Camera presentation is already being measured".into());
-        }
-        *pending = Some(PendingPresentation {
-            owner: owner.clone(),
-            reply,
-        });
-    }
-    let _guard = PendingGuard {
-        pending: broker.pending.clone(),
-        nonce: nonce.clone(),
-    };
-    CameraPresentationRequested {
-        nonce,
-        generation,
-        camera_revision: snapshot.camera.revision.to_string(),
-    }
-    .emit_to(app, window.label())
-    .map_err(|error| error.to_string())?;
-    let input = tokio::time::timeout(Duration::from_secs(2), rx)
-        .await
-        .map_err(|_| "Camera preview did not answer before the presentation deadline".to_string())?
-        .map_err(|_| "Camera presentation was cancelled".to_string())??;
-    owner.validate(app, native_snapshot(window).await?, &input)?;
-    let (presentation, processing) = presentation_from_input(&input, native.rect, capture)?;
-    Ok(PreparedPresentation {
-        owner,
-        actor,
-        input,
-        presentation,
-        reference_size: (capture.width, capture.height),
-        processing,
-    })
-}
-
-#[cfg(target_os = "linux")]
-fn processing(
-    state: &CameraPreviewState,
-) -> cap_recording::instant_recording::LinuxCameraProcessing {
-    use cap_recording::instant_recording::{LinuxCameraBlur, LinuxCameraProcessing};
-    LinuxCameraProcessing {
-        mirrored: state.mirrored,
-        blur: match state.background_blur {
-            cap_project::BackgroundBlurMode::Off | cap_project::BackgroundBlurMode::Remove => {
-                LinuxCameraBlur::Off
-            }
-            cap_project::BackgroundBlurMode::Light => LinuxCameraBlur::Light,
-            cap_project::BackgroundBlurMode::Heavy => LinuxCameraBlur::Heavy,
-        },
-    }
-}
-
-#[cfg(target_os = "linux")]
-fn presentation_from_input(
-    input: &CameraPresentationInput,
-    window: PhysicalRect,
-    capture: PhysicalRect,
-) -> Result<
-    (
-        cap_recording::instant_recording::LinuxCameraPresentation,
-        cap_recording::instant_recording::LinuxCameraProcessing,
-    ),
-    String,
-> {
-    use cap_recording::instant_recording::{
-        LinuxCameraEffect, LinuxCameraPresentation, LinuxCameraRect, LinuxCameraShape,
-    };
-    if ![
-        input.viewport_width,
-        input.viewport_height,
-        input.left,
-        input.top,
-        input.width,
-        input.height,
-        input.radius,
-    ]
-    .iter()
-    .all(|value| value.is_finite())
-        || input.viewport_width <= 0.0
-        || input.viewport_height <= 0.0
-        || input.width <= 0.0
-        || input.height <= 0.0
-        || input.left < 0.0
-        || input.top < 0.0
-        || input.radius < 0.0
-        || input.left + input.width > input.viewport_width + 1.0
-        || input.top + input.height > input.viewport_height + 1.0
-        || window.width == 0
-        || window.height == 0
-        || !input.state.size.is_finite()
-        || !(crate::camera::MIN_CAMERA_SIZE..=crate::camera::MAX_CAMERA_SIZE)
-            .contains(&input.state.size)
-    {
-        return Err("Camera preview has invalid content bounds".into());
-    }
-    let sx = f64::from(window.width) / input.viewport_width;
-    let sy = f64::from(window.height) / input.viewport_height;
-    if (sx - sy).abs() > sx.min(sy) * 0.01 {
-        return Err("Camera preview has an unsupported physical scale".into());
-    }
-    let left = f64::from(window.x) + (input.left * sx).round();
-    let top = f64::from(window.y) + (input.top * sy).round();
-    let right = f64::from(window.x) + ((input.left + input.width) * sx).round();
-    let bottom = f64::from(window.y) + ((input.top + input.height) * sy).round();
-    let x = left - f64::from(capture.x);
-    let y = top - f64::from(capture.y);
-    let width = right - left;
-    let height = bottom - top;
-    if x < 0.0
-        || y < 0.0
-        || width < 1.0
-        || height < 1.0
-        || x + width > f64::from(capture.width)
-        || y + height > f64::from(capture.height)
-    {
-        return Err(
-            "Move the whole camera preview inside the capture area before recording".into(),
-        );
-    }
-    let width = width as u32;
-    let height = height as u32;
-    let shape = match input.state.shape {
-        CameraPreviewShape::Round if width == height => LinuxCameraShape::Round,
-        CameraPreviewShape::Round if width.abs_diff(height) <= 1 => {
-            LinuxCameraShape::RoundedRectangle {
-                radius_pixels: width.min(height) / 2,
-            }
-        }
-        CameraPreviewShape::Round => return Err("Round camera preview is not square".into()),
-        CameraPreviewShape::Square | CameraPreviewShape::Full => {
-            LinuxCameraShape::RoundedRectangle {
-                radius_pixels: ((input.radius * sx.min(sy)).round() as u32)
-                    .min(width.min(height) / 2),
-            }
-        }
-    };
-    let mut presentation = LinuxCameraPresentation {
-        rect: LinuxCameraRect {
-            x: x as u32,
-            y: y as u32,
-            width,
-            height,
-        },
-        shape,
-        mirrored: input.state.mirrored,
-        effect: LinuxCameraEffect::None,
-    };
-    presentation
-        .validate(capture.width, capture.height)
-        .map_err(|error| error.to_string())?;
-    if input.state.background_blur != cap_project::BackgroundBlurMode::Off {
-        presentation.effect = LinuxCameraEffect::BackgroundBlur;
-    }
-    Ok((presentation, processing(&input.state)))
-}
-
-#[cfg(target_os = "linux")]
-mod producer {
-    use super::*;
-    use cap_recording::{
-        FFmpegVideoFrame,
-        feeds::camera::{self, CameraFeed, CameraFeedLock},
-        instant_recording::{
-            LINUX_CAMERA_MAX_MASK_AGE, LinuxCameraBlur, LinuxCameraMaskReceipt, LinuxCameraPixels,
-            LinuxCameraProcessing, LinuxCameraPublisher, LinuxProcessedCameraFrame,
-            LinuxProcessedCameraSource,
-        },
-    };
-    use cap_timestamp::Timestamp;
-    use kameo::actor::ActorRef;
-    use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
-
-    pub struct Reservation(Arc);
-
-    impl Reservation {
-        pub(super) fn acquire(active: &Arc) -> Option {
-            active
-                .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
-                .ok()
-                .map(|_| Self(active.clone()))
-        }
-    }
-
-    impl Drop for Reservation {
-        fn drop(&mut self) {
-            self.0.store(false, Ordering::Release);
-        }
-    }
-
-    struct Attachment {
-        actor: ActorRef,
-        sender: flume::Sender,
-        runtime: tokio::runtime::Handle,
-        _reservation: Reservation,
-    }
-
-    impl Drop for Attachment {
-        fn drop(&mut self) {
-            let actor = self.actor.clone();
-            let sender = self.sender.clone();
-            drop(self.runtime.spawn(async move {
-                let _ = actor.ask(camera::RemoveSender(sender)).await;
-            }));
-        }
-    }
-
-    #[derive(Clone)]
-    pub struct ProcessingFactory {
-        commands: flume::Sender>,
-        reserved: Arc,
-        generation: Arc,
-    }
-
-    pub(crate) fn channel() -> (ProcessingFactory, flume::Receiver>) {
-        let (commands, receiver) = flume::bounded(1);
-        (
-            ProcessingFactory {
-                commands,
-                reserved: Arc::new(AtomicBool::new(false)),
-                generation: Arc::new(AtomicU64::new(0)),
-            },
-            receiver,
-        )
-    }
-
-    impl ProcessingFactory {
-        pub async fn subscribe(
-            &self,
-            feed: Arc,
-            prepared: &PreparedPresentation,
-        ) -> anyhow::Result {
-            let info = feed.camera_info();
-            let matches = match &prepared.owner.selection.selected {
-                camera::DeviceOrModelID::DeviceID(id) => info.device_id() == id,
-                camera::DeviceOrModelID::ModelID(id) => info.model_id() == Some(id),
-            };
-            anyhow::ensure!(
-                matches && feed.id() == prepared.actor.id(),
-                "Processed camera does not match the requested camera lock"
-            );
-            anyhow::ensure!(
-                prepared.owner.selection.current()
-                    && *prepared.owner.state.borrow() == prepared.input.state,
-                "Camera request or appearance changed before recording"
-            );
-            let reservation = tokio::time::timeout(Duration::from_millis(1500), async {
-                loop {
-                    if let Some(reservation) = Reservation::acquire(&self.reserved) {
-                        break reservation;
-                    }
-                    tokio::time::sleep(Duration::from_millis(10)).await;
-                }
-            })
-            .await
-            .map_err(|_| {
-                anyhow::anyhow!("Previous camera processing has not released its lease")
-            })?;
-            let (sender, frames) = flume::bounded(2);
-            let attachment = Attachment {
-                actor: prepared.actor.clone(),
-                sender: sender.clone(),
-                runtime: tokio::runtime::Handle::current(),
-                _reservation: reservation,
-            };
-            anyhow::ensure!(
-                prepared.owner.selection.current(),
-                "Camera selection changed while waiting for processing"
-            );
-            let generation = self.generation.fetch_add(1, Ordering::AcqRel) + 1;
-            let not_before = Instant::now();
-            let (publisher, mut source) = LinuxProcessedCameraSource::channel(
-                feed.clone(),
-                prepared.processing,
-                generation,
-                not_before,
-            );
-            tokio::time::timeout(
-                Duration::from_millis(1500),
-                feed.ask(camera::AddSender(sender)),
-            )
-            .await
-            .map_err(|_| anyhow::anyhow!("Camera processing attachment timed out"))?
-            .map_err(|error| anyhow::anyhow!("Camera processing attachment failed: {error}"))?;
-            let work = RecordingWork {
-                frames,
-                publisher,
-                state: prepared.input.state.clone(),
-                selection: prepared.owner.selection.clone(),
-                current_state: prepared.owner.state.clone(),
-                generation,
-                not_before,
-                published: AtomicBool::new(false),
-                _attachment: attachment,
-            };
-            tokio::time::timeout(
-                Duration::from_millis(1500),
-                self.commands.send_async(Box::new(work)),
-            )
-            .await
-            .map_err(|_| anyhow::anyhow!("Camera processing command timed out"))?
-            .map_err(|_| anyhow::anyhow!("Camera processing worker disconnected"))?;
-            source.wait_ready(Duration::from_secs(10)).await?;
-            anyhow::ensure!(
-                prepared.owner.selection.current()
-                    && *prepared.owner.state.borrow() == prepared.input.state,
-                "Camera request or appearance changed while processing warmed up"
-            );
-            Ok(source)
-        }
-    }
-
-    #[derive(Clone, Debug)]
-    pub(crate) struct FrameReceipt {
-        pub timestamp: Timestamp,
-        pub generation: u64,
-        pub processing: LinuxCameraProcessing,
-        pub dimensions: (u32, u32),
-        pub blur: Option,
-    }
-
-    pub(crate) struct RecordingWork {
-        pub frames: flume::Receiver,
-        publisher: LinuxCameraPublisher,
-        pub state: CameraPreviewState,
-        selection: SelectionGuard,
-        current_state: tokio::sync::watch::Receiver,
-        generation: u64,
-        not_before: Instant,
-        published: AtomicBool,
-        _attachment: Attachment,
-    }
-
-    impl RecordingWork {
-        pub fn cancelled(&self) -> bool {
-            self.publisher.is_cancelled()
-        }
-        pub fn fail(&self, error: impl Into) {
-            self.publisher.fail(error.into());
-        }
-        pub fn accepts(&self, timestamp: Timestamp) -> Result {
-            if !self.selection.current() || *self.current_state.borrow() != self.state {
-                return Err("Requested camera or appearance changed during recording".into());
-            }
-            let Timestamp::Instant(captured) = timestamp else {
-                return Err("Camera requires an original monotonic timestamp".into());
-            };
-            Ok(captured >= self.not_before)
-        }
-        pub fn receipt(&self, timestamp: Timestamp, dimensions: (u32, u32)) -> FrameReceipt {
-            FrameReceipt {
-                timestamp,
-                generation: self.generation,
-                processing: processing(&self.state),
-                dimensions,
-                blur: None,
-            }
-        }
-        pub fn publish(&self, rgba: &[u8], receipt: FrameReceipt) {
-            if self.cancelled() {
-                return;
-            }
-            match self.accepts(receipt.timestamp) {
-                Ok(true) => {}
-                Ok(false) => return,
-                Err(error) => {
-                    self.fail(error);
-                    return;
-                }
-            }
-            let now = Instant::now();
-            if !self.published.load(Ordering::Acquire)
-                && matches!(receipt.timestamp, Timestamp::Instant(captured) if now.saturating_duration_since(captured)>Duration::from_secs(1))
-            {
-                return;
-            }
-            let result = make_processed_frame(
-                rgba,
-                receipt,
-                self.generation,
-                self.not_before,
-                processing(&self.state),
-                now,
-            );
-            match result {
-                Ok(Some(frame)) => {
-                    self.publisher.publish(frame);
-                    self.published.store(true, Ordering::Release);
-                }
-                Ok(None) => {}
-                Err(error) => self.fail(error),
-            }
-        }
-    }
-
-    pub(crate) fn make_processed_frame(
-        rgba: &[u8],
-        receipt: FrameReceipt,
-        generation: u64,
-        not_before: Instant,
-        expected: LinuxCameraProcessing,
-        now: Instant,
-    ) -> Result, String> {
-        if receipt.generation != generation || receipt.processing != expected {
-            return Err("Processed camera receipt belongs to another request".into());
-        }
-        let Timestamp::Instant(captured) = receipt.timestamp else {
-            return Err("Processed camera timestamp is not monotonic".into());
-        };
-        if captured < not_before
-            || captured > now
-            || now.saturating_duration_since(captured) > Duration::from_secs(1)
-        {
-            return Err("Processed camera capture timestamp is stale or invalid".into());
-        }
-        let mask = match (expected.blur, receipt.blur) {
-            (LinuxCameraBlur::Off, None) => None,
-            (LinuxCameraBlur::Light | LinuxCameraBlur::Heavy, Some(status)) => {
-                let mode = if expected.blur == LinuxCameraBlur::Light {
-                    cap_camera_effects::BlurMode::Light
-                } else {
-                    cap_camera_effects::BlurMode::Heavy
-                };
-                match status.applied_at(now, LINUX_CAMERA_MAX_MASK_AGE) {
-                    Ok(applied)
-                        if applied.mode == mode
-                            && applied.output_dimensions == receipt.dimensions
-                            && applied.mask.input_submitted_at >= not_before
-                            && applied.mask.generation > 0 =>
-                    {
-                        Some(LinuxCameraMaskReceipt {
-                            generation: applied.mask.generation,
-                            submitted_at: applied.mask.input_submitted_at,
-                            completed_at: applied.mask.inference_completed_at,
-                        })
-                    }
-                    Err(cap_camera_effects::BlurOutputUnavailable::Pending) => return Ok(None),
-                    other => {
-                        return Err(format!("Requested camera blur was not applied: {other:?}"));
-                    }
-                }
-            }
-            _ => return Err("Requested camera blur has no matching output receipt".into()),
-        };
-        let (width, height) = receipt.dimensions;
-        let row = (width as usize)
-            .checked_mul(4)
-            .ok_or("Camera row overflow")?;
-        let size = row
-            .checked_mul(height as usize)
-            .ok_or("Camera image overflow")?;
-        if width == 0 || height == 0 || rgba.len() != size {
-            return Err("Camera pixels do not match their receipt".into());
-        }
-        let mut bgra = vec![0; size];
-        for (source, destination) in rgba.chunks_exact(row).zip(bgra.chunks_exact_mut(row)) {
-            for (x, pixel) in destination.chunks_exact_mut(4).enumerate() {
-                let source_x = if expected.mirrored {
-                    width as usize - 1 - x
-                } else {
-                    x
-                };
-                let source = &source[source_x * 4..source_x * 4 + 4];
-                pixel.copy_from_slice(&[source[2], source[1], source[0], source[3]]);
-            }
-        }
-        Ok(Some(LinuxProcessedCameraFrame {
-            bgra: LinuxCameraPixels::new(bgra),
-            dimensions: receipt.dimensions,
-            stride: row,
-            timestamp: receipt.timestamp,
-            generation,
-            processing: expected,
-            mask,
-        }))
-    }
-}
-
-#[cfg(target_os = "linux")]
-pub use producer::ProcessingFactory;
-#[cfg(target_os = "linux")]
-pub(crate) use producer::{FrameReceipt, RecordingWork, channel as processing_channel};
-
-#[cfg(all(test, target_os = "linux"))]
-mod tests {
-    use super::*;
-    use cap_recording::instant_recording::{LinuxCameraBlur, LinuxCameraProcessing};
-    use cap_timestamp::Timestamp;
-
-    fn input() -> CameraPresentationInput {
-        CameraPresentationInput {
-            viewport_width: 230.0,
-            viewport_height: 286.0,
-            left: 0.0,
-            top: 56.0,
-            width: 230.0,
-            height: 230.0,
-            radius: 115.0,
-            layout_revision: 1,
-            state: CameraPreviewState::default(),
-        }
-    }
-
-    #[test]
-    fn camera_content_excludes_toolbar_and_preserves_physical_position() {
-        let window = PhysicalRect {
-            x: -1200,
-            y: 100,
-            width: 460,
-            height: 572,
-        };
-        let capture = PhysicalRect {
-            x: -1920,
-            y: 0,
-            width: 1920,
-            height: 1080,
-        };
-        let (presentation, _) = presentation_from_input(&input(), window, capture).unwrap();
-        assert_eq!(presentation.rect.x, 720);
-        assert_eq!(presentation.rect.y, 212);
-        assert_eq!(
-            (presentation.rect.width, presentation.rect.height),
-            (460, 460)
-        );
-    }
-
-    #[test]
-    fn presentation_rejects_outside_capture_ambiguous_scale_and_invalid_geometry() {
-        let capture = PhysicalRect {
-            x: 0,
-            y: 0,
-            width: 1920,
-            height: 1080,
-        };
-        assert!(
-            presentation_from_input(
-                &input(),
-                PhysicalRect {
-                    x: 1800,
-                    y: 0,
-                    width: 230,
-                    height: 286
-                },
-                capture
-            )
-            .is_err()
-        );
-        assert!(
-            presentation_from_input(
-                &input(),
-                PhysicalRect {
-                    x: 0,
-                    y: 0,
-                    width: 460,
-                    height: 286
-                },
-                capture
-            )
-            .is_err()
-        );
-        let mut invalid = input();
-        invalid.width = f64::NAN;
-        assert!(
-            presentation_from_input(
-                &invalid,
-                PhysicalRect {
-                    x: 0,
-                    y: 0,
-                    width: 230,
-                    height: 286
-                },
-                capture
-            )
-            .is_err()
-        );
-    }
-
-    #[test]
-    fn full_shape_and_exact_effects_are_not_replaced_by_defaults() {
-        let mut input = input();
-        input.width = 460.0;
-        input.viewport_width = 460.0;
-        input.radius = 24.0;
-        input.state.shape = CameraPreviewShape::Full;
-        input.state.mirrored = true;
-        input.state.background_blur = cap_project::BackgroundBlurMode::Heavy;
-        let (presentation, processing) = presentation_from_input(
-            &input,
-            PhysicalRect {
-                x: 20,
-                y: 30,
-                width: 460,
-                height: 286,
-            },
-            PhysicalRect {
-                x: 0,
-                y: 0,
-                width: 1920,
-                height: 1080,
-            },
-        )
-        .unwrap();
-        assert_eq!(
-            presentation.shape,
-            cap_recording::instant_recording::LinuxCameraShape::RoundedRectangle {
-                radius_pixels: 24
-            }
-        );
-        assert_eq!(presentation.rect.width, 460);
-        assert_eq!(
-            processing,
-            LinuxCameraProcessing {
-                mirrored: true,
-                blur: LinuxCameraBlur::Heavy
-            }
-        );
-    }
-
-    fn receipt(now: Instant) -> FrameReceipt {
-        FrameReceipt {
-            timestamp: Timestamp::Instant(now),
-            generation: 3,
-            processing: LinuxCameraProcessing {
-                mirrored: true,
-                blur: LinuxCameraBlur::Off,
-            },
-            dimensions: (2, 1),
-            blur: None,
-        }
-    }
-
-    #[test]
-    fn recording_packs_rgba_to_bgra_and_mirrors_already_processed_pixels_once() {
-        let now = Instant::now();
-        let receipt = receipt(now);
-        let expected = receipt.processing;
-        let frame = producer::make_processed_frame(
-            &[1, 2, 3, 255, 4, 5, 6, 128],
-            receipt,
-            3,
-            now,
-            expected,
-            now,
-        )
-        .unwrap()
-        .unwrap();
-        assert_eq!(&*frame.bgra, &[6, 5, 4, 128, 3, 2, 1, 255]);
-        assert_eq!(frame.generation, 3);
-        assert_eq!(frame.dimensions, (2, 1));
-    }
-
-    #[test]
-    fn recording_rejects_old_generation_old_capture_and_missing_requested_blur() {
-        let now = Instant::now();
-        let original = receipt(now);
-        assert!(
-            producer::make_processed_frame(
-                &[0; 8],
-                original.clone(),
-                4,
-                now,
-                original.processing,
-                now
-            )
-            .is_err()
-        );
-        assert!(
-            producer::make_processed_frame(
-                &[0; 8],
-                original.clone(),
-                3,
-                now + Duration::from_millis(1),
-                original.processing,
-                now
-            )
-            .is_err()
-        );
-        assert!(
-            producer::make_processed_frame(
-                &[0; 8],
-                original.clone(),
-                3,
-                now,
-                original.processing,
-                now + Duration::from_secs(2)
-            )
-            .is_err()
-        );
-        let mut blurred = original;
-        blurred.processing.blur = LinuxCameraBlur::Light;
-        let expected = blurred.processing;
-        assert!(producer::make_processed_frame(&[0; 8], blurred, 3, now, expected, now).is_err());
-    }
-
-    #[test]
-    fn pending_failed_wrong_mode_and_stale_masks_never_become_recorded_raw_frames() {
-        use cap_camera_effects::{
-            BlurFailure, BlurMaskReceipt, BlurMaskStatus, BlurMode, BlurOutputStatus,
-        };
-        let now = Instant::now();
-        let mut receipt = receipt(now);
-        receipt.processing.blur = LinuxCameraBlur::Heavy;
-        let expected = receipt.processing;
-        let mut status = BlurOutputStatus {
-            mode: BlurMode::Heavy,
-            output_sequence: 1,
-            output_dimensions: (2, 1),
-            mask: BlurMaskStatus::Pending,
-        };
-        receipt.blur = Some(status.clone());
-        assert!(
-            producer::make_processed_frame(&[0; 8], receipt.clone(), 3, now, expected, now)
-                .unwrap()
-                .is_none()
-        );
-        status.mask = BlurMaskStatus::Failed(BlurFailure::Inference("failed".into()));
-        receipt.blur = Some(status.clone());
-        assert!(
-            producer::make_processed_frame(&[0; 8], receipt.clone(), 3, now, expected, now)
-                .is_err()
-        );
-        status.mask = BlurMaskStatus::Ready(BlurMaskReceipt {
-            generation: 1,
-            input_submitted_at: now,
-            inference_completed_at: now,
-            input_dimensions: (2, 1),
-        });
-        status.mode = BlurMode::Light;
-        receipt.blur = Some(status.clone());
-        assert!(
-            producer::make_processed_frame(&[0; 8], receipt.clone(), 3, now, expected, now)
-                .is_err()
-        );
-        status.mode = BlurMode::Heavy;
-        receipt.blur = Some(status);
-        assert!(
-            producer::make_processed_frame(&[0; 8], receipt.clone(), 3, now, expected, now)
-                .unwrap()
-                .is_some()
-        );
-        assert!(
-            producer::make_processed_frame(
-                &[0; 8],
-                receipt,
-                3,
-                now,
-                expected,
-                now + Duration::from_millis(751)
-            )
-            .is_err()
-        );
-    }
-
-    #[tokio::test]
-    async fn presentation_request_cancellation_only_releases_owned_nonce() {
-        let pending = Arc::new(Mutex::new(None));
-        let inputs = Arc::new(Mutex::new(crate::RequestedInputs {
-            microphone: crate::RequestedInput::new(None),
-            camera: crate::RequestedInput::new(Some(
-                cap_recording::feeds::camera::DeviceOrModelID::DeviceID("camera-a".into()),
-            )),
-        }));
-        let (_, state) = tokio::sync::watch::channel(CameraPreviewState::default());
-        let owner = PresentationOwner {
-            nonce: "new".into(),
-            generation: 2,
-            native: NativeSnapshot {
-                id: 1,
-                rect: PhysicalRect {
-                    x: 0,
-                    y: 0,
-                    width: 230,
-                    height: 286,
-                },
-            },
-            selection: SelectionGuard {
-                inputs,
-                revision: 0,
-                selected: cap_recording::feeds::camera::DeviceOrModelID::DeviceID(
-                    "camera-a".into(),
-                ),
-            },
-            state,
-        };
-        let (reply, received) = tokio::sync::oneshot::channel();
-        *pending.lock().unwrap() = Some(PendingPresentation { owner, reply });
-        drop(PendingGuard {
-            pending: pending.clone(),
-            nonce: "old".into(),
-        });
-        assert!(pending.lock().unwrap().is_some());
-        drop(PendingGuard {
-            pending: pending.clone(),
-            nonce: "new".into(),
-        });
-        assert!(received.await.is_err());
-        assert!(pending.lock().unwrap().is_none());
-    }
-
-    #[test]
-    fn camera_request_revision_guard_does_not_rewrite_input_intent() {
-        let state = crate::RequestedInputsState::new(
-            None,
-            Some(cap_recording::feeds::camera::DeviceOrModelID::DeviceID(
-                "camera-a".into(),
-            )),
-        );
-        let guard = SelectionGuard {
-            inputs: state.inner.clone(),
-            revision: 0,
-            selected: cap_recording::feeds::camera::DeviceOrModelID::DeviceID("camera-a".into()),
-        };
-        assert!(guard.current());
-        let revision = state.inner.lock().unwrap().camera.begin(None);
-        assert!(!guard.current());
-        state.inner.lock().unwrap().camera.finish(revision, &Ok(()));
-        assert!(!guard.current());
-        assert!(state.snapshot().camera.value.is_none());
-    }
-
-    #[tokio::test]
-    async fn recording_reservation_excludes_another_attempt_until_owned_drop() {
-        use std::sync::atomic::{AtomicBool, Ordering};
-        let active = Arc::new(AtomicBool::new(false));
-        let first = producer::Reservation::acquire(&active).unwrap();
-        let next_active = active.clone();
-        let (blocked, seen) = tokio::sync::oneshot::channel();
-        let (release, ready) = tokio::sync::oneshot::channel();
-        let next = tokio::spawn(async move {
-            assert!(producer::Reservation::acquire(&next_active).is_none());
-            blocked.send(()).unwrap();
-            ready.await.unwrap();
-            producer::Reservation::acquire(&next_active).unwrap()
-        });
-        seen.await.unwrap();
-        assert!(active.load(Ordering::Acquire));
-        drop(first);
-        release.send(()).unwrap();
-        let next = next.await.unwrap();
-        assert!(active.load(Ordering::Acquire));
-        drop(next);
-        assert!(!active.load(Ordering::Acquire));
-    }
-}
diff --git a/apps/desktop/src-tauri/src/logging.rs b/apps/desktop/src-tauri/src/logging.rs
deleted file mode 100644
index a3650410a27..00000000000
--- a/apps/desktop/src-tauri/src/logging.rs
+++ /dev/null
@@ -1,267 +0,0 @@
-use crate::{
-    ArcLock, feeds::microphone::MicrophoneFeed, general_settings::GeneralSettingsStore,
-    permissions, web_api::ManagerExt,
-};
-use cap_recording::diagnostics::{
-    CameraDiagnostics, CameraFormatInfo, DisplayDiagnostics, HardwareInfo, MicrophoneDiagnostics,
-    StorageInfo,
-};
-use serde::Serialize;
-
-use tauri::{AppHandle, Manager};
-
-#[derive(Serialize)]
-#[serde(rename_all = "camelCase")]
-struct LogUploadDiagnostics {
-    hardware: HardwareInfo,
-    system: cap_recording::diagnostics::SystemDiagnostics,
-    displays: Vec,
-    cameras: Vec,
-    microphones: Vec,
-    storage: Option,
-    permissions: PermissionsInfo,
-    app_state: AppStateInfo,
-}
-
-#[derive(Serialize)]
-#[serde(rename_all = "camelCase")]
-struct PermissionsInfo {
-    screen_recording: String,
-    camera: String,
-    microphone: String,
-}
-
-#[derive(Serialize)]
-#[serde(rename_all = "camelCase")]
-struct AppStateInfo {
-    is_recording: bool,
-    recordings_dir: String,
-    app_data_dir: String,
-}
-
-fn collect_cameras(has_permission: bool) -> Vec {
-    if !has_permission {
-        return vec![];
-    }
-
-    cap_camera::list_cameras()
-        .map(|camera| {
-            let formats = camera
-                .formats()
-                .unwrap_or_default()
-                .into_iter()
-                .take(10)
-                .map(|f| CameraFormatInfo {
-                    width: f.width(),
-                    height: f.height(),
-                    frame_rate: f.frame_rate(),
-                    pixel_format: f.pixel_format_name(),
-                })
-                .collect();
-
-            CameraDiagnostics {
-                device_id: camera.device_id().to_string(),
-                display_name: camera.display_name().to_string(),
-                model_id: camera.model_id().map(|m| m.to_string()),
-                formats,
-            }
-        })
-        .collect()
-}
-
-fn collect_microphones(has_permission: bool) -> Vec {
-    if !has_permission {
-        return vec![];
-    }
-
-    MicrophoneFeed::list()
-        .into_iter()
-        .map(|(name, (_device, config))| MicrophoneDiagnostics {
-            name,
-            sample_rate: config.sample_rate().0,
-            channels: config.channels(),
-            sample_format: format!("{:?}", config.sample_format()),
-            // The richer capability/heuristic fields belong to the diagnostic
-            // report; the log upload keeps its existing shape.
-            is_default: None,
-            is_bluetooth: None,
-            is_usb: None,
-            is_builtin: None,
-            supported_configs: None,
-        })
-        .collect()
-}
-
-fn collect_storage_info(recordings_path: &std::path::Path) -> Option {
-    use sysinfo::Disks;
-    let disks = Disks::new_with_refreshed_list();
-
-    let mut best_match: Option<(&sysinfo::Disk, usize)> = None;
-
-    for disk in disks.iter() {
-        if recordings_path.starts_with(disk.mount_point()) {
-            let mount_point_len = disk.mount_point().as_os_str().len();
-            if best_match.is_none_or(|(_, len)| mount_point_len > len) {
-                best_match = Some((disk, mount_point_len));
-            }
-        }
-    }
-
-    best_match.map(|(disk, _)| StorageInfo {
-        // The diagnostic report redacts these same paths, and both fields ride
-        // in one upload -- leaving this one raw defeats the redaction.
-        recordings_path: cap_recording::diagnostics::redact_home_paths(
-            &recordings_path.display().to_string(),
-        ),
-        available_space_mb: disk.available_space() / (1024 * 1024),
-        total_space_mb: disk.total_space() / (1024 * 1024),
-    })
-}
-
-pub(crate) fn permission_status_str(status: &permissions::OSPermissionStatus) -> &'static str {
-    match status {
-        permissions::OSPermissionStatus::NotNeeded => "not_needed",
-        permissions::OSPermissionStatus::Empty => "not_requested",
-        permissions::OSPermissionStatus::Granted => "granted",
-        permissions::OSPermissionStatus::Denied => "denied",
-    }
-}
-
-fn collect_diagnostics_for_upload(
-    recordings_dir: &std::path::Path,
-    app_data_dir: &std::path::Path,
-    is_recording: bool,
-) -> LogUploadDiagnostics {
-    let hardware = cap_recording::diagnostics::collect_hardware_info();
-    let system = cap_recording::diagnostics::collect_diagnostics();
-    let displays = cap_recording::diagnostics::collect_displays();
-    let permissions = permissions::do_permissions_check(false);
-
-    let cameras = collect_cameras(permissions.camera.permitted());
-    let microphones = collect_microphones(permissions.microphone.permitted());
-    let storage = collect_storage_info(recordings_dir);
-
-    LogUploadDiagnostics {
-        hardware,
-        system,
-        displays,
-        cameras,
-        microphones,
-        storage,
-        permissions: PermissionsInfo {
-            screen_recording: permission_status_str(&permissions.screen_recording).to_string(),
-            camera: permission_status_str(&permissions.camera).to_string(),
-            microphone: permission_status_str(&permissions.microphone).to_string(),
-        },
-        app_state: AppStateInfo {
-            is_recording,
-            recordings_dir: cap_recording::diagnostics::redact_home_paths(
-                &recordings_dir.display().to_string(),
-            ),
-            app_data_dir: cap_recording::diagnostics::redact_home_paths(
-                &app_data_dir.display().to_string(),
-            ),
-        },
-    }
-}
-
-pub async fn upload_log_file(app: &AppHandle) -> Result<(), String> {
-    upload_log_file_inner(app, None).await
-}
-
-pub(crate) async fn upload_log_file_inner(
-    app: &AppHandle,
-    report: Option,
-) -> Result<(), String> {
-    let logs_dir = app
-        .state::>()
-        .read()
-        .await
-        .logs_dir
-        .clone();
-    let log_bundle = tokio::task::spawn_blocking(move || {
-        logs_dir
-            .as_deref()
-            .map_or_else(cap_utils::log_upload::LogBundle::unavailable, |directory| {
-                cap_utils::log_upload::collect(directory, "cap-desktop.log")
-            })
-    })
-    .await
-    .map_err(|_| "Log collection could not finish".to_string())?;
-
-    let app_data_dir = app
-        .path()
-        .app_data_dir()
-        .map_err(|e| format!("Failed to get app data dir: {e}"))?;
-    let recordings_dir = GeneralSettingsStore::recordings_dir(app);
-
-    let is_recording = {
-        let app_lock = app.state::>();
-        let state = app_lock.read().await;
-        matches!(
-            state.recording_state,
-            crate::RecordingState::Active(_) | crate::RecordingState::Pending { .. }
-        )
-    };
-
-    let diagnostics = tokio::task::spawn_blocking(move || {
-        collect_diagnostics_for_upload(&recordings_dir, &app_data_dir, is_recording)
-    })
-    .await
-    .ok();
-    let diagnostics_json = serde_json::to_string(&diagnostics).unwrap_or_else(|_| "{}".to_string());
-    let context = serde_json::json!({
-        "schemaVersion": 1,
-        "app": {
-            "flavor": "tauri",
-            "version": env!("CARGO_PKG_VERSION"),
-            "os": std::env::consts::OS,
-            "binaryArchitecture": std::env::consts::ARCH,
-            "debugBuild": cfg!(debug_assertions),
-            "sourceRevision": option_env!("CAP_BUILD_REVISION"),
-            "sourceDirty": option_env!("CAP_BUILD_DIRTY").and_then(|value| value.parse::().ok()),
-        },
-        "operations": cap_utils::operation_diagnostics::snapshot(),
-        "logCoverage": &log_bundle,
-        "environmentCollectedAt": "upload_time",
-        "mediaIncluded": false,
-    });
-
-    // Everything leaving the machine goes through the redactor. Logs record
-    // whole URLs on failure (reqwest's Display and Debug both append the URL),
-    // and an upload failure logs a presigned S3 PUT, whose query string is a
-    // live write credential for up to an hour.
-    use cap_recording::log_redaction::scrub_log_text;
-
-    let upload = cap_utils::log_upload::prepare_upload(
-        log_bundle,
-        context,
-        Some(&diagnostics_json),
-        report.as_deref(),
-        scrub_log_text,
-    );
-    let mut form = reqwest::multipart::Form::new()
-        .text("log", upload.log)
-        .text("os", std::env::consts::OS)
-        .text("version", env!("CARGO_PKG_VERSION"))
-        .text("context", upload.context);
-    if let Some(diagnostics) = upload.diagnostics {
-        form = form.text("diagnostics", diagnostics);
-    }
-    if let Some(report) = upload.report {
-        form = form.text("report", report);
-    }
-
-    let response = app
-        .api_request("/api/desktop/logs", |client, url| {
-            client.post(url).multipart(form)
-        })
-        .await
-        .map_err(|e| format!("Failed to upload logs: {e}"))?;
-
-    if !response.status().is_success() {
-        return Err(format!("Upload failed with status: {}", response.status()));
-    }
-
-    Ok(())
-}
diff --git a/apps/desktop/src-tauri/src/macos_save_panel.rs b/apps/desktop/src-tauri/src/macos_save_panel.rs
deleted file mode 100644
index c975b5d4c18..00000000000
--- a/apps/desktop/src-tauri/src/macos_save_panel.rs
+++ /dev/null
@@ -1,108 +0,0 @@
-use block2::RcBlock;
-use objc2::rc::Retained;
-use objc2::{ClassType, MainThreadMarker, msg_send};
-use objc2_app_kit::{NSApplication, NSModalResponseCancel, NSModalResponseOK, NSSavePanel};
-use objc2_foundation::{NSArray, NSString};
-use std::cell::RefCell;
-use std::path::PathBuf;
-
-fn response_result(response: isize, path: Option) -> Result, String> {
-    match response {
-        value if value == NSModalResponseCancel => Ok(None),
-        value if value == NSModalResponseOK => path
-            .map(Some)
-            .ok_or_else(|| "The save dialog did not return a file path".to_string()),
-        _ => Err("The save dialog could not be displayed".to_string()),
-    }
-}
-
-pub fn show(
-    file_name: &str,
-    extensions: &[&str],
-    completion: impl FnOnce(Result, String>) + 'static,
-) {
-    let Some(mtm) = MainThreadMarker::new() else {
-        completion(Err(
-            "The save dialog must run on the main thread".to_string()
-        ));
-        return;
-    };
-
-    // AppKit can return nil here even when the bundle signature is valid (Cap #2163).
-    let panel: Option> =
-        unsafe { msg_send![NSSavePanel::class(), savePanel] };
-    let Some(panel) = panel else {
-        completion(Err("The save dialog is unavailable".to_string()));
-        return;
-    };
-
-    unsafe {
-        panel.setCanCreateDirectories(true);
-        panel.setTitle(Some(&NSString::from_str("Save File")));
-        panel.setNameFieldStringValue(&NSString::from_str(file_name));
-        if !extensions.is_empty() {
-            let extensions: Vec<_> = extensions
-                .iter()
-                .map(|extension| NSString::from_str(extension))
-                .collect();
-            let extensions = NSArray::from_retained_slice(&extensions);
-            let _: () = msg_send![&*panel, setAllowedFileTypes: &*extensions];
-        }
-    }
-
-    let completion = RefCell::new(Some(completion));
-    let callback_panel = panel.clone();
-    let callback = RcBlock::new(move |response: isize| {
-        let Some(completion) = completion.borrow_mut().take() else {
-            return;
-        };
-        let path = if response == NSModalResponseOK {
-            unsafe { callback_panel.URL() }
-                .and_then(|url| unsafe { url.path() })
-                .map(|path| PathBuf::from(path.to_string()))
-        } else {
-            None
-        };
-        callback_panel.orderOut(None);
-        completion(response_result(response, path));
-    });
-    let app = NSApplication::sharedApplication(mtm);
-    let parent = app.keyWindow().or_else(|| unsafe { app.mainWindow() });
-    unsafe {
-        if let Some(parent) = parent {
-            panel.beginSheetModalForWindow_completionHandler(&parent, &callback);
-        } else {
-            panel.beginWithCompletionHandler(&callback);
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use objc2_app_kit::NSModalResponseAbort;
-
-    #[test]
-    fn explicit_cancel_does_not_become_a_dialog_failure() {
-        assert_eq!(response_result(NSModalResponseCancel, None), Ok(None));
-    }
-
-    #[test]
-    fn native_failure_is_distinct_from_explicit_cancel() {
-        assert!(response_result(NSModalResponseAbort, None).is_err());
-    }
-
-    #[test]
-    fn accepted_dialog_requires_a_destination() {
-        assert!(response_result(NSModalResponseOK, None).is_err());
-    }
-
-    #[test]
-    fn accepted_dialog_preserves_the_selected_destination() {
-        let path = PathBuf::from("/tmp/My Export.mov");
-        assert_eq!(
-            response_result(NSModalResponseOK, Some(path.clone())),
-            Ok(Some(path))
-        );
-    }
-}
diff --git a/apps/desktop/src-tauri/src/main.rs b/apps/desktop/src-tauri/src/main.rs
deleted file mode 100644
index aa57efeaa70..00000000000
--- a/apps/desktop/src-tauri/src/main.rs
+++ /dev/null
@@ -1,597 +0,0 @@
-#![recursion_limit = "256"]
-#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
-
-use std::sync::Arc;
-
-use cap_desktop_lib::DynLoggingLayer;
-use tracing_subscriber::{Layer, layer::SubscriberExt, util::SubscriberInitExt};
-
-const TOKIO_WORKER_THREAD_STACK_SIZE: usize = 16 * 1024 * 1024;
-
-fn main() {
-    #[cfg(target_os = "linux")]
-    if let Some(threads) = cap_utils::linux_runtime::llvmpipe_thread_count() {
-        // Mesa counts host CPUs inside containers; configure it before spawning threads or bundled children.
-        unsafe {
-            std::env::set_var("LP_NUM_THREADS", threads.to_string());
-        }
-    }
-
-    #[cfg(target_os = "linux")]
-    if let Some(config) = cap_utils::linux_package::appimage_alsa_config_path() {
-        // Configure ALSA before starting threads or handing off to a bundled child process.
-        unsafe {
-            std::env::set_var("ALSA_CONFIG_PATH", config);
-        }
-    }
-
-    #[cfg(target_os = "linux")]
-    if let Err(error) = cap_cli_install::appimage::dispatch_cli() {
-        eprintln!("{error}");
-        std::process::exit(1);
-    }
-
-    #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
-    if std::env::var_os("ORT_DYLIB_PATH").is_none()
-        && let Some(path) = cap_camera_effects::onnx_runtime_library_path()
-    {
-        unsafe {
-            std::env::set_var("ORT_DYLIB_PATH", path);
-        }
-    }
-
-    #[cfg(debug_assertions)]
-    unsafe {
-        std::env::set_var("RUST_LOG", "trace");
-    }
-
-    #[cfg(target_os = "linux")]
-    unsafe {
-        std::env::set_var("WEBKIT_DISABLE_DMABUF_RENDERER", "1");
-    }
-
-    // We have to hold onto the ClientInitGuard until the very end
-    let _sentry_guard = std::option_env!("CAP_DESKTOP_SENTRY_URL").map(|url| {
-        // Crashpad minidump initialization is intentionally disabled. Its process-wide SEH
-        // handler terminates through TerminateProcess, bypassing panic hooks, Tauri exit
-        // events, and Windows Error Reporting. Re-enable it by binding this guard and
-        // passing it to tauri_plugin_sentry::minidump::init once the WER trace is captured.
-        sentry::init((
-            url,
-            sentry::ClientOptions {
-                release: sentry::release_name!(),
-                debug: cfg!(debug_assertions),
-                before_send: Some(Arc::new(|mut event| {
-                    // this is irrelevant to us + users probably don't want us knowing their computer names
-                    event.server_name = None;
-
-                    #[cfg(debug_assertions)]
-                    {
-                        let msg = event.message.clone().unwrap_or("No message".into());
-                        println!("Sentry captured {}: {}", &event.level, &msg);
-                        println!("-- user: {:?}", &event.user);
-                        println!("-- event tags: {:?}", &event.tags);
-                        println!("-- event contexts: {:?}", &event.contexts);
-                        None
-                    }
-
-                    #[cfg(not(debug_assertions))]
-                    {
-                        Some(event)
-                    }
-                })),
-                ..Default::default()
-            },
-        ))
-    });
-
-    let (reload_layer, handle) = tracing_subscriber::reload::Layer::new(None::);
-
-    let logs_dir = {
-        #[cfg(target_os = "macos")]
-        let base_directory = dirs::home_dir();
-
-        #[cfg(not(target_os = "macos"))]
-        let base_directory = dirs::data_local_dir();
-
-        let path = resolve_log_directory(base_directory);
-
-        #[cfg(debug_assertions)]
-        let path =
-            match cap_desktop_lib::initialize_stop_editor_benchmark(create_benchmark_log_directory)
-            {
-                Ok(directory) => directory.or(path),
-                Err(error) => {
-                    eprintln!("Invalid Stop benchmark invocation: {error}");
-                    std::process::exit(2);
-                }
-            };
-
-        path
-    };
-
-    if logs_dir.is_none() {
-        eprintln!(
-            "Log directory is unavailable; file logging and persistent crash detection are disabled; console logging remains enabled"
-        );
-    }
-
-    let (info_file_writer, _info_logger_guard) = match (
-        logs_dir.as_deref(),
-        create_log_appender(logs_dir.as_deref(), "cap-desktop.log"),
-    ) {
-        (Some(logs_dir), Some(appender)) => {
-            let (writer, guard) = tracing_appender::non_blocking(
-                cap_utils::diagnostic_writer::DiagnosticWriter::new(
-                    appender,
-                    logs_dir,
-                    "cap-desktop.log",
-                ),
-            );
-            let queue_errors = writer.error_counter();
-            cap_utils::operation_diagnostics::install_queue_loss_counter(move || {
-                queue_errors.dropped_lines()
-            });
-            let diagnostic_writer = writer.clone();
-            cap_utils::operation_diagnostics::install_sink(
-                cap_utils::operation_diagnostics::AppInfo {
-                    flavor: "tauri",
-                    version: env!("CARGO_PKG_VERSION"),
-                    source_revision: option_env!("CAP_BUILD_REVISION"),
-                    debug_build: cfg!(debug_assertions),
-                    source_dirty: option_env!("CAP_BUILD_DIRTY").map(|value| value == "true"),
-                },
-                move |bytes| {
-                    use std::io::Write;
-                    let _ = diagnostic_writer.clone().write_all(bytes);
-                },
-            );
-            (Some(writer), Some(guard))
-        }
-        _ => (None, None),
-    };
-
-    let errors_file_appender = create_log_appender(logs_dir.as_deref(), "cap-desktop-errors.log");
-
-    let (otel_layer, _tracer) = if cfg!(debug_assertions) {
-        use opentelemetry::trace::TracerProvider;
-        use opentelemetry_otlp::WithExportConfig;
-        use tracing_subscriber::Layer;
-
-        let tracer = opentelemetry_sdk::trace::SdkTracerProvider::builder()
-            .with_batch_exporter(
-                opentelemetry_otlp::SpanExporter::builder()
-                    .with_http()
-                    .with_protocol(opentelemetry_otlp::Protocol::HttpJson)
-                    .build()
-                    .unwrap(),
-            )
-            .with_resource(
-                opentelemetry_sdk::Resource::builder()
-                    .with_service_name("cap-desktop")
-                    .build(),
-            )
-            .build();
-
-        let layer = tracing_opentelemetry::layer()
-            .with_tracer(tracer.tracer("cap-desktop"))
-            .boxed();
-
-        opentelemetry::global::set_tracer_provider(tracer.clone());
-        (Some(layer), Some(tracer))
-    } else {
-        (None, None)
-    };
-
-    #[cfg(debug_assertions)]
-    let level_filter = tracing_subscriber::filter::LevelFilter::TRACE;
-    #[cfg(not(debug_assertions))]
-    let level_filter = tracing_subscriber::filter::LevelFilter::INFO;
-
-    tracing_subscriber::registry()
-        .with(tracing_subscriber::filter::filter_fn(
-            (|v| v.target().starts_with("cap_")) as fn(&tracing::Metadata) -> bool,
-        ))
-        .with(reload_layer)
-        .with(level_filter)
-        .with(otel_layer)
-        .with(
-            tracing_subscriber::fmt::layer()
-                .with_ansi(true)
-                .with_target(true),
-        )
-        .with(info_file_writer.map(|writer| {
-            tracing_subscriber::fmt::layer()
-                .with_ansi(false)
-                .with_target(true)
-                .with_writer(writer)
-        }))
-        .with(errors_file_appender.map(|appender| {
-            tracing_subscriber::fmt::layer()
-                .with_ansi(false)
-                .with_target(true)
-                .with_writer(appender)
-                .with_filter(tracing_subscriber::filter::LevelFilter::WARN)
-        }))
-        .init();
-
-    install_panic_hook(logs_dir.clone());
-
-    #[cfg(debug_assertions)]
-    sentry::configure_scope(|scope| {
-        scope.set_user(Some(sentry::User {
-            username: Some("_DEV_".into()),
-            ..Default::default()
-        }));
-    });
-
-    tokio::runtime::Builder::new_multi_thread()
-        .enable_all()
-        .thread_stack_size(TOKIO_WORKER_THREAD_STACK_SIZE)
-        .build()
-        .expect("Failed to build multi threaded tokio runtime")
-        .block_on(async move {
-            drop(tokio::spawn(
-                cap_utils::operation_diagnostics::run_checkpoints(),
-            ));
-            cap_desktop_lib::run(handle, logs_dir).await;
-        });
-}
-
-fn resolve_log_directory(base_directory: Option) -> Option {
-    base_directory.map(|directory| {
-        #[cfg(target_os = "macos")]
-        let directory = directory.join("Library/Logs").join("so.cap.desktop");
-        #[cfg(not(target_os = "macos"))]
-        let directory = directory.join("so.cap.desktop").join("logs");
-        directory
-    })
-}
-
-fn create_log_appender(
-    directory: Option<&std::path::Path>,
-    prefix: &str,
-) -> Option {
-    use std::io::Write;
-
-    let directory = directory?;
-    match tracing_appender::rolling::RollingFileAppender::builder()
-        .rotation(tracing_appender::rolling::Rotation::DAILY)
-        .filename_prefix(prefix)
-        .build(directory)
-    {
-        Ok(appender) => Some(appender),
-        Err(error) => {
-            let _ = writeln!(
-                std::io::stderr(),
-                "Could not open {prefix} in {}: {error}; console logging remains enabled",
-                directory.display()
-            );
-            None
-        }
-    }
-}
-
-#[cfg(debug_assertions)]
-fn create_benchmark_log_directory(
-    output: &std::path::Path,
-    directory: &std::path::Path,
-) -> std::io::Result {
-    use std::{io, path::Component};
-
-    if !output.is_absolute()
-        || !directory.is_absolute()
-        || output == directory
-        || [output, directory].into_iter().any(|path| {
-            path.components().any(|component| {
-                !matches!(
-                    component,
-                    Component::Prefix(_) | Component::RootDir | Component::Normal(_)
-                )
-            })
-        })
-    {
-        return Err(io::Error::new(
-            io::ErrorKind::InvalidInput,
-            "Benchmark paths must be distinct absolute paths without traversal",
-        ));
-    }
-    let parent = directory.parent().ok_or_else(|| {
-        io::Error::new(
-            io::ErrorKind::InvalidInput,
-            "Benchmark log directory has no parent",
-        )
-    })?;
-    if output.parent() != Some(parent) || parent.canonicalize()? != parent || !parent.is_dir() {
-        return Err(io::Error::new(
-            io::ErrorKind::InvalidInput,
-            "Benchmark output and logs must share an existing canonical parent",
-        ));
-    }
-    for path in [output, directory] {
-        match std::fs::symlink_metadata(path) {
-            Ok(_) => {
-                return Err(io::Error::new(
-                    io::ErrorKind::AlreadyExists,
-                    "Benchmark output and log paths must be new",
-                ));
-            }
-            Err(error) if error.kind() == io::ErrorKind::NotFound => {}
-            Err(error) => return Err(error),
-        }
-    }
-    let builder = std::fs::DirBuilder::new();
-    #[cfg(unix)]
-    let builder = {
-        use std::os::unix::fs::DirBuilderExt;
-        let mut builder = builder;
-        builder.mode(0o700);
-        builder
-    };
-    builder.create(directory)?;
-    Ok(directory.to_path_buf())
-}
-
-fn install_panic_hook(logs_dir: Option) {
-    let prev = std::panic::take_hook();
-    let panics_log = logs_dir.map(|directory| directory.join("panics.log"));
-    std::panic::set_hook(Box::new(move |info| {
-        let location = info
-            .location()
-            .map(|l| format!("{}:{}:{}", l.file(), l.line(), l.column()))
-            .unwrap_or_else(|| "".to_string());
-        let message = info
-            .payload()
-            .downcast_ref::<&str>()
-            .map(|s| (*s).to_string())
-            .or_else(|| info.payload().downcast_ref::().cloned())
-            .unwrap_or_else(|| "".to_string());
-        let backtrace = std::backtrace::Backtrace::force_capture();
-        let thread = std::thread::current();
-        let thread_name = thread.name().unwrap_or("").to_string();
-        let timestamp = chrono::Utc::now().to_rfc3339();
-        let pid = std::process::id();
-
-        write_panic_record(
-            panics_log.as_deref(),
-            ×tamp,
-            pid,
-            &thread_name,
-            &location,
-            &message,
-            &backtrace,
-        );
-
-        tracing::error!(
-            target: "cap_desktop_panic",
-            location = %location,
-            thread = %thread_name,
-            message = %message,
-            backtrace = %backtrace,
-            "panic"
-        );
-        eprintln!(
-            "[cap-desktop panic] thread '{thread_name}' at {location}: {message}\nbacktrace:\n{backtrace}"
-        );
-        prev(info);
-    }));
-}
-
-fn write_panic_record(
-    path: Option<&std::path::Path>,
-    timestamp: &str,
-    pid: u32,
-    thread_name: &str,
-    location: &str,
-    message: &str,
-    backtrace: &std::backtrace::Backtrace,
-) {
-    use std::io::Write;
-    let Some(path) = path else {
-        return;
-    };
-    let Ok(mut file) = std::fs::OpenOptions::new()
-        .create(true)
-        .append(true)
-        .open(path)
-    else {
-        return;
-    };
-    let _ = writeln!(
-        file,
-        "[{timestamp}] pid={pid} thread='{thread_name}' at {location}: {message}\n{backtrace}\n----"
-    );
-    let _ = file.flush();
-}
-
-#[cfg(test)]
-mod logging_tests {
-    use super::{create_log_appender, resolve_log_directory, write_panic_record};
-    use std::{io::Write, path::PathBuf};
-
-    struct LogDirectory(PathBuf);
-
-    impl LogDirectory {
-        fn new() -> Self {
-            let nonce = std::time::SystemTime::now()
-                .duration_since(std::time::UNIX_EPOCH)
-                .unwrap()
-                .as_nanos();
-            let directory = std::env::temp_dir().join(format!(
-                "cap-desktop-logging-{}-{nonce}",
-                std::process::id()
-            ));
-            std::fs::create_dir_all(&directory).unwrap();
-            Self(directory)
-        }
-    }
-
-    impl Drop for LogDirectory {
-        fn drop(&mut self) {
-            let _ = std::fs::remove_dir_all(&self.0);
-        }
-    }
-
-    #[test]
-    fn missing_base_directory_disables_file_logging_without_a_fallback() {
-        let directory = resolve_log_directory(None);
-        assert!(directory.is_none());
-        assert!(create_log_appender(directory.as_deref(), "cap-desktop.log").is_none());
-        assert!(create_log_appender(directory.as_deref(), "cap-desktop-errors.log").is_none());
-        write_panic_record(
-            None,
-            "timestamp",
-            1,
-            "test",
-            "test:1",
-            "synthetic panic",
-            &std::backtrace::Backtrace::disabled(),
-        );
-    }
-
-    #[test]
-    fn available_base_directory_preserves_the_platform_log_path() {
-        let base = LogDirectory::new();
-        #[cfg(target_os = "macos")]
-        let expected = base.0.join("Library/Logs/so.cap.desktop");
-        #[cfg(not(target_os = "macos"))]
-        let expected = base.0.join("so.cap.desktop/logs");
-        assert_eq!(resolve_log_directory(Some(base.0.clone())), Some(expected));
-        assert!(std::fs::read_dir(&base.0).unwrap().next().is_none());
-    }
-
-    #[test]
-    fn available_panic_log_preserves_existing_records() {
-        let directory = LogDirectory::new();
-        let path = directory.0.join("panics.log");
-        std::fs::write(&path, "existing record\n").unwrap();
-        write_panic_record(
-            Some(&path),
-            "timestamp",
-            1,
-            "test",
-            "test:1",
-            "synthetic panic",
-            &std::backtrace::Backtrace::disabled(),
-        );
-        let records = std::fs::read_to_string(path).unwrap();
-        assert!(records.starts_with("existing record\n"));
-        assert!(records.contains("synthetic panic"));
-    }
-
-    #[test]
-    fn healthy_log_destination_preserves_existing_records() {
-        let directory = LogDirectory::new();
-        let destination = directory.0.join("nested");
-        for record in ["first\n", "second\n"] {
-            let mut appender = create_log_appender(Some(&destination), "cap.log").unwrap();
-            appender.write_all(record.as_bytes()).unwrap();
-            appender.flush().unwrap();
-        }
-        let records: String = std::fs::read_dir(destination)
-            .unwrap()
-            .map(|entry| std::fs::read_to_string(entry.unwrap().path()).unwrap())
-            .collect();
-        assert!(records.contains("first\n"));
-        assert!(records.contains("second\n"));
-    }
-
-    #[test]
-    fn unavailable_log_directory_disables_only_file_logging() {
-        let directory = LogDirectory::new();
-        let destination = directory.0.join("blocked");
-        std::fs::write(&destination, "existing file").unwrap();
-        assert!(create_log_appender(Some(&destination), "cap.log").is_none());
-        assert_eq!(
-            std::fs::read_to_string(destination).unwrap(),
-            "existing file"
-        );
-    }
-
-    #[test]
-    fn unavailable_daily_log_file_disables_only_file_logging() {
-        let directory = LogDirectory::new();
-        let today = chrono::Utc::now().date_naive();
-        for days in [-1, 0, 1] {
-            let date = today + chrono::Duration::days(days);
-            std::fs::create_dir(directory.0.join(format!("cap.log.{date}"))).unwrap();
-        }
-        assert!(create_log_appender(Some(&directory.0), "cap.log").is_none());
-        assert!(create_log_appender(Some(&directory.0), "other.log").is_some());
-    }
-}
-
-#[cfg(all(test, debug_assertions))]
-mod benchmark_log_directory_tests {
-    use super::create_benchmark_log_directory;
-
-    #[test]
-    fn benchmark_logs_use_a_new_private_sibling_without_creating_output() {
-        let temporary = tempfile::tempdir().unwrap();
-        let root = temporary.path().canonicalize().unwrap();
-        let output = root.join("benchmark.json");
-        let logs = root.join("logs");
-        assert_eq!(
-            create_benchmark_log_directory(&output, &logs).unwrap(),
-            logs
-        );
-        assert!(logs.is_dir());
-        assert!(!output.exists());
-        #[cfg(unix)]
-        {
-            use std::os::unix::fs::PermissionsExt;
-            assert_eq!(logs.metadata().unwrap().permissions().mode() & 0o777, 0o700);
-        }
-    }
-
-    #[test]
-    fn existing_or_foreign_benchmark_paths_are_preserved() {
-        let temporary = tempfile::tempdir().unwrap();
-        let root = temporary.path().canonicalize().unwrap();
-        let output = root.join("benchmark.json");
-        let logs = root.join("logs");
-        std::fs::write(&output, "retained evidence").unwrap();
-        assert!(create_benchmark_log_directory(&output, &logs).is_err());
-        assert_eq!(
-            std::fs::read_to_string(&output).unwrap(),
-            "retained evidence"
-        );
-        assert!(!logs.exists());
-        std::fs::create_dir(&logs).unwrap();
-        assert!(create_benchmark_log_directory(&root.join("new.json"), &logs).is_err());
-        assert!(
-            create_benchmark_log_directory(&root.join("new.json"), &root.join("other/logs"))
-                .is_err()
-        );
-        assert!(
-            create_benchmark_log_directory(
-                std::path::Path::new("relative.json"),
-                &root.join("fresh")
-            )
-            .is_err()
-        );
-        assert!(
-            create_benchmark_log_directory(&root.join("new.json"), &root.join("nested/../fresh"))
-                .is_err()
-        );
-        assert!(!root.join("fresh").exists());
-    }
-
-    #[cfg(unix)]
-    #[test]
-    fn symlinked_benchmark_parents_are_rejected_without_writes() {
-        use std::os::unix::fs::symlink;
-        let temporary = tempfile::tempdir().unwrap();
-        let root = temporary.path().canonicalize().unwrap();
-        let actual = root.join("actual");
-        let alias = root.join("alias");
-        std::fs::create_dir(&actual).unwrap();
-        symlink(&actual, &alias).unwrap();
-        assert!(
-            create_benchmark_log_directory(&alias.join("result.json"), &alias.join("logs"))
-                .is_err()
-        );
-        assert!(!actual.join("logs").exists());
-        assert!(!actual.join("result.json").exists());
-    }
-}
diff --git a/apps/desktop/src-tauri/src/main_window_geometry.rs b/apps/desktop/src-tauri/src/main_window_geometry.rs
deleted file mode 100644
index 17ed9e88b1c..00000000000
--- a/apps/desktop/src-tauri/src/main_window_geometry.rs
+++ /dev/null
@@ -1,54 +0,0 @@
-pub(crate) const SIZE: (f64, f64) = (330.0, 395.0);
-const PADDING: f64 = 12.0;
-
-pub(crate) fn restored_position(
-    before: (f64, f64),
-    window_size: (f64, f64),
-    work_origin: (f64, f64),
-    work_size: (f64, f64),
-    scale: f64,
-) -> (f64, f64) {
-    let padding = PADDING * scale;
-    let minimum = (work_origin.0 + padding, work_origin.1 + padding);
-    let maximum = (
-        (work_origin.0 + work_size.0 - window_size.0 - padding).max(minimum.0),
-        (work_origin.1 + work_size.1 - window_size.1 - padding).max(minimum.1),
-    );
-    (
-        before.0.clamp(minimum.0, maximum.0),
-        before.1.clamp(minimum.1, maximum.1),
-    )
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn preserves_top_left_and_clamps_on_scaled_negative_coordinate_screens() {
-        assert_eq!(
-            restored_position(
-                (-1800.0, 80.0),
-                (1200.0, 1320.0),
-                (-2880.0, 0.0),
-                (2880.0, 1800.0),
-                2.0
-            ),
-            (-1800.0, 80.0)
-        );
-        assert_eq!(
-            restored_position(
-                (-400.0, 1700.0),
-                (1200.0, 1320.0),
-                (-2880.0, 0.0),
-                (2880.0, 1800.0),
-                2.0
-            ),
-            (-1224.0, 456.0)
-        );
-        assert_eq!(
-            restored_position((0.0, 0.0), (600.0, 660.0), (0.0, 0.0), (500.0, 500.0), 1.0),
-            (12.0, 12.0)
-        );
-    }
-}
diff --git a/apps/desktop/src-tauri/src/notifications.rs b/apps/desktop/src-tauri/src/notifications.rs
deleted file mode 100644
index be0d16563d6..00000000000
--- a/apps/desktop/src-tauri/src/notifications.rs
+++ /dev/null
@@ -1,160 +0,0 @@
-use crate::{AppSounds, general_settings::GeneralSettingsStore};
-#[cfg(not(target_os = "linux"))]
-use tauri_plugin_notification::NotificationExt;
-
-#[allow(unused)]
-pub enum NotificationType {
-    VideoSaved,
-    VideoCopiedToClipboard,
-    ShareableLinkCopied,
-    UploadFailed,
-    VideoSaveFailed,
-    VideoCopyFailed,
-    ShareableLinkFailed,
-    ScreenshotSaved,
-    ScreenshotCopiedToClipboard,
-    ScreenshotSaveFailed,
-    ScreenshotCopyFailed,
-}
-
-impl NotificationType {
-    fn details(&self) -> (&'static str, &'static str, bool) {
-        match self {
-            NotificationType::VideoSaved => ("Video Saved", "Video saved successfully", false),
-            NotificationType::VideoCopiedToClipboard => {
-                ("Video Copied", "Video copied to clipboard", false)
-            }
-            NotificationType::ShareableLinkCopied => {
-                ("Link Copied", "Link copied to clipboard", false)
-            }
-            NotificationType::UploadFailed => (
-                "Upload Failed",
-                "Unable to upload media. Please try again",
-                true,
-            ),
-            NotificationType::VideoSaveFailed => (
-                "Save Failed",
-                "Unable to save video. Please try again",
-                true,
-            ),
-            NotificationType::VideoCopyFailed => (
-                "Copy Failed",
-                "Unable to copy video to clipboard. Please try again",
-                true,
-            ),
-            NotificationType::ShareableLinkFailed => (
-                "Share Failed",
-                "Unable to create shareable link. Please try again",
-                true,
-            ),
-            NotificationType::ScreenshotSaved => {
-                ("Screenshot Saved", "Screenshot saved successfully", false)
-            }
-            NotificationType::ScreenshotCopiedToClipboard => {
-                ("Screenshot Copied", "Screenshot copied to clipboard", false)
-            }
-            NotificationType::ScreenshotSaveFailed => (
-                "Save Failed",
-                "Unable to save screenshot. Please try again",
-                true,
-            ),
-            NotificationType::ScreenshotCopyFailed => (
-                "Copy Failed",
-                "Unable to copy screenshot to clipboard. Please try again",
-                true,
-            ),
-        }
-    }
-
-    #[allow(unused)]
-    pub fn message(&self) -> &'static str {
-        match self {
-            NotificationType::UploadFailed => {
-                "Failed to upload your video after multiple attempts. Please try again later."
-            }
-            _ => "",
-        }
-    }
-
-    #[allow(unused)]
-    pub fn title(&self) -> &'static str {
-        match self {
-            NotificationType::UploadFailed => "Upload Failed",
-            _ => "",
-        }
-    }
-
-    pub fn send(self, app: &tauri::AppHandle) {
-        send_notification(app, self);
-    }
-}
-
-pub fn send_notification(app: &tauri::AppHandle, notification_type: NotificationType) {
-    let enable_notifications = GeneralSettingsStore::get(app)
-        .map(|settings| settings.is_some_and(|s| s.enable_notifications))
-        .unwrap_or(false);
-
-    if !enable_notifications {
-        return;
-    }
-
-    let (title, body, _is_error) = notification_type.details();
-
-    #[cfg(target_os = "linux")]
-    tauri::async_runtime::spawn(async move {
-        if let Err(error) = show_linux_notification(title, body).await {
-            tracing::warn!(%error, "Failed to send notification");
-        }
-    });
-
-    #[cfg(not(target_os = "linux"))]
-    app.notification()
-        .builder()
-        .title(title)
-        .body(body)
-        .show()
-        .ok();
-
-    let skip_sound = matches!(
-        notification_type,
-        NotificationType::ScreenshotSaved
-            | NotificationType::ScreenshotCopiedToClipboard
-            | NotificationType::ScreenshotSaveFailed
-            | NotificationType::ScreenshotCopyFailed
-    );
-
-    if !skip_sound {
-        AppSounds::Notification.play();
-    }
-}
-
-#[cfg(target_os = "linux")]
-fn build_linux_notification(title: &str, body: &str) -> notify_rust::Notification {
-    let mut notification = notify_rust::Notification::new();
-    notification.summary(title).body(body).auto_icon();
-    notification
-}
-
-#[cfg(target_os = "linux")]
-pub(crate) async fn show_linux_notification(title: &str, body: &str) -> Result<(), String> {
-    build_linux_notification(title, body)
-        .show_async()
-        .await
-        .map(|_| ())
-        .map_err(|error| format!("Failed to send notification: {error}"))
-}
-
-#[cfg(all(test, target_os = "linux"))]
-mod tests {
-    use super::build_linux_notification;
-
-    #[test]
-    fn linux_notification_preserves_content_and_application_icon() {
-        let notification = build_linux_notification("Screenshot Saved", "Saved successfully");
-
-        assert_eq!(notification.summary, "Screenshot Saved");
-        assert_eq!(notification.body, "Saved successfully");
-        assert_eq!(notification.icon, notification.appname);
-        assert!(!notification.icon.is_empty());
-    }
-}
diff --git a/apps/desktop/src-tauri/src/panel_manager.rs b/apps/desktop/src-tauri/src/panel_manager.rs
deleted file mode 100644
index 68bc7eff07d..00000000000
--- a/apps/desktop/src-tauri/src/panel_manager.rs
+++ /dev/null
@@ -1,243 +0,0 @@
-#[cfg(target_os = "macos")]
-use std::collections::HashMap;
-#[cfg(target_os = "macos")]
-use tokio::sync::RwLock;
-#[cfg(target_os = "macos")]
-use tracing::{debug, info, trace, warn};
-
-#[cfg(target_os = "macos")]
-#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
-pub enum PanelState {
-    #[default]
-    None,
-    Creating,
-    Ready,
-    Destroying,
-}
-
-#[cfg(target_os = "macos")]
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub enum PanelWindowType {
-    Camera,
-}
-
-#[cfg(target_os = "macos")]
-impl std::fmt::Display for PanelWindowType {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            Self::Camera => write!(f, "Camera"),
-        }
-    }
-}
-
-#[cfg(target_os = "macos")]
-struct PanelEntry {
-    state: PanelState,
-    operation_id: u64,
-}
-
-#[cfg(target_os = "macos")]
-impl Default for PanelEntry {
-    fn default() -> Self {
-        Self {
-            state: PanelState::None,
-            operation_id: 0,
-        }
-    }
-}
-
-#[cfg(target_os = "macos")]
-pub struct PanelManager {
-    panels: RwLock>,
-    operation_counter: std::sync::atomic::AtomicU64,
-}
-
-#[cfg(target_os = "macos")]
-impl Default for PanelManager {
-    fn default() -> Self {
-        Self::new()
-    }
-}
-
-#[cfg(target_os = "macos")]
-impl PanelManager {
-    pub fn new() -> Self {
-        Self {
-            panels: RwLock::new(HashMap::new()),
-            operation_counter: std::sync::atomic::AtomicU64::new(0),
-        }
-    }
-
-    pub async fn get_state(&self, window_type: PanelWindowType) -> PanelState {
-        let panels = self.panels.read().await;
-        panels
-            .get(&window_type)
-            .map(|e| e.state)
-            .unwrap_or(PanelState::None)
-    }
-
-    pub async fn try_begin_create(
-        &self,
-        window_type: PanelWindowType,
-    ) -> Option {
-        let mut panels = self.panels.write().await;
-        let entry = panels.entry(window_type).or_default();
-
-        match entry.state {
-            PanelState::None => {
-                let op_id = self
-                    .operation_counter
-                    .fetch_add(1, std::sync::atomic::Ordering::SeqCst);
-                entry.state = PanelState::Creating;
-                entry.operation_id = op_id;
-                debug!(
-                    "Panel {}: beginning create operation (op_id={})",
-                    window_type, op_id
-                );
-                Some(PanelOperationGuard {
-                    operation_id: op_id,
-                    completed: false,
-                })
-            }
-            PanelState::Creating => {
-                debug!(
-                    "Panel {}: create blocked - already creating (op_id={})",
-                    window_type, entry.operation_id
-                );
-                None
-            }
-            PanelState::Ready => {
-                debug!(
-                    "Panel {}: create blocked - already ready (op_id={})",
-                    window_type, entry.operation_id
-                );
-                None
-            }
-            PanelState::Destroying => {
-                debug!(
-                    "Panel {}: create blocked - currently destroying (op_id={})",
-                    window_type, entry.operation_id
-                );
-                None
-            }
-        }
-    }
-
-    pub async fn mark_ready(&self, window_type: PanelWindowType, operation_id: u64) {
-        let mut panels = self.panels.write().await;
-        if let Some(entry) = panels.get_mut(&window_type) {
-            if entry.operation_id == operation_id && entry.state == PanelState::Creating {
-                entry.state = PanelState::Ready;
-                info!(
-                    "Panel {}: marked ready (op_id={})",
-                    window_type, operation_id
-                );
-            } else {
-                warn!(
-                    "Panel {}: mark_ready ignored - state mismatch (current state={:?}, current op={}, requested op={})",
-                    window_type, entry.state, entry.operation_id, operation_id
-                );
-            }
-        }
-    }
-
-    pub async fn force_reset(&self, window_type: PanelWindowType) {
-        let mut panels = self.panels.write().await;
-        if let Some(entry) = panels.get_mut(&window_type) {
-            warn!(
-                "Panel {}: force reset from state {:?} (op_id={})",
-                window_type, entry.state, entry.operation_id
-            );
-            entry.state = PanelState::None;
-            entry.operation_id = 0;
-        }
-    }
-
-    pub async fn wait_for_state(
-        &self,
-        window_type: PanelWindowType,
-        target_states: &[PanelState],
-        timeout: std::time::Duration,
-    ) -> bool {
-        let start = std::time::Instant::now();
-        let poll_interval = std::time::Duration::from_millis(10);
-
-        while start.elapsed() < timeout {
-            let state = self.get_state(window_type).await;
-            if target_states.contains(&state) {
-                return true;
-            }
-            tokio::time::sleep(poll_interval).await;
-        }
-
-        let state = self.get_state(window_type).await;
-        warn!(
-            "Panel {}: wait_for_state timed out after {:?}, current state={:?}, wanted one of {:?}",
-            window_type, timeout, state, target_states
-        );
-        false
-    }
-}
-
-#[cfg(target_os = "macos")]
-pub struct PanelOperationGuard {
-    pub operation_id: u64,
-    completed: bool,
-}
-
-#[cfg(target_os = "macos")]
-impl PanelOperationGuard {
-    pub fn mark_completed(&mut self) {
-        self.completed = true;
-    }
-}
-
-#[cfg(target_os = "macos")]
-pub fn is_window_handle_valid(window: &tauri::WebviewWindow) -> bool {
-    match window.inner_size() {
-        Ok(_) => true,
-        Err(e) => {
-            trace!("Window handle validation failed: {}", e);
-            false
-        }
-    }
-}
-
-#[cfg(target_os = "macos")]
-pub type NSPanel = tauri_nspanel::objc_id::Id<
-    tauri_nspanel::raw_nspanel::RawNSPanel,
-    tauri_nspanel::objc_id::Shared,
->;
-
-#[cfg(target_os = "macos")]
-pub fn try_to_panel(window: &tauri::WebviewWindow) -> Result {
-    use tauri_nspanel::WebviewWindowExt as NSPanelWebviewWindowExt;
-
-    if !is_window_handle_valid(window) {
-        return Err(PanelConversionError::InvalidHandle);
-    }
-
-    window
-        .to_panel()
-        .map_err(|e| PanelConversionError::ConversionFailed(format!("{e:?}")))
-}
-
-#[cfg(target_os = "macos")]
-#[derive(Debug)]
-pub enum PanelConversionError {
-    InvalidHandle,
-    ConversionFailed(String),
-}
-
-#[cfg(target_os = "macos")]
-impl std::fmt::Display for PanelConversionError {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            Self::InvalidHandle => write!(f, "Window handle is invalid or unavailable"),
-            Self::ConversionFailed(msg) => write!(f, "Panel conversion failed: {msg}"),
-        }
-    }
-}
-
-#[cfg(target_os = "macos")]
-impl std::error::Error for PanelConversionError {}
diff --git a/apps/desktop/src-tauri/src/permissions.rs b/apps/desktop/src-tauri/src/permissions.rs
deleted file mode 100644
index 6c37e8e9c5b..00000000000
--- a/apps/desktop/src-tauri/src/permissions.rs
+++ /dev/null
@@ -1,979 +0,0 @@
-use serde::{Deserialize, Serialize};
-
-#[cfg(target_os = "macos")]
-use crate::{general_settings::GeneralSettingsStore, windows::CapWindowId};
-#[cfg(target_os = "macos")]
-use cidre::{av, sc};
-#[cfg(target_os = "macos")]
-use objc2_app_kit::{NSApplicationActivationOptions, NSRunningApplication};
-#[cfg(target_os = "macos")]
-use std::{
-    future::Future,
-    str::FromStr,
-    sync::atomic::{AtomicBool, AtomicU8, AtomicU32, AtomicU64, Ordering},
-    time::Duration,
-};
-#[cfg(target_os = "macos")]
-use tauri::Manager;
-use tracing::instrument;
-
-#[cfg(target_os = "macos")]
-static MACOS_DOCK_VISIBILITY_SYNC_GENERATION: AtomicU64 = AtomicU64::new(0);
-#[cfg(target_os = "macos")]
-static MACOS_PENDING_PANEL_WINDOWS: AtomicU32 = AtomicU32::new(0);
-#[cfg(target_os = "macos")]
-static MACOS_SCK_PERMISSION_MISMATCH_LOGGED: AtomicBool = AtomicBool::new(false);
-#[cfg(target_os = "macos")]
-static MACOS_SCK_DISPLAYS_VALIDATED: AtomicBool = AtomicBool::new(false);
-#[cfg(target_os = "macos")]
-static MACOS_SCK_DISPLAYS_VALIDATION_IN_FLIGHT: AtomicBool = AtomicBool::new(false);
-#[cfg(target_os = "macos")]
-static MACOS_SCK_LAST_STRICT_OUTCOME: AtomicU8 = AtomicU8::new(MACOS_SCK_OUTCOME_UNKNOWN);
-#[cfg(target_os = "macos")]
-static MACOS_SCK_LAST_VALIDATION_ATTEMPT: std::sync::Mutex> =
-    std::sync::Mutex::new(None);
-#[cfg(target_os = "macos")]
-const MACOS_SCK_VALIDATION_RETRY_INTERVAL: Duration = Duration::from_secs(5);
-// Strictly less than the retry interval: the backoff stamp is refreshed when
-// an attempt completes, and a timeout that consumed the whole interval would
-// otherwise leave zero backoff between attempts against a wedged replayd.
-#[cfg(target_os = "macos")]
-const MACOS_SCK_VALIDATION_TIMEOUT: Duration = Duration::from_secs(4);
-#[cfg(target_os = "macos")]
-const MACOS_SCK_OUTCOME_UNKNOWN: u8 = 0;
-#[cfg(target_os = "macos")]
-const MACOS_SCK_OUTCOME_OK: u8 = 1;
-#[cfg(target_os = "macos")]
-const MACOS_SCK_OUTCOME_FAILED: u8 = 2;
-
-#[cfg(target_os = "macos")]
-pub(crate) struct MacosPanelWindowActivationGuard {
-    app: tauri::AppHandle,
-}
-
-#[cfg(target_os = "macos")]
-impl Drop for MacosPanelWindowActivationGuard {
-    fn drop(&mut self) {
-        let pending = MACOS_PENDING_PANEL_WINDOWS.fetch_sub(1, Ordering::AcqRel);
-        if pending == 1 {
-            schedule_macos_dock_visibility_sync(&self.app);
-        }
-    }
-}
-
-#[cfg(target_os = "macos")]
-#[link(name = "ApplicationServices", kind = "framework")]
-unsafe extern "C" {
-    fn AXIsProcessTrusted() -> bool;
-    fn AXIsProcessTrustedWithOptions(options: core_foundation::dictionary::CFDictionaryRef)
-    -> bool;
-}
-
-#[cfg(target_os = "macos")]
-fn macos_prompt_screen_recording_access() {
-    scap_screencapturekit::request_permission();
-}
-
-#[cfg(target_os = "macos")]
-fn macos_prompt_accessibility_access() {
-    use core_foundation::base::TCFType;
-    use core_foundation::dictionary::CFDictionary;
-    use core_foundation::string::CFString;
-
-    let prompt_key = CFString::new("AXTrustedCheckOptionPrompt");
-    let prompt_value = core_foundation::boolean::CFBoolean::true_value();
-
-    let options =
-        CFDictionary::from_CFType_pairs(&[(prompt_key.as_CFType(), prompt_value.as_CFType())]);
-
-    unsafe {
-        AXIsProcessTrustedWithOptions(options.as_concrete_TypeRef());
-    }
-}
-
-#[cfg(target_os = "macos")]
-fn macos_run_on_main_thread(
-    app: &tauri::AppHandle,
-    callback: impl FnOnce() -> R + Send + 'static,
-) -> Option {
-    use std::sync::mpsc;
-
-    let (tx, rx) = mpsc::sync_channel(1);
-
-    if let Err(err) = app.run_on_main_thread(move || {
-        let _ = tx.send(callback());
-    }) {
-        tracing::warn!("Failed to run permission action on main thread: {err}");
-        return None;
-    }
-
-    rx.recv_timeout(Duration::from_secs(2)).ok()
-}
-
-#[cfg(target_os = "macos")]
-fn macos_permission_settings_url(permission: &OSPermission) -> &'static str {
-    match permission {
-        OSPermission::ScreenRecording => {
-            "x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture"
-        }
-        OSPermission::Camera => {
-            "x-apple.systempreferences:com.apple.preference.security?Privacy_Camera"
-        }
-        OSPermission::Microphone => {
-            "x-apple.systempreferences:com.apple.preference.security?Privacy_Microphone"
-        }
-        OSPermission::Accessibility => {
-            "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"
-        }
-    }
-}
-
-#[cfg(target_os = "macos")]
-fn macos_permission_needs_settings_fallback(permission: &OSPermission) -> bool {
-    matches!(
-        permission,
-        OSPermission::ScreenRecording | OSPermission::Accessibility
-    )
-}
-
-#[cfg(target_os = "macos")]
-fn macos_focus_permission_window(app: &tauri::AppHandle) {
-    if let Some(window) = ["onboarding", "main", "settings"]
-        .into_iter()
-        .find_map(|label| app.get_webview_window(label))
-    {
-        let _ = window.show();
-        let _ = window.set_focus();
-    }
-}
-
-#[cfg(target_os = "macos")]
-fn macos_prepare_permission_request(app: &tauri::AppHandle, focus_app: bool) {
-    if crate::app_is_exiting(app) {
-        return;
-    }
-
-    if let Err(err) = app.set_dock_visibility(true) {
-        tracing::warn!("Failed to show dock icon for permission request: {err}");
-    }
-
-    if let Err(err) = app.set_activation_policy(tauri::ActivationPolicy::Regular) {
-        tracing::warn!("Failed to set activation policy to Regular: {err}");
-    }
-
-    if !focus_app {
-        return;
-    }
-
-    macos_focus_permission_window(app);
-
-    if let Some(current_app) = unsafe {
-        NSRunningApplication::runningApplicationWithProcessIdentifier(std::process::id() as _)
-    } {
-        unsafe {
-            current_app
-                .activateWithOptions(NSApplicationActivationOptions::ActivateIgnoringOtherApps);
-        }
-    }
-}
-
-#[cfg(target_os = "macos")]
-fn macos_sync_activation_policy(app: &tauri::AppHandle, should_show_dock: bool) {
-    let policy = if should_show_dock {
-        tauri::ActivationPolicy::Regular
-    } else {
-        tauri::ActivationPolicy::Accessory
-    };
-
-    if let Err(err) = app.set_activation_policy(policy) {
-        tracing::warn!("Failed to update activation policy: {err}");
-    }
-}
-
-// Changing the activation policy (which `set_dock_visibility` also does under
-// the hood) while any window owns a fullscreen Space makes AppKit throw an
-// NSException that aborts the process when it unwinds into Rust. Callers must
-// leave the policy alone until fullscreen exits.
-#[cfg(target_os = "macos")]
-fn macos_any_window_fullscreen(app: &tauri::AppHandle) -> bool {
-    app.webview_windows()
-        .values()
-        .any(|window| window.is_fullscreen().unwrap_or(false))
-}
-
-#[cfg(target_os = "macos")]
-pub(crate) fn prepare_macos_panel_window(
-    app: &tauri::AppHandle,
-) -> MacosPanelWindowActivationGuard {
-    let prev = MACOS_PENDING_PANEL_WINDOWS.fetch_add(1, Ordering::AcqRel);
-
-    if prev == 0 && !macos_any_window_fullscreen(app) {
-        if let Err(err) = app.set_activation_policy(tauri::ActivationPolicy::Accessory) {
-            tracing::warn!("Failed to prepare macOS panel activation policy: {err}");
-        }
-    }
-
-    MacosPanelWindowActivationGuard { app: app.clone() }
-}
-
-#[cfg(target_os = "macos")]
-pub(crate) fn sync_macos_dock_visibility(app: &tauri::AppHandle) {
-    if crate::app_is_exiting(app) || MACOS_PENDING_PANEL_WINDOWS.load(Ordering::Acquire) > 0 {
-        return;
-    }
-
-    if macos_any_window_fullscreen(app) {
-        return;
-    }
-
-    let should_hide_dock = GeneralSettingsStore::get(app)
-        .ok()
-        .flatten()
-        .is_some_and(|settings| settings.hide_dock_icon);
-
-    let has_visible_panel_window = app.webview_windows().iter().any(|(label, window)| {
-        CapWindowId::from_str(label)
-            .map(|id| !id.activates_dock() && window.is_visible().unwrap_or(false))
-            .unwrap_or(false)
-    });
-
-    if has_visible_panel_window && should_hide_dock {
-        return;
-    }
-
-    let has_visible_dock_window = app.webview_windows().iter().any(|(label, window)| {
-        CapWindowId::from_str(label)
-            .map(|window_id| window_id.activates_dock() && window.is_visible().unwrap_or(false))
-            .unwrap_or(false)
-    });
-
-    let should_show_dock = !should_hide_dock || has_visible_dock_window;
-
-    macos_sync_activation_policy(app, should_show_dock);
-
-    if let Err(err) = app.set_dock_visibility(should_show_dock) {
-        tracing::warn!("Failed to update dock visibility: {err}");
-    }
-}
-
-#[cfg(target_os = "macos")]
-pub(crate) fn schedule_macos_dock_visibility_sync(app: &tauri::AppHandle) {
-    let generation = MACOS_DOCK_VISIBILITY_SYNC_GENERATION.fetch_add(1, Ordering::AcqRel) + 1;
-    let app = app.clone();
-    tauri::async_runtime::spawn(async move {
-        tokio::time::sleep(Duration::from_millis(100)).await;
-        if MACOS_DOCK_VISIBILITY_SYNC_GENERATION.load(Ordering::Acquire) == generation {
-            sync_macos_dock_visibility(&app);
-        }
-    });
-}
-
-#[cfg(target_os = "macos")]
-fn macos_permission_status(permission: &OSPermission, initial_check: bool) -> OSPermissionStatus {
-    match permission {
-        OSPermission::ScreenRecording => {
-            let granted = macos_screen_recording_available();
-            match (granted, initial_check) {
-                (true, _) => OSPermissionStatus::Granted,
-                (false, true) => OSPermissionStatus::Empty,
-                (false, false) => OSPermissionStatus::Denied,
-            }
-        }
-        OSPermission::Camera => {
-            match av::CaptureDevice::authorization_status_for_media_type(av::MediaType::video()) {
-                Ok(av::AuthorizationStatus::NotDetermined) => OSPermissionStatus::Empty,
-                Ok(av::AuthorizationStatus::Authorized) => OSPermissionStatus::Granted,
-                Ok(_) => OSPermissionStatus::Denied,
-                Err(err) => {
-                    tracing::error!("Failed to query AV permission status: {err}");
-                    OSPermissionStatus::Denied
-                }
-            }
-        }
-        OSPermission::Microphone => {
-            match av::CaptureDevice::authorization_status_for_media_type(av::MediaType::audio()) {
-                Ok(av::AuthorizationStatus::NotDetermined) => OSPermissionStatus::Empty,
-                Ok(av::AuthorizationStatus::Authorized) => OSPermissionStatus::Granted,
-                Ok(_) => OSPermissionStatus::Denied,
-                Err(err) => {
-                    tracing::error!("Failed to query AV permission status: {err}");
-                    OSPermissionStatus::Denied
-                }
-            }
-        }
-        OSPermission::Accessibility => {
-            if unsafe { AXIsProcessTrusted() } {
-                OSPermissionStatus::Granted
-            } else if initial_check {
-                OSPermissionStatus::Empty
-            } else {
-                OSPermissionStatus::Denied
-            }
-        }
-    }
-}
-
-// The SCShareableContent snapshot behind this validation materialises every
-// window/app/display on the system (~1MB+ of ObjC objects per call). Polling
-// callers (devices snapshot emitter every 5s, permission UIs down to 250ms)
-// used to re-run it for the whole process lifetime, leaking the graph on
-// pool-less tokio threads at ~15MB/min until macOS exhausted swap (issue
-// #2023, the 82GB incident). A successful validation is cached for the rest
-// of the process: runtime revocation is caught by the cheap CGPreflight gate,
-// and macOS relaunches the app on screen-recording permission changes anyway.
-// Failed validations retry at most once per MACOS_SCK_VALIDATION_RETRY_INTERVAL.
-#[cfg(target_os = "macos")]
-fn macos_screen_recording_available() -> bool {
-    macos_screen_recording_available_with(
-        scap_screencapturekit::has_permission(),
-        MACOS_SCK_DISPLAYS_VALIDATED.load(Ordering::Acquire),
-        MACOS_SCK_LAST_STRICT_OUTCOME.load(Ordering::Acquire),
-        objc2::MainThreadMarker::new().is_some(),
-        macos_spawn_sck_displays_validation,
-        || {
-            // block_in_place covers the mutex acquisition too: waiters serialised
-            // behind an in-flight validation would otherwise park a tokio worker
-            // without telling the runtime.
-            if tokio::runtime::Handle::try_current().is_ok() {
-                tokio::task::block_in_place(macos_validate_sck_displays)
-            } else {
-                macos_validate_sck_displays()
-            }
-        },
-    )
-}
-
-// SCShareableContent's completion needs the main run loop, so blocking the
-// main thread on the strict validation deadlocks the whole app. Both
-// 2026-08-03 macOS hang reports show it: onboarding tray rebuilds
-// (run_on_main_thread → build_tray_menu → do_permissions_check) parked the
-// main thread in block_on for 76+s until force-quit. Main-thread callers are
-// the tray menu builds (tray.rs), create_tray, the setup-time log line
-// (lib.rs), and RunEvent::Reopen → should_show_onboarding (lib.rs); they get
-// the last strictly-observed answer without blocking — optimistic until the
-// first strict validation completes, since CGPreflight already passed. Reopen
-// consuming an optimistic answer is self-correcting: ShowCapWindow::Main
-// re-checks off-main (windows.rs) and redirects back to Onboarding. The
-// onboarding/permission UIs poll via async commands and keep the strict path.
-#[cfg(target_os = "macos")]
-fn macos_screen_recording_available_with(
-    preflight_granted: bool,
-    displays_validated: bool,
-    last_strict_outcome: u8,
-    on_main_thread: bool,
-    spawn_background_validation: impl FnOnce(),
-    validate: impl FnOnce() -> bool,
-) -> bool {
-    if !preflight_granted {
-        return false;
-    }
-
-    if displays_validated {
-        return true;
-    }
-
-    if on_main_thread {
-        spawn_background_validation();
-        return last_strict_outcome != MACOS_SCK_OUTCOME_FAILED;
-    }
-
-    validate()
-}
-
-#[cfg(target_os = "macos")]
-struct MacosSckValidationInFlightReset;
-
-#[cfg(target_os = "macos")]
-impl Drop for MacosSckValidationInFlightReset {
-    fn drop(&mut self) {
-        MACOS_SCK_DISPLAYS_VALIDATION_IN_FLIGHT.store(false, Ordering::Release);
-    }
-}
-
-// Blocking pool rather than a raw std::thread: pool threads carry the runtime
-// handle without tokio's "entered" flag, so the validator's nested
-// Handle::block_on is legal there (it panics on entered threads, which rules
-// out tokio::spawn), they inherit the 16MiB stack configured in main.rs
-// (SCK graph walks are why it was raised), and an idle pool thread is reused
-// instead of spawning one per check. The Drop guard clears the in-flight
-// latch even if the validation panics.
-#[cfg(target_os = "macos")]
-fn macos_spawn_sck_displays_validation() {
-    if MACOS_SCK_DISPLAYS_VALIDATION_IN_FLIGHT.swap(true, Ordering::AcqRel) {
-        return;
-    }
-    tauri::async_runtime::spawn_blocking(|| {
-        let _reset = MacosSckValidationInFlightReset;
-        macos_validate_sck_displays();
-    });
-}
-
-#[cfg(target_os = "macos")]
-fn macos_validate_sck_displays() -> bool {
-    // Serialise validators: concurrent callers during the first startup check
-    // must wait for the in-flight validation rather than tripping the backoff
-    // and transiently reporting a granted permission as denied.
-    let mut last_attempt = MACOS_SCK_LAST_VALIDATION_ATTEMPT
-        .lock()
-        .unwrap_or_else(std::sync::PoisonError::into_inner);
-    if MACOS_SCK_DISPLAYS_VALIDATED.load(Ordering::Acquire) {
-        return true;
-    }
-    if let Some(attempted_at) = *last_attempt
-        && attempted_at.elapsed() < MACOS_SCK_VALIDATION_RETRY_INTERVAL
-    {
-        return false;
-    }
-    *last_attempt = Some(std::time::Instant::now());
-
-    let validated = objc2::rc::autoreleasepool(|_| {
-        tauri::async_runtime::block_on(async {
-            // Bounded: a wedged replayd (post-sleep, or right after a TCC
-            // grant before relaunch) can leave this future unresolved forever,
-            // which would park whichever thread is validating.
-            let content = match tokio::time::timeout(
-                MACOS_SCK_VALIDATION_TIMEOUT,
-                sc::ShareableContent::current(),
-            )
-            .await
-            {
-                Ok(result) => result,
-                Err(_) => {
-                    tracing::warn!(
-                        timeout_ms = MACOS_SCK_VALIDATION_TIMEOUT.as_millis() as u64,
-                        "ScreenCaptureKit shareable content query timed out during permission check"
-                    );
-                    return false;
-                }
-            };
-            match content {
-                Ok(content) => {
-                    let display_count = content.displays().len();
-                    if display_count == 0
-                        && !MACOS_SCK_PERMISSION_MISMATCH_LOGGED.swap(true, Ordering::AcqRel)
-                    {
-                        tracing::debug!(
-                            window_count = content.windows().len(),
-                            application_count = content.apps().len(),
-                            "ScreenCaptureKit returned no displays despite CoreGraphics screen-recording permission"
-                        );
-                    }
-                    display_count > 0
-                }
-                Err(error) => {
-                    tracing::debug!(
-                        error = %error,
-                        "ScreenCaptureKit shareable content unavailable during permission check"
-                    );
-                    false
-                }
-            }
-        })
-    });
-
-    if validated {
-        MACOS_SCK_DISPLAYS_VALIDATED.store(true, Ordering::Release);
-    }
-    MACOS_SCK_LAST_STRICT_OUTCOME.store(
-        if validated {
-            MACOS_SCK_OUTCOME_OK
-        } else {
-            MACOS_SCK_OUTCOME_FAILED
-        },
-        Ordering::Release,
-    );
-    // Re-stamp on completion: an attempt can consume up to the SCK timeout,
-    // so a start-only stamp would leave a timed-out attempt with an already
-    // expired backoff window (back-to-back attempts against a wedged
-    // replayd). The start stamp above stays as insurance in case this thread
-    // dies mid-attempt.
-    *last_attempt = Some(std::time::Instant::now());
-    validated
-}
-
-#[cfg(target_os = "macos")]
-fn macos_request_permission(app: &tauri::AppHandle, permission: &OSPermission) {
-    match permission {
-        OSPermission::ScreenRecording => {
-            if macos_run_on_main_thread(app, macos_prompt_screen_recording_access).is_none() {
-                macos_prompt_screen_recording_access();
-            }
-        }
-        OSPermission::Camera => {
-            futures::executor::block_on(av::CaptureDevice::request_access_for_media_type(
-                av::MediaType::video(),
-            ))
-            .ok();
-        }
-        OSPermission::Microphone => {
-            futures::executor::block_on(av::CaptureDevice::request_access_for_media_type(
-                av::MediaType::audio(),
-            ))
-            .ok();
-        }
-        OSPermission::Accessibility => {
-            if macos_run_on_main_thread(app, macos_prompt_accessibility_access).is_none() {
-                macos_prompt_accessibility_access();
-            }
-        }
-    }
-}
-
-#[cfg(target_os = "macos")]
-async fn macos_wait_for_permission_update_with(
-    mut check: TCheck,
-    mut sleep: impl FnMut() -> TSleep,
-) -> bool
-where
-    TCheck: FnMut() -> bool,
-    TSleep: Future,
-{
-    if check() {
-        return true;
-    }
-
-    for _ in 0..10 {
-        sleep().await;
-        if check() {
-            return true;
-        }
-    }
-
-    false
-}
-
-#[cfg(target_os = "macos")]
-async fn macos_wait_for_permission_update(permission: &OSPermission) -> bool {
-    // The user just interacted with the permission prompt; drop the SCK
-    // validation backoff so this poll loop sees fresh answers instead of a
-    // stale negative from up to 5s ago. block_in_place because an in-flight
-    // validation holds this mutex for up to the SCK timeout, and waiting it
-    // out is deliberate — its result predates the grant, so the reset must
-    // land after it finishes.
-    if matches!(permission, OSPermission::ScreenRecording) {
-        tokio::task::block_in_place(|| {
-            *MACOS_SCK_LAST_VALIDATION_ATTEMPT
-                .lock()
-                .unwrap_or_else(std::sync::PoisonError::into_inner) = None;
-        });
-    }
-
-    macos_wait_for_permission_update_with(
-        || macos_permission_status(permission, false).permitted(),
-        || tokio::time::sleep(Duration::from_millis(200)),
-    )
-    .await
-}
-
-#[cfg(target_os = "macos")]
-fn macos_open_permission_settings(app: &tauri::AppHandle, permission: &OSPermission) {
-    use std::process::Command;
-
-    let process = Command::new("open")
-        .arg(macos_permission_settings_url(permission))
-        .spawn();
-
-    match process {
-        Ok(mut process) => {
-            let app = app.clone();
-            tokio::spawn(async move {
-                match tokio::task::spawn_blocking(move || process.wait()).await {
-                    Ok(Err(err)) => {
-                        tracing::error!("Error waiting for permission settings process: {err}");
-                    }
-                    Err(err) => {
-                        tracing::error!("Join error waiting for permission settings: {err}");
-                    }
-                    _ => {}
-                }
-                crate::tray::refresh_tray_menu_for_app(&app);
-                sync_macos_dock_visibility(&app);
-            });
-        }
-        Err(err) => {
-            tracing::error!("Failed to open permission settings: {err}");
-            sync_macos_dock_visibility(app);
-        }
-    }
-}
-
-#[derive(Debug, Serialize, Deserialize, specta::Type, Clone, Copy, PartialEq, Eq)]
-#[serde(rename_all = "camelCase")]
-pub enum OSPermission {
-    ScreenRecording,
-    Camera,
-    Microphone,
-    Accessibility,
-}
-
-#[tauri::command(async)]
-#[specta::specta]
-pub fn open_permission_settings(_app: tauri::AppHandle, _permission: OSPermission) {
-    #[cfg(target_os = "macos")]
-    {
-        macos_prepare_permission_request(&_app, false);
-        macos_open_permission_settings(&_app, &_permission);
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(_app))]
-pub async fn request_permission(_app: tauri::AppHandle, _permission: OSPermission) {
-    #[cfg(target_os = "macos")]
-    {
-        macos_prepare_permission_request(&_app, true);
-
-        let permission = _permission;
-        let app = _app.clone();
-        tauri::async_runtime::spawn_blocking(move || {
-            macos_request_permission(&app, &permission);
-        })
-        .await
-        .ok();
-
-        let granted = macos_wait_for_permission_update(&_permission).await;
-
-        if macos_permission_needs_settings_fallback(&_permission) && !granted {
-            macos_open_permission_settings(&_app, &_permission);
-        } else {
-            sync_macos_dock_visibility(&_app);
-        }
-    }
-
-    crate::tray::refresh_tray_menu_for_app(&_app);
-}
-
-pub(crate) fn check_camera_access() -> Result<(), String> {
-    #[cfg(target_os = "macos")]
-    let status =
-        objc2::rc::autoreleasepool(|_| macos_permission_status(&OSPermission::Camera, false));
-    #[cfg(not(target_os = "macos"))]
-    let status = OSPermissionStatus::NotNeeded;
-    camera_access_result(status)
-}
-
-fn camera_access_result(status: OSPermissionStatus) -> Result<(), String> {
-    match status {
-        OSPermissionStatus::Granted | OSPermissionStatus::NotNeeded => Ok(()),
-        OSPermissionStatus::Empty => Err(
-            "Camera access is required. Click the camera control to allow access, then select your camera again."
-                .into(),
-        ),
-        OSPermissionStatus::Denied => Err(
-            "Camera access is blocked. Allow Cap in System Settings > Privacy & Security > Camera, then select your camera again. If access is restricted, contact your administrator."
-                .into(),
-        ),
-    }
-}
-
-pub(crate) fn check_microphone_access() -> Result<(), String> {
-    #[cfg(target_os = "macos")]
-    let status =
-        objc2::rc::autoreleasepool(|_| macos_permission_status(&OSPermission::Microphone, false));
-    #[cfg(not(target_os = "macos"))]
-    let status = OSPermissionStatus::NotNeeded;
-    microphone_access_result(status)
-}
-
-fn microphone_access_result(status: OSPermissionStatus) -> Result<(), String> {
-    match status {
-        OSPermissionStatus::Granted | OSPermissionStatus::NotNeeded => Ok(()),
-        OSPermissionStatus::Empty => Err(
-            "Microphone access is required. Click the microphone control to allow access, then select your microphone again."
-                .into(),
-        ),
-        OSPermissionStatus::Denied => Err(
-            "Microphone access is blocked. Allow Cap in System Settings > Privacy & Security > Microphone, then select your microphone again."
-                .into(),
-        ),
-    }
-}
-
-#[derive(Serialize, Deserialize, Debug, specta::Type, Clone)]
-#[serde(rename_all = "camelCase")]
-pub enum OSPermissionStatus {
-    // This platform does not require this permission
-    NotNeeded,
-    // The user has neither granted nor denied permission
-    Empty,
-    // The user has explicitly granted permission
-    Granted,
-    // The user has denied permission, or has granted it but not yet restarted
-    Denied,
-}
-
-impl OSPermissionStatus {
-    pub fn permitted(&self) -> bool {
-        matches!(self, Self::NotNeeded | Self::Granted)
-    }
-}
-
-#[derive(Serialize, Deserialize, Debug, specta::Type, Clone)]
-#[serde(rename_all = "camelCase")]
-pub struct OSPermissionsCheck {
-    pub screen_recording: OSPermissionStatus,
-    pub microphone: OSPermissionStatus,
-    pub camera: OSPermissionStatus,
-    pub accessibility: OSPermissionStatus,
-}
-
-impl OSPermissionsCheck {
-    pub fn necessary_granted(&self) -> bool {
-        self.screen_recording.permitted() && self.accessibility.permitted()
-    }
-}
-
-#[tauri::command(async)]
-#[specta::specta]
-pub fn do_permissions_check(_initial_check: bool) -> OSPermissionsCheck {
-    // Pool-wrapped because this runs on tokio/tauri worker threads (which have
-    // no ambient NSAutoreleasePool) from polling callers; without it every
-    // autoreleased AVFoundation/AppKit temporary leaks for the process lifetime.
-    #[cfg(target_os = "macos")]
-    {
-        objc2::rc::autoreleasepool(|_| OSPermissionsCheck {
-            screen_recording: macos_permission_status(
-                &OSPermission::ScreenRecording,
-                _initial_check,
-            ),
-            microphone: macos_permission_status(&OSPermission::Microphone, _initial_check),
-            camera: macos_permission_status(&OSPermission::Camera, _initial_check),
-            accessibility: macos_permission_status(&OSPermission::Accessibility, _initial_check),
-        })
-    }
-
-    #[cfg(not(target_os = "macos"))]
-    {
-        OSPermissionsCheck {
-            screen_recording: OSPermissionStatus::NotNeeded,
-            microphone: OSPermissionStatus::NotNeeded,
-            camera: OSPermissionStatus::NotNeeded,
-            accessibility: OSPermissionStatus::NotNeeded,
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn camera_setup_requires_granted_access() {
-        for status in [OSPermissionStatus::Granted, OSPermissionStatus::NotNeeded] {
-            assert!(camera_access_result(status).is_ok());
-        }
-        assert!(
-            camera_access_result(OSPermissionStatus::Empty)
-                .unwrap_err()
-                .contains("camera control")
-        );
-        let blocked = camera_access_result(OSPermissionStatus::Denied).unwrap_err();
-        assert!(blocked.contains("System Settings > Privacy & Security > Camera"));
-        assert!(blocked.contains("restricted"));
-    }
-
-    #[test]
-    fn microphone_setup_requires_granted_access() {
-        for status in [OSPermissionStatus::Granted, OSPermissionStatus::NotNeeded] {
-            assert!(microphone_access_result(status).is_ok());
-        }
-        assert!(
-            microphone_access_result(OSPermissionStatus::Empty)
-                .unwrap_err()
-                .contains("microphone control")
-        );
-        assert!(
-            microphone_access_result(OSPermissionStatus::Denied)
-                .unwrap_err()
-                .contains("System Settings > Privacy & Security > Microphone")
-        );
-    }
-
-    #[test]
-    fn permission_status_permitted_matches_granted_states() {
-        assert!(OSPermissionStatus::Granted.permitted());
-        assert!(OSPermissionStatus::NotNeeded.permitted());
-        assert!(!OSPermissionStatus::Empty.permitted());
-        assert!(!OSPermissionStatus::Denied.permitted());
-    }
-
-    #[cfg(target_os = "macos")]
-    #[test]
-    fn permission_settings_urls_match_expected_privacy_pages() {
-        assert_eq!(
-            macos_permission_settings_url(&OSPermission::ScreenRecording),
-            "x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture"
-        );
-        assert_eq!(
-            macos_permission_settings_url(&OSPermission::Accessibility),
-            "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"
-        );
-        assert_eq!(
-            macos_permission_settings_url(&OSPermission::Camera),
-            "x-apple.systempreferences:com.apple.preference.security?Privacy_Camera"
-        );
-        assert_eq!(
-            macos_permission_settings_url(&OSPermission::Microphone),
-            "x-apple.systempreferences:com.apple.preference.security?Privacy_Microphone"
-        );
-    }
-
-    #[cfg(target_os = "macos")]
-    #[tokio::test]
-    async fn permission_update_wait_returns_true_once_permission_is_observed() {
-        let mut checks = [false, false, true, true].into_iter();
-
-        let granted =
-            macos_wait_for_permission_update_with(|| checks.next().unwrap_or(true), || async {})
-                .await;
-
-        assert!(granted);
-    }
-
-    #[cfg(target_os = "macos")]
-    #[tokio::test]
-    async fn permission_update_wait_returns_false_when_permission_never_changes() {
-        let mut checks = [false, false, false].into_iter();
-
-        let granted =
-            macos_wait_for_permission_update_with(|| checks.next().unwrap_or(false), || async {})
-                .await;
-
-        assert!(!granted);
-    }
-
-    #[cfg(target_os = "macos")]
-    #[test]
-    fn main_thread_never_validates_inline() {
-        use std::cell::Cell;
-
-        let spawned = Cell::new(false);
-        let validated_inline = Cell::new(false);
-
-        let result = macos_screen_recording_available_with(
-            true,
-            false,
-            MACOS_SCK_OUTCOME_UNKNOWN,
-            true,
-            || spawned.set(true),
-            || {
-                validated_inline.set(true);
-                true
-            },
-        );
-
-        assert!(result, "optimistic before the first strict validation");
-        assert!(spawned.get(), "must kick a background validation");
-        assert!(
-            !validated_inline.get(),
-            "the main thread must never run the blocking SCK validation"
-        );
-    }
-
-    #[cfg(target_os = "macos")]
-    #[test]
-    fn main_thread_reports_last_failed_strict_outcome() {
-        use std::cell::Cell;
-
-        let spawned = Cell::new(false);
-
-        let result = macos_screen_recording_available_with(
-            true,
-            false,
-            MACOS_SCK_OUTCOME_FAILED,
-            true,
-            || spawned.set(true),
-            || unreachable!("main thread must not validate inline"),
-        );
-
-        assert!(!result, "a strictly-observed failure must not be masked");
-        assert!(spawned.get(), "still revalidates in the background");
-    }
-
-    #[cfg(target_os = "macos")]
-    #[test]
-    fn off_main_thread_keeps_the_strict_path() {
-        use std::cell::Cell;
-
-        let spawned = Cell::new(false);
-        let validated_inline = Cell::new(false);
-
-        let result = macos_screen_recording_available_with(
-            true,
-            false,
-            MACOS_SCK_OUTCOME_UNKNOWN,
-            false,
-            || spawned.set(true),
-            || {
-                validated_inline.set(true);
-                false
-            },
-        );
-
-        assert!(!result);
-        assert!(validated_inline.get(), "off-main callers validate inline");
-        assert!(!spawned.get());
-    }
-
-    #[cfg(target_os = "macos")]
-    #[test]
-    fn preflight_denial_and_cached_validation_short_circuit() {
-        let denied = macos_screen_recording_available_with(
-            false,
-            false,
-            MACOS_SCK_OUTCOME_UNKNOWN,
-            true,
-            || unreachable!("no work when preflight is denied"),
-            || unreachable!("no work when preflight is denied"),
-        );
-        assert!(!denied);
-
-        let cached = macos_screen_recording_available_with(
-            true,
-            true,
-            MACOS_SCK_OUTCOME_UNKNOWN,
-            true,
-            || unreachable!("no work once displays are validated"),
-            || unreachable!("no work once displays are validated"),
-        );
-        assert!(cached);
-    }
-
-    #[cfg(target_os = "macos")]
-    #[test]
-    fn sck_timeout_fits_inside_the_retry_backoff() {
-        assert!(MACOS_SCK_VALIDATION_TIMEOUT < MACOS_SCK_VALIDATION_RETRY_INTERVAL);
-    }
-
-    #[cfg(target_os = "macos")]
-    #[test]
-    fn in_flight_latch_clears_even_when_validation_panics() {
-        MACOS_SCK_DISPLAYS_VALIDATION_IN_FLIGHT.store(true, Ordering::Release);
-
-        let panicked = std::panic::catch_unwind(|| {
-            let _reset = MacosSckValidationInFlightReset;
-            panic!("validation blew up");
-        });
-
-        assert!(panicked.is_err());
-        assert!(!MACOS_SCK_DISPLAYS_VALIDATION_IN_FLIGHT.load(Ordering::Acquire));
-    }
-
-    #[cfg(target_os = "macos")]
-    #[test]
-    fn settings_fallback_only_applies_to_screen_and_accessibility() {
-        assert!(macos_permission_needs_settings_fallback(
-            &OSPermission::ScreenRecording
-        ));
-        assert!(macos_permission_needs_settings_fallback(
-            &OSPermission::Accessibility
-        ));
-        assert!(!macos_permission_needs_settings_fallback(
-            &OSPermission::Camera
-        ));
-        assert!(!macos_permission_needs_settings_fallback(
-            &OSPermission::Microphone
-        ));
-    }
-}
diff --git a/apps/desktop/src-tauri/src/picker-benchmark.js b/apps/desktop/src-tauri/src/picker-benchmark.js
deleted file mode 100644
index d675f323c95..00000000000
--- a/apps/desktop/src-tauri/src/picker-benchmark.js
+++ /dev/null
@@ -1,28 +0,0 @@
-(() => {
-	let armed = true;
-	let frames = 0;
-	const invoke = window.__TAURI_INTERNALS__.invoke;
-	globalThis.__capArmPickerBenchmark = () => {
-		armed = true;
-		frames = 0;
-	};
-	const tick = () => {
-		const button = Array.from(
-			document.querySelectorAll('[data-disabled="false"]'),
-		).find((element) => element.textContent.includes("Start Recording"));
-		if (armed && button?.getBoundingClientRect().width > 0) {
-			frames += 1;
-			if (frames === 2) {
-				armed = false;
-				void invoke("plugin:event|emit", {
-					event: "cap-picker-benchmark-ready",
-					payload: { navigationMs: performance.now() },
-				});
-			}
-		} else {
-			frames = 0;
-		}
-		requestAnimationFrame(tick);
-	};
-	requestAnimationFrame(tick);
-})();
diff --git a/apps/desktop/src-tauri/src/picker_benchmark.rs b/apps/desktop/src-tauri/src/picker_benchmark.rs
deleted file mode 100644
index bd2abbf6470..00000000000
--- a/apps/desktop/src-tauri/src/picker_benchmark.rs
+++ /dev/null
@@ -1,189 +0,0 @@
-use std::time::{Duration, Instant};
-
-use tauri::{Listener, Manager};
-use tauri_specta::Event;
-
-use crate::{
-    RequestSetTargetMode, recording_settings::RecordingTargetMode,
-    target_select_overlay::WindowFocusManager,
-};
-
-pub const SCRIPT: &str = include_str!("picker-benchmark.js");
-
-pub fn enabled() -> bool {
-    std::env::var_os("CAP_PICKER_BENCHMARK_OUTPUT").is_some()
-}
-
-pub fn run(app: tauri::AppHandle) {
-    let Some(output) = std::env::var_os("CAP_PICKER_BENCHMARK_OUTPUT") else {
-        return;
-    };
-    tokio::spawn(async move {
-        let delay = std::env::var("CAP_PICKER_BENCHMARK_DELAY_MS")
-            .ok()
-            .and_then(|delay| delay.parse().ok())
-            .unwrap_or(2000);
-        tokio::time::sleep(Duration::from_millis(delay)).await;
-        let (sender, mut receiver) = tokio::sync::mpsc::unbounded_channel();
-        let listener = app.listen_any("cap-picker-benchmark-ready", move |event| {
-            let _ = sender.send(event.payload().to_owned());
-        });
-        // Six alternating Display/Window cycles by default; the overlay
-        // soak (see CAP-CHANGES in vendor/tauri-nspanel) runs hundreds.
-        let sample_count = std::env::var("CAP_PICKER_BENCHMARK_SAMPLES")
-            .ok()
-            .and_then(|count| count.parse::().ok())
-            .filter(|count| *count > 0)
-            .unwrap_or(6);
-        let mut samples = Vec::new();
-        for sample in 0..sample_count {
-            let mode = if sample % 2 == 0 {
-                RecordingTargetMode::Display
-            } else {
-                RecordingTargetMode::Window
-            };
-            for (label, window) in app.webview_windows() {
-                if label.starts_with("target-select-overlay") {
-                    let _ = window.eval("globalThis.__capArmPickerBenchmark?.()");
-                }
-            }
-            let started = Instant::now();
-            let _ = RequestSetTargetMode {
-                target_mode: Some(mode),
-                display_id: None,
-            }
-            .emit(&app);
-            let result = tokio::time::timeout(Duration::from_secs(20), receiver.recv()).await;
-            samples.push(serde_json::json!({
-                "sample": sample,
-                "mode": mode,
-                "elapsedMs": started.elapsed().as_secs_f64() * 1000.0,
-                "ready": matches!(result, Ok(Some(_))),
-                "frontend": result.ok().flatten().and_then(|payload| serde_json::from_str::(&payload).ok()),
-            }));
-            let _ = RequestSetTargetMode {
-                target_mode: None,
-                display_id: None,
-            }
-            .emit(&app);
-            tokio::time::sleep(Duration::from_millis(300)).await;
-        }
-        if let Err(error) = std::fs::write(&output, serde_json::json!(samples).to_string()) {
-            tracing::error!(%error, "Could not write picker benchmark results");
-        }
-
-        // Optional Escape phase: open the Display picker and confirm it is
-        // dismissed through the Escape path. `CAP_PICKER_BENCHMARK_ESCAPE=direct`
-        // calls the same dismissal the global-shortcut handler runs;
-        // `CAP_PICKER_BENCHMARK_ESCAPE=wait:` instead holds the picker open
-        // for that long while an external driver sends a real Escape keypress,
-        // and records whether the picker session ended on its own.
-        if let Ok(mode) = std::env::var("CAP_PICKER_BENCHMARK_ESCAPE") {
-            let hold_ms = mode
-                .strip_prefix("wait:")
-                .and_then(|value| value.parse::().ok());
-            let mut escape_samples = Vec::new();
-            for cycle in 0..3 {
-                for (label, window) in app.webview_windows() {
-                    if label.starts_with("target-select-overlay") {
-                        let _ = window.eval("globalThis.__capArmPickerBenchmark?.()");
-                    }
-                }
-                let _ = RequestSetTargetMode {
-                    target_mode: Some(RecordingTargetMode::Display),
-                    display_id: None,
-                }
-                .emit(&app);
-                let ready = tokio::time::timeout(Duration::from_secs(20), receiver.recv())
-                    .await
-                    .is_ok();
-                let started = Instant::now();
-                let picker_open = || app.state::().picker_session().is_some();
-                let dismissed = if let Some(hold_ms) = hold_ms {
-                    // Tell the external driver the picker is up so it sends
-                    // exactly one Escape per cycle.
-                    let marker = std::path::PathBuf::from(&output).with_extension("escape.ready");
-                    let _ = std::fs::write(&marker, b"ready");
-                    let deadline = Instant::now() + Duration::from_millis(hold_ms);
-                    let mut dismissed = false;
-                    while Instant::now() < deadline {
-                        if !picker_open() {
-                            dismissed = true;
-                            break;
-                        }
-                        tokio::time::sleep(Duration::from_millis(50)).await;
-                    }
-                    let _ = std::fs::remove_file(&marker);
-                    dismissed
-                } else {
-                    tokio::time::sleep(Duration::from_millis(400)).await;
-                    crate::target_select_overlay::dismiss_picker_from_escape(&app);
-                    tokio::time::sleep(Duration::from_millis(200)).await;
-                    !picker_open()
-                };
-                escape_samples.push(serde_json::json!({
-                    "cycle": cycle,
-                    "ready": ready,
-                    "dismissed": dismissed,
-                    "dismissMs": started.elapsed().as_secs_f64() * 1000.0,
-                }));
-                if !dismissed {
-                    let _ = RequestSetTargetMode {
-                        target_mode: None,
-                        display_id: None,
-                    }
-                    .emit(&app);
-                }
-                tokio::time::sleep(Duration::from_millis(600)).await;
-            }
-            let escape_output = std::path::PathBuf::from(&output).with_extension("escape.json");
-            if let Err(error) =
-                std::fs::write(escape_output, serde_json::json!(escape_samples).to_string())
-            {
-                tracing::error!(%error, "Could not write escape benchmark results");
-            }
-        }
-        app.unlisten(listener);
-
-        // Optional second phase: close and reopen the camera window, which is
-        // destroyed and recreated under the same label. This exercises the
-        // NSPanel store's stale-entry replacement and its Destroyed cleanup
-        // (the paths that free a converted window for real), so an ownership
-        // bug in the vendored tauri-nspanel surfaces here instead of in a
-        // user's recording session. Results land next to the picker output.
-        let camera_cycles = std::env::var("CAP_PICKER_BENCHMARK_CAMERA_CYCLES")
-            .ok()
-            .and_then(|count| count.parse::().ok())
-            .unwrap_or(0);
-        if camera_cycles > 0 {
-            let mut camera_samples = Vec::new();
-            for cycle in 0..camera_cycles {
-                let started = Instant::now();
-                let removed = crate::windows::cleanup_camera_window(&app, None, true, true).await;
-                let close_ms = started.elapsed().as_secs_f64() * 1000.0;
-                tokio::time::sleep(Duration::from_millis(400)).await;
-                let started = Instant::now();
-                let shown = (crate::windows::ShowCapWindow::Camera { centered: true })
-                    .show(&app)
-                    .await
-                    .is_ok();
-                camera_samples.push(serde_json::json!({
-                    "cycle": cycle,
-                    "removed": removed,
-                    "closeMs": close_ms,
-                    "shown": shown,
-                    "showMs": started.elapsed().as_secs_f64() * 1000.0,
-                }));
-                tokio::time::sleep(Duration::from_millis(900)).await;
-            }
-            let camera_output = std::path::PathBuf::from(&output).with_extension("camera.json");
-            if let Err(error) =
-                std::fs::write(camera_output, serde_json::json!(camera_samples).to_string())
-            {
-                tracing::error!(%error, "Could not write camera benchmark results");
-            }
-        }
-        tracing::info!("Picker benchmark complete; requesting app exit");
-        app.exit(0);
-    });
-}
diff --git a/apps/desktop/src-tauri/src/platform/macos/delegates.rs b/apps/desktop/src-tauri/src/platform/macos/delegates.rs
deleted file mode 100644
index bf0bfa1b7a2..00000000000
--- a/apps/desktop/src-tauri/src/platform/macos/delegates.rs
+++ /dev/null
@@ -1,509 +0,0 @@
-// TODO(Ilya): Re-write all macos code to use `objc2` crates n
-///
-/// Credit to @haasal, @charrondev, Hoppscotch app, Electron, Zed Editor
-///
-/// https://github.com/haasal
-/// https://gist.github.com/charrondev
-/// https://github.com/hoppscotch/hoppscotch
-/// https://github.com/clearlysid/tauri-plugin-decorum/
-/// (Issue) https://github.com/tauri-apps/tauri/issues/4789
-/// (Gist) https://gist.github.com/charrondev/43150e940bd2771b1ea88256d491c7a9
-/// (Hoppscotch) https://github.com/hoppscotch/hoppscotch/blob/286fcd2bb08a84f027b10308d1e18da368f95ebf/packages/hoppscotch-selfhost-desktop/src-tauri/src/mac/window.rs
-/// (Electron) https://github.com/electron/electron/blob/38512efd25a159ddc64a54c22ef9eb6dd60064ec/shell/browser/native_window_mac.mm#L1454
-///
-use objc::{class, msg_send, sel, sel_impl};
-use tauri::{Emitter, LogicalPosition, Runtime, Window};
-
-pub struct UnsafeWindowHandle(pub *mut std::ffi::c_void);
-unsafe impl Send for UnsafeWindowHandle {}
-unsafe impl Sync for UnsafeWindowHandle {}
-
-#[derive(Debug)]
-struct WindowState {
-    window: Window,
-    controls_inset: LogicalPosition,
-}
-
-// TODO: Respect RTL display language
-// TODO: Update Height, consider supporting the scenario where the buttons are hidden by the system due to screen sharing of the window
-// https://developer.apple.com/documentation/appkit/nsapplication/1428556-userinterfacelayoutdirection?language=objc
-pub fn position_window_controls(
-    ns_window_handle: UnsafeWindowHandle,
-    inset: &LogicalPosition,
-) {
-    use cocoa::{
-        appkit::{NSView, NSWindow, NSWindowButton, NSWindowStyleMask},
-        base::id,
-        foundation::NSRect,
-    };
-
-    let ns_window = ns_window_handle.0 as id;
-    unsafe {
-        // In native fullscreen the standard window buttons are hosted in a
-        // system-managed titlebar overlay; resizing their superviews there
-        // makes AppKit throw an NSException, which aborts the process once it
-        // unwinds into Rust. The system positions them itself in fullscreen.
-        if ns_window
-            .styleMask()
-            .contains(NSWindowStyleMask::NSFullScreenWindowMask)
-        {
-            return;
-        }
-
-        let close = ns_window.standardWindowButton_(NSWindowButton::NSWindowCloseButton);
-        let minimize = ns_window.standardWindowButton_(NSWindowButton::NSWindowMiniaturizeButton);
-        let zoom = ns_window.standardWindowButton_(NSWindowButton::NSWindowZoomButton);
-        if close.is_null() || minimize.is_null() || zoom.is_null() {
-            return;
-        }
-
-        let title_bar_container_view = close.superview().superview();
-        if title_bar_container_view.is_null() {
-            return;
-        }
-
-        let close_rect: NSRect = msg_send![close, frame];
-        let button_height = close_rect.size.height;
-
-        let title_bar_frame_height = button_height + inset.y;
-        let mut title_bar_rect = NSView::frame(title_bar_container_view);
-        title_bar_rect.size.height = title_bar_frame_height;
-        title_bar_rect.origin.y = NSView::frame(ns_window).size.height - title_bar_frame_height;
-        let _: () = msg_send![title_bar_container_view, setFrame: title_bar_rect];
-
-        let window_buttons = vec![close, minimize, zoom];
-        let space_between = NSView::frame(minimize).origin.x - NSView::frame(close).origin.x;
-        let vertical_offset = 4.0; // Adjust this value to push buttons down
-
-        for (i, button) in window_buttons.into_iter().enumerate() {
-            let mut rect: NSRect = NSView::frame(button);
-            rect.origin.x = inset.x + (i as f64 * space_between);
-            rect.origin.y = ((title_bar_frame_height - button_height) / 2.0) - vertical_offset;
-            button.setFrameOrigin(rect.origin);
-        }
-    }
-}
-
-pub fn setup(window: Window, controls_inset: LogicalPosition) {
-    use cocoa::appkit::NSWindow;
-    use cocoa::base::{BOOL, id};
-    use cocoa::foundation::NSUInteger;
-    use objc::declare::ClassDecl;
-    use objc::runtime::{Class, Object, Sel};
-    use std::ffi::c_void;
-
-    let Ok(ns_win) = window.ns_window() else {
-        tracing::warn!("Failed to get window handle for delegate setup");
-        return;
-    };
-
-    // Do the initial positioning
-    position_window_controls(UnsafeWindowHandle(ns_win), &controls_inset);
-
-    // Ensure they stay in place while resizing the window.
-    fn with_window_state) -> T, T>(
-        this: &Object,
-        func: F,
-    ) {
-        let x: *mut c_void = unsafe { *this.get_ivar("app_box") };
-        // `app_box` is nulled out in `windowWillClose:`; ignore any late
-        // callbacks that arrive after that instead of dereferencing null.
-        if x.is_null() {
-            return;
-        }
-        let ptr = unsafe { &mut *(x as *mut WindowState) };
-        func(ptr);
-    }
-
-    fn suppress_delegate_panic(selector: &'static str, fallback: T, operation: F) -> T
-    where
-        F: FnOnce() -> T,
-    {
-        match std::panic::catch_unwind(std::panic::AssertUnwindSafe(operation)) {
-            Ok(value) => value,
-            Err(_) => {
-                tracing::error!(selector, "Suppressed panic in macOS window delegate");
-                fallback
-            }
-        }
-    }
-
-    unsafe {
-        let ns_win_id = ns_win as id;
-        let current_delegate: id = ns_win_id.delegate();
-
-        extern "C" fn on_window_should_close(this: &Object, _cmd: Sel, sender: id) -> BOOL {
-            suppress_delegate_panic("windowShouldClose:", cocoa::base::NO, || unsafe {
-                let super_del: id = *this.get_ivar("super_delegate");
-                msg_send![super_del, windowShouldClose: sender]
-            })
-        }
-        extern "C" fn on_window_will_close(this: &Object, _cmd: Sel, notification: id) {
-            let window = unsafe { objc::rc::StrongPtr::retain(*this.get_ivar("window")) };
-            let super_del: id = unsafe { *this.get_ivar("super_delegate") };
-
-            // Forward to the previous delegate first, but don't let a panic there
-            // skip the cleanup below (which would bring back the leak).
-            suppress_delegate_panic("windowWillClose:", (), || unsafe {
-                let _: () = msg_send![super_del, windowWillClose: notification];
-            });
-
-            suppress_delegate_panic("windowWillClose:cleanup", (), || unsafe {
-                // Tao clears the delegate before Destroyed; preserve that even if forwarding panics.
-                let _: () = msg_send![*window, setDelegate: cocoa::base::nil];
-
-                // Drop the boxed `WindowState` (and the `Window` handle it holds)
-                // that was leaked via `Box::into_raw` when this delegate was created.
-                let app_box: *mut c_void = *this.get_ivar("app_box");
-                if !app_box.is_null() {
-                    let this_mut = this as *const Object as *mut Object;
-                    (*this_mut).set_ivar("app_box", std::ptr::null_mut::());
-                    drop(Box::from_raw(app_box as *mut WindowState));
-                }
-
-                // NSWindow does not retain its delegate, so the reference taken when
-                // this delegate was created (`new`) is the only owning one. Release
-                // it now that the window is closing.
-                let this_id = this as *const Object as id;
-                let _: () = msg_send![this_id, release];
-            });
-        }
-        extern "C" fn on_window_did_resize(this: &Object, _cmd: Sel, notification: id) {
-            suppress_delegate_panic("windowDidResize:", (), || unsafe {
-                with_window_state(this, |state: &mut WindowState| {
-                    if let Ok(window_handle) = state.window.ns_window() {
-                        position_window_controls(
-                            UnsafeWindowHandle(window_handle),
-                            &state.controls_inset,
-                        );
-                    } else {
-                        tracing::warn!("Failed to get handle to NSWindow during resize");
-                    }
-                });
-
-                let super_del: id = *this.get_ivar("super_delegate");
-                let _: () = msg_send![super_del, windowDidResize: notification];
-            });
-        }
-        extern "C" fn on_window_did_move(this: &Object, _cmd: Sel, notification: id) {
-            suppress_delegate_panic("windowDidMove:", (), || unsafe {
-                let super_del: id = *this.get_ivar("super_delegate");
-                let _: () = msg_send![super_del, windowDidMove: notification];
-            });
-        }
-        extern "C" fn on_window_did_change_backing_properties(
-            this: &Object,
-            _cmd: Sel,
-            notification: id,
-        ) {
-            suppress_delegate_panic("windowDidChangeBackingProperties:", (), || unsafe {
-                let super_del: id = *this.get_ivar("super_delegate");
-                let _: () = msg_send![super_del, windowDidChangeBackingProperties: notification];
-            });
-        }
-        extern "C" fn on_window_did_become_key(this: &Object, _cmd: Sel, notification: id) {
-            suppress_delegate_panic("windowDidBecomeKey:", (), || unsafe {
-                let super_del: id = *this.get_ivar("super_delegate");
-                let _: () = msg_send![super_del, windowDidBecomeKey: notification];
-            });
-        }
-        extern "C" fn on_window_did_resign_key(this: &Object, _cmd: Sel, notification: id) {
-            suppress_delegate_panic("windowDidResignKey:", (), || unsafe {
-                let super_del: id = *this.get_ivar("super_delegate");
-                let _: () = msg_send![super_del, windowDidResignKey: notification];
-            });
-        }
-        extern "C" fn on_dragging_entered(this: &Object, _cmd: Sel, notification: id) -> BOOL {
-            suppress_delegate_panic("draggingEntered:", cocoa::base::NO, || unsafe {
-                let super_del: id = *this.get_ivar("super_delegate");
-                msg_send![super_del, draggingEntered: notification]
-            })
-        }
-        extern "C" fn on_prepare_for_drag_operation(
-            this: &Object,
-            _cmd: Sel,
-            notification: id,
-        ) -> BOOL {
-            suppress_delegate_panic("prepareForDragOperation:", cocoa::base::NO, || unsafe {
-                let super_del: id = *this.get_ivar("super_delegate");
-                msg_send![super_del, prepareForDragOperation: notification]
-            })
-        }
-        extern "C" fn on_perform_drag_operation(this: &Object, _cmd: Sel, sender: id) -> BOOL {
-            suppress_delegate_panic("performDragOperation:", cocoa::base::NO, || unsafe {
-                let super_del: id = *this.get_ivar("super_delegate");
-                msg_send![super_del, performDragOperation: sender]
-            })
-        }
-        extern "C" fn on_conclude_drag_operation(this: &Object, _cmd: Sel, notification: id) {
-            suppress_delegate_panic("concludeDragOperation:", (), || unsafe {
-                let super_del: id = *this.get_ivar("super_delegate");
-                let _: () = msg_send![super_del, concludeDragOperation: notification];
-            });
-        }
-        extern "C" fn on_dragging_exited(this: &Object, _cmd: Sel, notification: id) {
-            suppress_delegate_panic("draggingExited:", (), || unsafe {
-                let super_del: id = *this.get_ivar("super_delegate");
-                let _: () = msg_send![super_del, draggingExited: notification];
-            });
-        }
-        extern "C" fn on_window_will_use_full_screen_presentation_options(
-            this: &Object,
-            _cmd: Sel,
-            window: id,
-            proposed_options: NSUInteger,
-        ) -> NSUInteger {
-            suppress_delegate_panic(
-                "window:willUseFullScreenPresentationOptions:",
-                proposed_options,
-                || unsafe {
-                    let super_del: id = *this.get_ivar("super_delegate");
-                    msg_send![super_del, window: window willUseFullScreenPresentationOptions: proposed_options]
-                },
-            )
-        }
-        extern "C" fn on_window_did_enter_full_screen(
-            this: &Object,
-            _cmd: Sel,
-            notification: id,
-        ) {
-            suppress_delegate_panic("windowDidEnterFullScreen:", (), || unsafe {
-                with_window_state(this, |state: &mut WindowState| {
-                    if let Err(err) = state.window.emit("did-enter-fullscreen", ()) {
-                        tracing::warn!("Failed to emit did-enter-fullscreen: {err}");
-                    }
-                });
-
-                let super_del: id = *this.get_ivar("super_delegate");
-                let _: () = msg_send![super_del, windowDidEnterFullScreen: notification];
-            });
-        }
-        extern "C" fn on_window_will_enter_full_screen(
-            this: &Object,
-            _cmd: Sel,
-            notification: id,
-        ) {
-            suppress_delegate_panic("windowWillEnterFullScreen:", (), || unsafe {
-                with_window_state(this, |state: &mut WindowState| {
-                    if let Err(err) = state.window.emit("will-enter-fullscreen", ()) {
-                        tracing::warn!("Failed to emit will-enter-fullscreen: {err}");
-                    }
-                });
-
-                let super_del: id = *this.get_ivar("super_delegate");
-                let _: () = msg_send![super_del, windowWillEnterFullScreen: notification];
-            });
-        }
-        extern "C" fn on_window_did_exit_full_screen(
-            this: &Object,
-            _cmd: Sel,
-            notification: id,
-        ) {
-            suppress_delegate_panic("windowDidExitFullScreen:", (), || unsafe {
-                with_window_state(this, |state: &mut WindowState| {
-                    if let Err(err) = state.window.emit("did-exit-fullscreen", ()) {
-                        tracing::warn!("Failed to emit did-exit-fullscreen: {err}");
-                    }
-
-                    if let Ok(window_handle) = state.window.ns_window() {
-                        position_window_controls(
-                            UnsafeWindowHandle(window_handle),
-                            &state.controls_inset,
-                        );
-                    } else {
-                        tracing::warn!("Failed to get handle to NSWindow after exiting fullscreen");
-                    }
-                });
-
-                let super_del: id = *this.get_ivar("super_delegate");
-                let _: () = msg_send![super_del, windowDidExitFullScreen: notification];
-            });
-        }
-        extern "C" fn on_window_will_exit_full_screen(
-            this: &Object,
-            _cmd: Sel,
-            notification: id,
-        ) {
-            suppress_delegate_panic("windowWillExitFullScreen:", (), || unsafe {
-                with_window_state(this, |state: &mut WindowState| {
-                    if let Err(err) = state.window.emit("will-exit-fullscreen", ()) {
-                        tracing::warn!("Failed to emit will-exit-fullscreen: {err}");
-                    }
-                });
-
-                let super_del: id = *this.get_ivar("super_delegate");
-                let _: () = msg_send![super_del, windowWillExitFullScreen: notification];
-            });
-        }
-        extern "C" fn on_window_did_fail_to_enter_full_screen(
-            this: &Object,
-            _cmd: Sel,
-            window: id,
-        ) {
-            suppress_delegate_panic("windowDidFailToEnterFullScreen:", (), || unsafe {
-                let super_del: id = *this.get_ivar("super_delegate");
-                let _: () = msg_send![super_del, windowDidFailToEnterFullScreen: window];
-            });
-        }
-        extern "C" fn on_effective_appearance_did_change(
-            this: &Object,
-            _cmd: Sel,
-            notification: id,
-        ) {
-            suppress_delegate_panic("effectiveAppearanceDidChange:", (), || unsafe {
-                let super_del: id = *this.get_ivar("super_delegate");
-                let _: () = msg_send![super_del, effectiveAppearanceDidChange: notification];
-            });
-        }
-        extern "C" fn on_effective_appearance_did_changed_on_main_thread(
-            this: &Object,
-            _cmd: Sel,
-            notification: id,
-        ) {
-            suppress_delegate_panic(
-                "effectiveAppearanceDidChangedOnMainThread:",
-                (),
-                || unsafe {
-                    let super_del: id = *this.get_ivar("super_delegate");
-                    let _: () = msg_send![
-                        super_del,
-                        effectiveAppearanceDidChangedOnMainThread: notification
-                    ];
-                },
-            );
-        }
-
-        // Register the delegate class once and reuse it for every window. Previously a brand
-        // new class was registered (with a randomized name) on every call to `setup`, which
-        // permanently leaked Objective-C class metadata for the lifetime of the process.
-        //
-        // NOTE: `static CLASS` below is a single process-wide instance shared across every
-        // monomorphization of this function, not one per `R`. `setup` is only ever called
-        // with `R = tauri::Wry` in this app, so this is fine in practice; if it were ever
-        // called with a different `R`, the first call's `on_*::` method pointers would
-        // be baked into the shared class for all `R`.
-        fn get_or_register_delegate_class() -> &'static Class {
-            static CLASS: std::sync::OnceLock<&'static Class> = std::sync::OnceLock::new();
-            CLASS.get_or_init(|| {
-                if let Some(existing) = Class::get("CapWindowDelegate") {
-                    return existing;
-                }
-
-                let mut decl = match ClassDecl::new("CapWindowDelegate", class!(NSObject)) {
-                    Some(decl) => decl,
-                    None => {
-                        return Class::get("CapWindowDelegate")
-                            .expect("CapWindowDelegate should exist if already registered");
-                    }
-                };
-
-                decl.add_ivar::("window");
-                decl.add_ivar::<*mut c_void>("app_box");
-                decl.add_ivar::("toolbar");
-                decl.add_ivar::("super_delegate");
-
-                unsafe {
-                    decl.add_method(
-                        sel!(windowShouldClose:),
-                        on_window_should_close as extern "C" fn(&Object, Sel, id) -> BOOL,
-                    );
-                    decl.add_method(
-                        sel!(windowWillClose:),
-                        on_window_will_close:: as extern "C" fn(&Object, Sel, id),
-                    );
-                    decl.add_method(
-                        sel!(windowDidResize:),
-                        on_window_did_resize:: as extern "C" fn(&Object, Sel, id),
-                    );
-                    decl.add_method(
-                        sel!(windowDidMove:),
-                        on_window_did_move as extern "C" fn(&Object, Sel, id),
-                    );
-                    decl.add_method(
-                        sel!(windowDidChangeBackingProperties:),
-                        on_window_did_change_backing_properties as extern "C" fn(&Object, Sel, id),
-                    );
-                    decl.add_method(
-                        sel!(windowDidBecomeKey:),
-                        on_window_did_become_key as extern "C" fn(&Object, Sel, id),
-                    );
-                    decl.add_method(
-                        sel!(windowDidResignKey:),
-                        on_window_did_resign_key as extern "C" fn(&Object, Sel, id),
-                    );
-                    decl.add_method(
-                        sel!(draggingEntered:),
-                        on_dragging_entered as extern "C" fn(&Object, Sel, id) -> BOOL,
-                    );
-                    decl.add_method(
-                        sel!(prepareForDragOperation:),
-                        on_prepare_for_drag_operation as extern "C" fn(&Object, Sel, id) -> BOOL,
-                    );
-                    decl.add_method(
-                        sel!(performDragOperation:),
-                        on_perform_drag_operation as extern "C" fn(&Object, Sel, id) -> BOOL,
-                    );
-                    decl.add_method(
-                        sel!(concludeDragOperation:),
-                        on_conclude_drag_operation as extern "C" fn(&Object, Sel, id),
-                    );
-                    decl.add_method(
-                        sel!(draggingExited:),
-                        on_dragging_exited as extern "C" fn(&Object, Sel, id),
-                    );
-                    decl.add_method(
-                        sel!(window:willUseFullScreenPresentationOptions:),
-                        on_window_will_use_full_screen_presentation_options
-                            as extern "C" fn(&Object, Sel, id, NSUInteger) -> NSUInteger,
-                    );
-                    decl.add_method(
-                        sel!(windowDidEnterFullScreen:),
-                        on_window_did_enter_full_screen:: as extern "C" fn(&Object, Sel, id),
-                    );
-                    decl.add_method(
-                        sel!(windowWillEnterFullScreen:),
-                        on_window_will_enter_full_screen:: as extern "C" fn(&Object, Sel, id),
-                    );
-                    decl.add_method(
-                        sel!(windowDidExitFullScreen:),
-                        on_window_did_exit_full_screen:: as extern "C" fn(&Object, Sel, id),
-                    );
-                    decl.add_method(
-                        sel!(windowWillExitFullScreen:),
-                        on_window_will_exit_full_screen:: as extern "C" fn(&Object, Sel, id),
-                    );
-                    decl.add_method(
-                        sel!(windowDidFailToEnterFullScreen:),
-                        on_window_did_fail_to_enter_full_screen as extern "C" fn(&Object, Sel, id),
-                    );
-                    decl.add_method(
-                        sel!(effectiveAppearanceDidChange:),
-                        on_effective_appearance_did_change as extern "C" fn(&Object, Sel, id),
-                    );
-                    decl.add_method(
-                        sel!(effectiveAppearanceDidChangedOnMainThread:),
-                        on_effective_appearance_did_changed_on_main_thread
-                            as extern "C" fn(&Object, Sel, id),
-                    );
-                }
-
-                decl.register()
-            })
-        }
-
-        let app_state = WindowState {
-            window,
-            controls_inset,
-        };
-        let app_box = Box::into_raw(Box::new(app_state)) as *mut c_void;
-
-        let delegate_class = get_or_register_delegate_class::();
-        let delegate: id = msg_send![delegate_class, new];
-        (*delegate).set_ivar("window", ns_win_id);
-        (*delegate).set_ivar("app_box", app_box);
-        (*delegate).set_ivar("toolbar", cocoa::base::nil);
-        (*delegate).set_ivar("super_delegate", current_delegate);
-
-        ns_win_id.setDelegate_(delegate)
-    }
-}
diff --git a/apps/desktop/src-tauri/src/platform/macos/mod.rs b/apps/desktop/src-tauri/src/platform/macos/mod.rs
deleted file mode 100644
index e4072177d7c..00000000000
--- a/apps/desktop/src-tauri/src/platform/macos/mod.rs
+++ /dev/null
@@ -1,788 +0,0 @@
-// use std::ffi::c_void;
-
-// use cocoa::{
-//     base::{id, nil},
-//     foundation::NSString,
-// };
-// use core_graphics::{
-//     base::boolean_t,
-//     display::{CFDictionaryRef, CGRect},
-// };
-// use objc::{class, msg_send, sel, sel_impl};
-
-pub mod delegates;
-mod sc_shareable_content;
-
-pub use sc_shareable_content::*;
-
-fn constrain_position_to_visible_top(
-    position: tauri::PhysicalPosition,
-    monitor_top: i32,
-    scale_factor: f64,
-    visible_frame_top_inset: f64,
-    safe_area_top_inset: f64,
-) -> Option> {
-    let top_inset = visible_frame_top_inset.max(safe_area_top_inset).max(0.0);
-    let minimum_y = monitor_top.saturating_add((top_inset * scale_factor).round() as i32);
-
-    (position.y < minimum_y).then(|| tauri::PhysicalPosition::new(position.x, minimum_y))
-}
-
-pub fn constrain_main_window_to_visible_top(
-    window: &tauri::Window,
-    position: tauri::PhysicalPosition,
-) -> Option> {
-    use objc2::{runtime::NSObjectProtocol, sel};
-    use objc2_app_kit::NSWindow;
-
-    let monitor = window.current_monitor().ok().flatten()?;
-    let ns_window = window.ns_window().ok()? as *const NSWindow;
-    let screen = unsafe { (*ns_window).screen() }?;
-    let frame = screen.frame();
-    let visible_frame = screen.visibleFrame();
-    let safe_area_top_inset = if screen.respondsToSelector(sel!(safeAreaInsets)) {
-        unsafe { screen.safeAreaInsets().top }
-    } else {
-        0.0
-    };
-    // Tauri runtime 2.8 omits this macOS top offset from Monitor::work_area().position.
-    let visible_frame_top_inset =
-        frame.origin.y + frame.size.height - visible_frame.origin.y - visible_frame.size.height;
-
-    constrain_position_to_visible_top(
-        position,
-        monitor.position().y,
-        monitor.scale_factor(),
-        visible_frame_top_inset,
-        safe_area_top_inset,
-    )
-}
-
-fn constrain_frame_to_visible_area(
-    frame: objc2_foundation::NSRect,
-    screen_frame: objc2_foundation::NSRect,
-    visible_frame: objc2_foundation::NSRect,
-    safe_area_top_inset: f64,
-) -> Option {
-    use objc2_foundation::{NSPoint, NSRect, NSSize};
-
-    let minimum_x = visible_frame.origin.x;
-    let minimum_y = visible_frame.origin.y;
-    let maximum_x = minimum_x + visible_frame.size.width;
-    let maximum_y = (minimum_y + visible_frame.size.height)
-        .min(screen_frame.origin.y + screen_frame.size.height - safe_area_top_inset.max(0.0));
-    if ![
-        frame.origin.x,
-        frame.origin.y,
-        frame.size.width,
-        frame.size.height,
-        minimum_x,
-        minimum_y,
-        maximum_x,
-        maximum_y,
-    ]
-    .into_iter()
-    .all(f64::is_finite)
-        || frame.size.width <= 0.0
-        || frame.size.height <= 0.0
-        || maximum_x <= minimum_x
-        || maximum_y <= minimum_y
-    {
-        return None;
-    }
-
-    let width = frame.size.width.min(maximum_x - minimum_x);
-    let height = frame.size.height.min(maximum_y - minimum_y);
-    let constrained = NSRect::new(
-        NSPoint::new(
-            frame.origin.x.clamp(minimum_x, maximum_x - width),
-            frame.origin.y.clamp(minimum_y, maximum_y - height),
-        ),
-        NSSize::new(width, height),
-    );
-    (constrained != frame).then_some(constrained)
-}
-
-pub fn constrain_main_window_to_visible_frame(window: &tauri::Window) -> Result<(), String> {
-    use objc2::{MainThreadMarker, runtime::NSObjectProtocol, sel};
-    use objc2_app_kit::{NSScreen, NSWindow};
-
-    let main_thread =
-        MainThreadMarker::new().ok_or("Main window bounds must be checked on the main thread")?;
-    let ns_window = window.ns_window().map_err(|error| error.to_string())? as *const NSWindow;
-    let ns_window = unsafe { ns_window.as_ref() }.ok_or("Main window is unavailable")?;
-    let screen = ns_window
-        .screen()
-        .or_else(|| NSScreen::mainScreen(main_thread))
-        .ok_or("Main window screen is unavailable")?;
-    let safe_area_top_inset = if screen.respondsToSelector(sel!(safeAreaInsets)) {
-        unsafe { screen.safeAreaInsets().top }
-    } else {
-        0.0
-    };
-    if let Some(frame) = constrain_frame_to_visible_area(
-        ns_window.frame(),
-        screen.frame(),
-        screen.visibleFrame(),
-        safe_area_top_inset,
-    ) {
-        ns_window.setFrame_display(frame, true);
-    }
-    Ok(())
-}
-
-pub fn set_window_level(window: tauri::Window, level: objc2_app_kit::NSWindowLevel) {
-    let c_window = window.clone();
-    _ = window.run_on_main_thread(move || unsafe {
-        let Ok(ns_win) = c_window.ns_window() else {
-            return;
-        };
-        let ns_win = ns_win as *const objc2_app_kit::NSWindow;
-        (*ns_win).setLevel(level);
-    });
-}
-
-pub fn set_window_opacity(window: tauri::Window, opacity: f64) {
-    let opacity = opacity.clamp(0.45, 1.0);
-    let c_window = window.clone();
-    _ = window.run_on_main_thread(move || unsafe {
-        use cocoa::base::id;
-        use objc::{msg_send, sel, sel_impl};
-
-        let Ok(ns_win) = c_window.ns_window() else {
-            return;
-        };
-        let ns_win = ns_win as id;
-        let _: () = msg_send![ns_win, setAlphaValue: opacity];
-    });
-}
-
-pub fn apply_squircle_corners(window: &tauri::WebviewWindow, radius: f64) {
-    use cocoa::base::{id, nil};
-    use cocoa::foundation::NSString;
-    use objc::{msg_send, sel, sel_impl};
-
-    let Ok(ns_win) = window.ns_window() else {
-        return;
-    };
-
-    unsafe {
-        let ns_win = ns_win as id;
-        let content_view: id = msg_send![ns_win, contentView];
-
-        if content_view != nil {
-            let _: () = msg_send![content_view, setWantsLayer: true];
-
-            let layer: id = msg_send![content_view, layer];
-            if layer != nil {
-                let _: () = msg_send![layer, setCornerRadius: radius];
-                let _: () = msg_send![layer, setMasksToBounds: true];
-
-                let continuous = NSString::alloc(nil).init_str("continuous");
-                let _: () = msg_send![layer, setCornerCurve: continuous];
-            }
-        }
-    }
-}
-
-const TAURI_VIBRANCY_VIEW_TAG: isize = 91376254;
-const LIQUID_GLASS_IDENTIFIER: &str = "so.cap.liquid-glass-background";
-const NS_GLASS_EFFECT_VIEW_STYLE_REGULAR: isize = 0;
-
-#[derive(Clone, Copy, PartialEq, Eq)]
-enum LiquidGlassActivity {
-    SystemManaged,
-    AlwaysActive,
-}
-
-pub fn apply_main_window_liquid_glass_background(
-    window: &tauri::Window,
-    enabled: bool,
-    radius: f64,
-) -> Result {
-    apply_liquid_glass_background_inner(window, enabled, radius, LiquidGlassActivity::SystemManaged)
-}
-
-unsafe fn remove_tagged_subview(container: cocoa::base::id, tag: isize) {
-    use objc::{msg_send, sel, sel_impl};
-
-    unsafe {
-        let responds_to_view_with_tag: bool =
-            msg_send![container, respondsToSelector: sel!(viewWithTag:)];
-        if !responds_to_view_with_tag {
-            return;
-        }
-
-        let view: cocoa::base::id = msg_send![container, viewWithTag: tag];
-        if view != cocoa::base::nil {
-            let _: () = msg_send![view, removeFromSuperview];
-        }
-    }
-}
-
-unsafe fn remove_liquid_glass_subviews(
-    container: cocoa::base::id,
-    identifier: cocoa::base::id,
-    glass_class: *const objc::runtime::Class,
-) {
-    use cocoa::base::{id, nil};
-    use objc::{msg_send, sel, sel_impl};
-
-    unsafe {
-        let subviews: id = msg_send![container, subviews];
-        if subviews == nil {
-            return;
-        }
-
-        let count: usize = msg_send![subviews, count];
-        for index in (0..count).rev() {
-            let view: id = msg_send![subviews, objectAtIndex: index];
-            if view == nil {
-                continue;
-            }
-
-            let is_glass_view: bool = msg_send![view, isKindOfClass: glass_class];
-            if is_glass_view {
-                let _: () = msg_send![view, removeFromSuperview];
-                // Balance the `alloc` ownership claim taken when this view was
-                // created in `apply_liquid_glass_background`. Without this,
-                // removing it from the hierarchy only drops the superview's
-                // retain, leaving it stuck at refcount 1 forever — a leaked
-                // GPU/IOSurface-backed NSGlassEffectView on every re-apply.
-                let _: () = msg_send![view, release];
-                continue;
-            }
-
-            let responds_to_identifier: bool =
-                msg_send![view, respondsToSelector: sel!(identifier)];
-            if !responds_to_identifier {
-                continue;
-            }
-
-            let view_identifier: id = msg_send![view, identifier];
-            if view_identifier == nil {
-                continue;
-            }
-
-            let matches_identifier: bool = msg_send![view_identifier, isEqualToString: identifier];
-            if matches_identifier {
-                let _: () = msg_send![view, removeFromSuperview];
-            }
-        }
-    }
-}
-
-pub fn apply_liquid_glass_background(
-    window: &tauri::Window,
-    enabled: bool,
-    radius: f64,
-) -> Result {
-    apply_liquid_glass_background_inner(window, enabled, radius, LiquidGlassActivity::AlwaysActive)
-}
-
-fn apply_liquid_glass_background_inner(
-    window: &tauri::Window,
-    enabled: bool,
-    radius: f64,
-    activity: LiquidGlassActivity,
-) -> Result {
-    use cocoa::{
-        base::{id, nil},
-        foundation::{NSRect, NSString},
-    };
-    use objc::{class, msg_send, runtime::Class, sel, sel_impl};
-
-    unsafe {
-        let ns_window = window
-            .ns_window()
-            .map_err(|error| format!("Failed to get native window handle: {error}"))?
-            as id;
-        let content_view: id = msg_send![ns_window, contentView];
-
-        if content_view == nil {
-            return Err("Window has no content view".into());
-        }
-
-        let Some(glass_class) = Class::get("NSGlassEffectView") else {
-            // No NSGlassEffectView (pre-macOS-26) — the caller uses vibrancy.
-            if enabled {
-                crate::crash_sentinel::set_liquid_glass_outcome("unsupported");
-            }
-            return Ok(false);
-        };
-        let glass_class = glass_class as *const Class;
-        let glass_identifier = NSString::alloc(nil).init_str(LIQUID_GLASS_IDENTIFIER);
-
-        if !enabled {
-            teardown_liquid_glass_ns(ns_window);
-            return Ok(false);
-        }
-
-        remove_liquid_glass_subviews(content_view, glass_identifier, glass_class);
-
-        // Clip the content view itself to the same continuous (squircle) curve we apply
-        // to the NSGlassEffectView below. Without this, WebKit's CSS border-radius on
-        // `.cap-window-shell` and the window's Core Animation corner are rasterised by
-        // different engines and don't align pixel-perfectly, producing the visible inner
-        // "second border" inside the rounded corner. This is plain Core Animation (no
-        // private SPI / no WindowServer risk), so we apply it up front — it must clip
-        // BOTH the glass view and the vibrancy fallback, otherwise the artifact returns
-        // on the fallback path (most visibly on the larger-radius settings window).
-        let _: () = msg_send![content_view, setWantsLayer: true];
-        let content_layer: id = msg_send![content_view, layer];
-        if content_layer != nil {
-            let _: () = msg_send![content_layer, setCornerRadius: radius];
-            let _: () = msg_send![content_layer, setMasksToBounds: true];
-            let continuous = NSString::alloc(nil).init_str("continuous");
-            let _: () = msg_send![content_layer, setCornerCurve: continuous];
-        }
-
-        let bounds: NSRect = msg_send![content_view, bounds];
-        let glass_view: id = msg_send![glass_class, alloc];
-        let glass_view: id = msg_send![glass_view, initWithFrame: bounds];
-
-        if glass_view == nil {
-            crate::crash_sentinel::set_liquid_glass_outcome("fallback");
-            return Ok(false);
-        }
-
-        let responds_to_set_identifier: bool =
-            msg_send![glass_view, respondsToSelector: sel!(setIdentifier:)];
-        if responds_to_set_identifier {
-            let _: () = msg_send![glass_view, setIdentifier: glass_identifier];
-        }
-
-        let responds_to_set_corner_radius: bool =
-            msg_send![glass_view, respondsToSelector: sel!(setCornerRadius:)];
-        if responds_to_set_corner_radius {
-            let _: () = msg_send![glass_view, setCornerRadius: radius];
-        }
-
-        if activity == LiquidGlassActivity::SystemManaged {
-            let _: () = msg_send![glass_view, setStyle: NS_GLASS_EFFECT_VIEW_STYLE_REGULAR];
-        }
-
-        // Pin the glass to its "always-active" representation so it keeps re-rendering
-        // the live backdrop regardless of which window currently has key state. The
-        // default for an NSVisualEffectView-derived view is FollowsWindowActiveState,
-        // which dims the material whenever another Cap window (camera, settings, etc.)
-        // becomes key and masks the backdrop reactivity that's the whole point of
-        // Liquid Glass. The always-active state is private SPI, so we probe multiple
-        // state knobs (`setState:`, `setActive:`) instead of assuming one inheritance
-        // path. The main window does not enter this branch and remains system-managed.
-        //
-        // macOS 26.3 shipped an NSGlassEffectView that responds to neither selector,
-        // so the pin silently fails. In that state the material can't be relied on
-        // (it dims whenever another window becomes key), so abandon the private SPI
-        // entirely and let the caller fall back to NSVisualEffectView vibrancy
-        // (Ok(false)).
-        if activity == LiquidGlassActivity::AlwaysActive
-            && !force_glass_view_always_active(glass_view)
-        {
-            // Never entered the view hierarchy; balance the alloc and bail. The
-            // content-layer squircle clip applied above is kept (plain Core Animation,
-            // not a WindowServer/occlusion mutation) so the vibrancy fallback still gets
-            // the aligned rounded corner.
-            let _: () = msg_send![glass_view, release];
-            crate::crash_sentinel::set_liquid_glass_outcome("fallback");
-            return Ok(false);
-        }
-
-        remove_tagged_subview(content_view, TAURI_VIBRANCY_VIEW_TAG);
-
-        let clear_color: id = msg_send![class!(NSColor), clearColor];
-        let _: () = msg_send![ns_window, setOpaque: false];
-        let _: () = msg_send![ns_window, setBackgroundColor: clear_color];
-
-        // Deliberately DO NOT disable window/WKWebView occlusion detection here.
-        // Earlier builds called the private `_setWindowOcclusionDetectionEnabled:` /
-        // `_setWebViewWindowOcclusionDetectionEnabled:` SPI so the glass backdrop kept
-        // sampling while Cap was unfocused, but an occlusion-suppressed surface is one
-        // WindowServer can never quiesce — on macOS 26 that wedged the compositor when
-        // the window was later hidden or the app quit (often after sleep/lid-close),
-        // watchdog-stalling WindowServer and soft-restarting the whole login session.
-        // Gating it on the always-active pin was not enough: the main window's
-        // close-to-tray path hides the window without any teardown, so any future
-        // macOS build where the pin succeeds would silently re-arm the wedge. The
-        // only field-verified-safe configuration is to leave occlusion detection
-        // alone entirely; the trade-off is merely cosmetic (backdrop sampling may
-        // pause on the last frame while the app is deactivated).
-
-        let _: () = msg_send![glass_view, setAutoresizingMask: 18usize];
-        let _: () = msg_send![
-            content_view,
-            addSubview: glass_view
-            positioned: -1isize
-            relativeTo: nil
-        ];
-
-        if activity == LiquidGlassActivity::AlwaysActive {
-            // Re-apply after the view enters the hierarchy: some private AppKit views
-            // reset state machine fields on `viewDidMoveToWindow:`, so the post-add pass
-            // is what actually sticks.
-            force_glass_view_always_active(glass_view);
-        }
-
-        crate::crash_sentinel::set_liquid_glass_outcome("applied");
-        Ok(true)
-    }
-}
-
-/// Pin the glass material to its always-active representation. Returns whether the
-/// view actually responded to a known pinning selector. A `false` return means this
-/// macOS build's NSGlassEffectView SPI differs from what we understand (notably 26.3,
-/// where it responds to neither `setState:` nor `setActive:`) and the material must
-/// NOT be relied upon — see `apply_liquid_glass_background`.
-unsafe fn force_glass_view_always_active(glass_view: cocoa::base::id) -> bool {
-    use cocoa::base::id;
-    use objc::{msg_send, sel, sel_impl};
-
-    unsafe {
-        let responds_to_set_state: bool =
-            msg_send![glass_view, respondsToSelector: sel!(setState:)];
-        if responds_to_set_state {
-            // NSVisualEffectStateActive == 1
-            let _: () = msg_send![glass_view, setState: 1isize];
-            tracing::info!(target: "cap_desktop_lib::liquid_glass", "NSGlassEffectView responds to setState:");
-        }
-
-        let responds_to_set_active: bool =
-            msg_send![glass_view, respondsToSelector: sel!(setActive:)];
-        if responds_to_set_active {
-            let _: () = msg_send![glass_view, setActive: true];
-            tracing::info!(target: "cap_desktop_lib::liquid_glass", "NSGlassEffectView responds to setActive:");
-        }
-
-        if !responds_to_set_state && !responds_to_set_active {
-            tracing::debug!(
-                target: "cap_desktop_lib::liquid_glass",
-                "NSGlassEffectView responds to neither setState: nor setActive: — \
-                 cannot pin material to always-active; falling back to vibrancy"
-            );
-            return false;
-        }
-
-        // If the glass view internally wraps an NSVisualEffectView (rather than
-        // subclassing it), the state property on the outer view won't propagate.
-        // Walk one level of subviews and pin any visual-effect-like state we find.
-        let subviews: id = msg_send![glass_view, subviews];
-        if subviews != cocoa::base::nil {
-            let count: usize = msg_send![subviews, count];
-            for index in 0..count {
-                let subview: id = msg_send![subviews, objectAtIndex: index];
-                if subview == cocoa::base::nil {
-                    continue;
-                }
-
-                let subview_responds_to_set_state: bool =
-                    msg_send![subview, respondsToSelector: sel!(setState:)];
-                if subview_responds_to_set_state {
-                    let _: () = msg_send![subview, setState: 1isize];
-                }
-            }
-        }
-
-        true
-    }
-}
-
-unsafe fn enable_window_occlusion_detection(ns_window: cocoa::base::id) {
-    use objc::{msg_send, sel, sel_impl};
-
-    // Defense-in-depth heal: current builds never disable occlusion detection, but
-    // re-assert the OS default via whichever private SPI variant this AppKit build
-    // responds to, so the OS can always quiesce the surface.
-    unsafe {
-        let responds: bool = msg_send![
-            ns_window,
-            respondsToSelector: sel!(_setWindowOcclusionDetectionEnabled:)
-        ];
-        if responds {
-            let _: () = msg_send![ns_window, _setWindowOcclusionDetectionEnabled: true];
-            return;
-        }
-
-        let responds: bool = msg_send![
-            ns_window,
-            respondsToSelector: sel!(setWindowOcclusionDetectionEnabled:)
-        ];
-        if responds {
-            let _: () = msg_send![ns_window, setWindowOcclusionDetectionEnabled: true];
-            return;
-        }
-
-        let responds: bool = msg_send![
-            ns_window,
-            respondsToSelector: sel!(_setOcclusionDetectionEnabled:)
-        ];
-        if responds {
-            let _: () = msg_send![ns_window, _setOcclusionDetectionEnabled: true];
-            return;
-        }
-
-        let responds: bool = msg_send![
-            ns_window,
-            respondsToSelector: sel!(setOcclusionDetectionEnabled:)
-        ];
-        if responds {
-            let _: () = msg_send![ns_window, setOcclusionDetectionEnabled: true];
-        }
-    }
-}
-
-unsafe fn enable_webview_occlusion_detection(content_view: cocoa::base::id) {
-    use cocoa::base::id;
-    use objc::{msg_send, runtime::Class, sel, sel_impl};
-
-    // Re-enumerate the live WKWebView subview (its identity/index can change between
-    // apply and teardown) and restore occlusion detection, mirroring the disable path.
-    unsafe {
-        let Some(wkwebview_class) = Class::get("WKWebView") else {
-            return;
-        };
-        let wkwebview_class = wkwebview_class as *const Class;
-
-        let subviews: id = msg_send![content_view, subviews];
-        if subviews == cocoa::base::nil {
-            return;
-        }
-
-        let count: usize = msg_send![subviews, count];
-        for index in 0..count {
-            let subview: id = msg_send![subviews, objectAtIndex: index];
-            if subview == cocoa::base::nil {
-                continue;
-            }
-
-            let is_webview: bool = msg_send![subview, isKindOfClass: wkwebview_class];
-            if !is_webview {
-                continue;
-            }
-
-            let responds: bool = msg_send![
-                subview,
-                respondsToSelector: sel!(_setWebViewWindowOcclusionDetectionEnabled:)
-            ];
-            if responds {
-                let _: () = msg_send![subview, _setWebViewWindowOcclusionDetectionEnabled: true];
-                return;
-            }
-
-            let responds: bool = msg_send![
-                subview,
-                respondsToSelector: sel!(_setWindowOcclusionDetectionEnabled:)
-            ];
-            if responds {
-                let _: () = msg_send![subview, _setWindowOcclusionDetectionEnabled: true];
-                return;
-            }
-
-            return;
-        }
-    }
-}
-
-/// Reverse every WindowServer-visible mutation `apply_liquid_glass_background` makes:
-/// remove the NSGlassEffectView, then restore window/WKWebView occlusion detection and
-/// window opacity. MUST run on the AppKit main thread.
-unsafe fn teardown_liquid_glass_ns(ns_window: cocoa::base::id) {
-    use cocoa::{
-        base::{id, nil},
-        foundation::NSString,
-    };
-    use objc::{msg_send, runtime::Class, sel, sel_impl};
-
-    unsafe {
-        let content_view: id = msg_send![ns_window, contentView];
-        if content_view == nil {
-            return;
-        }
-
-        if let Some(glass_class) = Class::get("NSGlassEffectView") {
-            let glass_identifier = NSString::alloc(nil).init_str(LIQUID_GLASS_IDENTIFIER);
-            remove_liquid_glass_subviews(
-                content_view,
-                glass_identifier,
-                glass_class as *const Class,
-            );
-        }
-
-        enable_window_occlusion_detection(ns_window);
-        enable_webview_occlusion_detection(content_view);
-        let _: () = msg_send![ns_window, setOpaque: true];
-    }
-}
-
-/// Tear down liquid glass on every webview window. MUST be called on the AppKit main
-/// thread (e.g. from the `RunEvent::Exit` handler, which runs on main). Returns the
-/// number of windows processed.
-pub fn teardown_all_liquid_glass_on_main(app: &tauri::AppHandle) -> usize {
-    use tauri::Manager;
-
-    let mut count = 0usize;
-    for (_label, window) in app.webview_windows() {
-        if let Ok(ns_window) = window.ns_window() {
-            unsafe {
-                teardown_liquid_glass_ns(ns_window as cocoa::base::id);
-            }
-            count += 1;
-        }
-    }
-    count
-}
-
-/// Dispatch liquid-glass teardown onto the main thread and await it. Safe to call
-/// from a tokio worker during exit: the AppKit run loop is still pumping because the
-/// macOS terminate handler returned NSTerminateCancel before spawning the async exit.
-pub async fn teardown_all_liquid_glass(app: &tauri::AppHandle) -> Result<(), String> {
-    let app_for_closure = app.clone();
-    let (tx, rx) = tokio::sync::oneshot::channel();
-
-    app.run_on_main_thread(move || {
-        let count = teardown_all_liquid_glass_on_main(&app_for_closure);
-        let _ = tx.send(count);
-    })
-    .map_err(|error| error.to_string())?;
-
-    let count = rx
-        .await
-        .map_err(|_| "liquid glass teardown task was cancelled".to_string())?;
-    tracing::info!(
-        target: "cap_desktop_lib::liquid_glass",
-        windows = count,
-        "Tore down liquid glass before exit"
-    );
-    Ok(())
-}
-
-// pub fn get_ns_window_number(ns_window: *mut c_void) -> isize {
-//     let ns_window = ns_window as *const objc2_app_kit::NSWindow;
-
-//     unsafe { (*ns_window).windowNumber() }
-// }
-
-// #[link(name = "CoreGraphics", kind = "framework")]
-// unsafe extern "C" {
-//     pub fn CGRectMakeWithDictionaryRepresentation(
-//         dict: CFDictionaryRef,
-//         rect: *mut CGRect,
-//     ) -> boolean_t;
-// }
-
-// /// Makes the background of the WKWebView layer transparent.
-// /// This differs from Tauri's implementation as it does not change the window background which causes performance performance issues and artifacts when shadows are enabled on the window.
-// /// Use Tauri's implementation to make the window itself transparent.
-// pub fn make_webview_transparent(target: &tauri::WebviewWindow) -> tauri::Result<()> {
-//     target.with_webview(|webview| unsafe {
-//         let wkwebview = webview.inner() as id;
-//         let no: id = msg_send![class!(NSNumber), numberWithBool:0];
-//         // [https://developer.apple.com/documentation/webkit/webview/1408486-drawsbackground]
-//         let _: id = msg_send![wkwebview, setValue:no forKey: NSString::alloc(nil).init_str("drawsBackground")];
-//     })
-// }
-
-#[cfg(test)]
-mod tests {
-    use super::{constrain_frame_to_visible_area, constrain_position_to_visible_top};
-    use objc2_foundation::{NSPoint, NSRect, NSSize};
-    use tauri::PhysicalPosition;
-
-    fn rect(x: f64, y: f64, width: f64, height: f64) -> NSRect {
-        NSRect::new(NSPoint::new(x, y), NSSize::new(width, height))
-    }
-
-    #[test]
-    fn fits_the_actual_resized_frame_inside_the_work_area() {
-        let screen = rect(0.0, 0.0, 1440.0, 900.0);
-        let visible = rect(0.0, 24.0, 1440.0, 851.0);
-        let constrained = constrain_frame_to_visible_area(
-            rect(1300.0, 800.0, 330.0, 395.0),
-            screen,
-            visible,
-            0.0,
-        )
-        .unwrap();
-
-        assert_eq!(constrained, rect(1110.0, 480.0, 330.0, 395.0));
-        assert_eq!(
-            constrain_frame_to_visible_area(constrained, screen, visible, 0.0),
-            None
-        );
-    }
-
-    #[test]
-    fn fits_expanded_frames_below_a_notch_with_a_hidden_menu_bar() {
-        let screen = rect(0.0, 0.0, 1440.0, 900.0);
-        assert_eq!(
-            constrain_frame_to_visible_area(rect(100.0, 650.0, 480.0, 700.0), screen, screen, 37.0,),
-            Some(rect(100.0, 163.0, 480.0, 700.0))
-        );
-    }
-
-    #[test]
-    fn keeps_native_coordinates_on_a_display_above_and_left_of_primary() {
-        assert_eq!(
-            constrain_frame_to_visible_area(
-                rect(-2000.0, 1800.0, 480.0, 700.0),
-                rect(-1920.0, 900.0, 1920.0, 1080.0),
-                rect(-1880.0, 900.0, 1880.0, 1050.0),
-                37.0,
-            ),
-            Some(rect(-1880.0, 1243.0, 480.0, 700.0))
-        );
-    }
-
-    #[test]
-    fn fits_an_oversized_restored_frame_without_negative_clamp_ranges() {
-        let visible = rect(40.0, 24.0, 1400.0, 851.0);
-        assert_eq!(
-            constrain_frame_to_visible_area(
-                rect(-100.0, -100.0, 2000.0, 1200.0),
-                rect(0.0, 0.0, 1440.0, 900.0),
-                visible,
-                0.0,
-            ),
-            Some(visible)
-        );
-    }
-
-    #[test]
-    fn moves_a_window_below_a_notched_visible_frame() {
-        let position = PhysicalPosition::new(640, 0);
-
-        assert_eq!(
-            constrain_position_to_visible_top(position, 0, 2.0, 19.0, 18.0),
-            Some(PhysicalPosition::new(640, 38))
-        );
-    }
-
-    #[test]
-    fn uses_the_safe_area_when_the_menu_bar_is_hidden() {
-        let position = PhysicalPosition::new(200, 0);
-
-        assert_eq!(
-            constrain_position_to_visible_top(position, 0, 2.0, 0.0, 37.0),
-            Some(PhysicalPosition::new(200, 74))
-        );
-    }
-
-    #[test]
-    fn preserves_negative_coordinates_on_a_monitor_above_the_primary() {
-        let position = PhysicalPosition::new(-600, -1800);
-
-        assert_eq!(
-            constrain_position_to_visible_top(position, -1800, 1.5, 25.0, 0.0),
-            Some(PhysicalPosition::new(-600, -1762))
-        );
-    }
-
-    #[test]
-    fn leaves_an_accessible_position_unchanged() {
-        let position = PhysicalPosition::new(300, 100);
-
-        assert_eq!(
-            constrain_position_to_visible_top(position, 0, 2.0, 19.0, 18.0),
-            None
-        );
-    }
-}
diff --git a/apps/desktop/src-tauri/src/platform/macos/sc_shareable_content.rs b/apps/desktop/src-tauri/src/platform/macos/sc_shareable_content.rs
deleted file mode 100644
index 8bc5eebe713..00000000000
--- a/apps/desktop/src-tauri/src/platform/macos/sc_shareable_content.rs
+++ /dev/null
@@ -1,198 +0,0 @@
-use cidre::{arc, ns, sc};
-use std::sync::{Arc, OnceLock, RwLock};
-use tokio::sync::{Mutex, Notify};
-use tracing::{error, trace};
-
-#[derive(Default)]
-struct CacheState {
-    cache: RwLock>,
-    warmup: Mutex>,
-}
-
-type WarmupResult = Result<(), arc::R>;
-
-#[derive(Clone)]
-struct WarmupTask {
-    notify: Arc,
-    result: Arc>>,
-}
-
-static STATE: OnceLock = OnceLock::new();
-
-fn state() -> &'static CacheState {
-    STATE.get_or_init(CacheState::default)
-}
-
-pub async fn prewarm_shareable_content() -> Result<(), arc::R> {
-    prewarm_shareable_content_inner(false).await
-}
-
-pub async fn refresh_shareable_content() -> Result<(), arc::R> {
-    prewarm_shareable_content_inner(true).await
-}
-
-async fn prewarm_shareable_content_inner(force_refresh: bool) -> Result<(), arc::R> {
-    if force_refresh {
-        state().cache.write().unwrap().take();
-    } else if state().cache.read().unwrap().is_some() {
-        trace!("ScreenCaptureKit shareable content already warmed");
-        return Ok(());
-    }
-
-    let warmup = {
-        let mut guard = state().warmup.lock().await;
-        if let Some(task) = guard.clone() {
-            trace!("Awaiting in-flight ScreenCaptureKit warmup");
-            task
-        } else {
-            let task = WarmupTask {
-                notify: Arc::new(Notify::new()),
-                result: Arc::new(Mutex::new(None)),
-            };
-            *guard = Some(task.clone());
-            tokio::spawn(run_warmup(task.clone()));
-            task
-        }
-    };
-
-    warmup.notify.notified().await;
-    warmup.result.lock().await.clone().unwrap_or_else(|| {
-        error!("ScreenCaptureKit warmup task finished without a result");
-        Ok(())
-    })
-}
-
-pub async fn get_shareable_content()
--> Result>, arc::R> {
-    if let Some(content) = state()
-        .cache
-        .read()
-        .unwrap()
-        .as_ref()
-        .map(|v| v.content.retained())
-    {
-        return Ok(Some(content));
-    }
-
-    prewarm_shareable_content().await?;
-
-    let content = state().cache.read().unwrap();
-    Ok(content.as_ref().map(|v| v.content.retained()))
-}
-
-async fn run_warmup(task: WarmupTask) {
-    let result = async {
-        let content = sc::ShareableContent::current().await?;
-        let cache = ShareableContentCache::new(content);
-
-        let mut guard = state().cache.write().unwrap();
-        *guard = Some(cache);
-
-        Ok::<(), arc::R>(())
-    }
-    .await;
-
-    {
-        let mut res_guard = task.result.lock().await;
-        *res_guard = Some(result);
-    }
-
-    task.notify.notify_waiters();
-
-    let mut guard = state().warmup.lock().await;
-    if let Some(current) = guard.as_ref()
-        && Arc::ptr_eq(¤t.notify, &task.notify)
-    {
-        *guard = None;
-    }
-}
-
-#[derive(Debug)]
-struct ShareableContentCache {
-    #[allow(dead_code)]
-    content: arc::R,
-}
-
-unsafe impl Send for ShareableContentCache {}
-unsafe impl Sync for ShareableContentCache {}
-
-impl ShareableContentCache {
-    fn new(content: arc::R) -> Self {
-        Self { content }
-    }
-}
-
-pub(crate) struct ScreenCapturePrewarmer {
-    state: Mutex,
-}
-
-impl Default for ScreenCapturePrewarmer {
-    fn default() -> Self {
-        Self {
-            state: Mutex::new(PrewarmState::Idle),
-        }
-    }
-}
-
-impl ScreenCapturePrewarmer {
-    pub async fn request(&self, force: bool) {
-        let should_start = {
-            let mut state = self.state.lock().await;
-
-            if force {
-                *state = PrewarmState::Idle;
-            }
-
-            match *state {
-                PrewarmState::Idle => {
-                    *state = PrewarmState::Warming;
-                    true
-                }
-                PrewarmState::Warming => {
-                    trace!("ScreenCaptureKit prewarm already in progress");
-                    false
-                }
-                PrewarmState::Warmed => {
-                    if force {
-                        *state = PrewarmState::Warming;
-                        true
-                    } else {
-                        trace!("ScreenCaptureKit cache already warmed");
-                        false
-                    }
-                }
-            }
-        };
-
-        if !should_start {
-            return;
-        }
-
-        let warm_start = std::time::Instant::now();
-        let result = if force {
-            crate::platform::refresh_shareable_content().await
-        } else {
-            crate::platform::prewarm_shareable_content().await
-        };
-
-        let mut state = self.state.lock().await;
-        match result {
-            Ok(()) => {
-                let elapsed_ms = warm_start.elapsed().as_micros() as f64 / 1000.0;
-                *state = PrewarmState::Warmed;
-                trace!(elapsed_ms, "ScreenCaptureKit cache warmed");
-            }
-            Err(error) => {
-                *state = PrewarmState::Idle;
-                tracing::warn!(error = %error, "ScreenCaptureKit prewarm failed");
-            }
-        }
-    }
-}
-
-#[derive(Clone, Copy, PartialEq, Eq)]
-pub enum PrewarmState {
-    Idle,
-    Warming,
-    Warmed,
-}
diff --git a/apps/desktop/src-tauri/src/platform/mod.rs b/apps/desktop/src-tauri/src/platform/mod.rs
deleted file mode 100644
index e51d3e709a3..00000000000
--- a/apps/desktop/src-tauri/src/platform/mod.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-use serde::{Deserialize, Serialize};
-use specta::Type;
-#[cfg(target_os = "windows")]
-pub mod win;
-
-#[cfg(target_os = "macos")]
-pub mod macos;
-
-#[cfg(target_os = "macos")]
-pub use macos::*;
-use tracing::instrument;
-
-#[derive(Debug, Serialize, Deserialize, Type, Default)]
-#[serde(rename_all = "camelCase")]
-#[repr(isize)]
-pub enum HapticPattern {
-    Alignment = 0,
-    LevelChange = 1,
-    #[default]
-    Generic = 2,
-}
-
-#[derive(Debug, Serialize, Deserialize, Type, Default)]
-#[serde(rename_all = "camelCase")]
-#[repr(usize)]
-pub enum HapticPerformanceTime {
-    Default = 0,
-    #[default]
-    Now = 1,
-    DrawCompleted = 2,
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument]
-pub fn perform_haptic_feedback(
-    _pattern: Option,
-    _time: Option,
-) -> Result<(), String> {
-    #[cfg(target_os = "macos")]
-    unsafe {
-        use objc2_app_kit::{
-            NSHapticFeedbackManager, NSHapticFeedbackPattern, NSHapticFeedbackPerformanceTime,
-            NSHapticFeedbackPerformer,
-        };
-
-        NSHapticFeedbackManager::defaultPerformer().performFeedbackPattern_performanceTime(
-            NSHapticFeedbackPattern(_pattern.unwrap_or_default() as isize),
-            NSHapticFeedbackPerformanceTime(_time.unwrap_or_default() as usize),
-        );
-        Ok(())
-    }
-
-    #[cfg(not(target_os = "macos"))]
-    Err("Haptics are only supported on macOS.".into())
-}
-
-/// Check if system audio capture is supported on the current platform and OS version.
-/// On macOS, system audio capture requires macOS 13.0 or later.
-/// On Windows/Linux, this may have different requirements.
-#[tauri::command]
-#[specta::specta]
-#[instrument]
-pub fn is_system_audio_capture_supported() -> bool {
-    #[cfg(target_os = "macos")]
-    {
-        scap_screencapturekit::is_system_audio_supported()
-    }
-
-    #[cfg(not(target_os = "macos"))]
-    {
-        // On Windows/Linux, we assume system audio capture is available
-        // This can be refined later based on platform-specific requirements
-        true
-    }
-}
diff --git a/apps/desktop/src-tauri/src/platform/win.rs b/apps/desktop/src-tauri/src/platform/win.rs
deleted file mode 100644
index e5c47140d7f..00000000000
--- a/apps/desktop/src-tauri/src/platform/win.rs
+++ /dev/null
@@ -1,258 +0,0 @@
-use winreg::RegKey;
-use winreg::enums::HKEY_LOCAL_MACHINE;
-
-const ENV_OVERRIDE: &str = "CAP_WINDOW_CAPTURE_EXCLUSION";
-
-// Shadow reports S:102 for protected windows; EC2/DCV still displays excluded windows.
-const SMBIOS_MARKERS: &[&str] = &["shadow"];
-
-const VIRTUAL_DISPLAY_MARKERS: &[&str] = &[
-    "parsec",
-    "spacedesk",
-    "iddsample",
-    "virtual display",
-    "usbmmidd",
-    "amyuni",
-    "shadow",
-];
-
-pub fn capture_streamed_display_reason() -> Option {
-    streamed_display_reason_with(
-        std::env::var(ENV_OVERRIDE).ok().as_deref(),
-        remote_session_active,
-        streamed_computer_marker,
-        virtual_display_adapter,
-    )
-}
-
-fn exclusion_override(value: &str) -> Option {
-    match value.trim().to_ascii_lowercase().as_str() {
-        "on" | "always" | "1" => Some(true),
-        "off" | "never" | "0" => Some(false),
-        _ => None,
-    }
-}
-
-fn streamed_display_reason_with(
-    override_value: Option<&str>,
-    remote_session: impl FnOnce() -> bool,
-    streamed_computer: impl FnOnce() -> Option,
-    virtual_display: impl FnOnce() -> Option,
-) -> Option {
-    match override_value.and_then(exclusion_override) {
-        Some(true) => return None,
-        Some(false) => return Some(format!("{ENV_OVERRIDE} env override")),
-        None => {}
-    }
-    if remote_session() {
-        return Some("remote desktop session (SM_REMOTESESSION)".to_string());
-    }
-    if let Some(marker) = streamed_computer() {
-        return Some(format!("streamed computer SMBIOS ({marker})"));
-    }
-    virtual_display().map(|device| format!("virtual display adapter ({device})"))
-}
-
-fn remote_session_active() -> bool {
-    use windows::Win32::UI::WindowsAndMessaging::{GetSystemMetrics, SM_REMOTESESSION};
-    unsafe { GetSystemMetrics(SM_REMOTESESSION) != 0 }
-}
-
-fn streamed_computer_marker() -> Option {
-    let key = RegKey::predef(HKEY_LOCAL_MACHINE)
-        .open_subkey("HARDWARE\\DESCRIPTION\\System\\BIOS")
-        .ok()?;
-
-    for value in [
-        "SystemManufacturer",
-        "SystemProductName",
-        "SystemFamily",
-        "BIOSVendor",
-    ] {
-        let Ok(text) = key.get_value::(value) else {
-            continue;
-        };
-        if let Some(marker) = find_marker(&text, SMBIOS_MARKERS) {
-            return Some(format!("{value}=\"{text}\" matched \"{marker}\""));
-        }
-    }
-
-    None
-}
-
-fn virtual_display_adapter() -> Option {
-    use windows::Win32::Graphics::Gdi::{
-        DISPLAY_DEVICE_ATTACHED_TO_DESKTOP, DISPLAY_DEVICEW, EnumDisplayDevicesW,
-    };
-    use windows::core::PCWSTR;
-
-    let mut index = 0u32;
-    loop {
-        let mut device = DISPLAY_DEVICEW {
-            cb: std::mem::size_of::() as u32,
-            ..Default::default()
-        };
-        if !unsafe { EnumDisplayDevicesW(PCWSTR::null(), index, &mut device, 0) }.as_bool() {
-            return None;
-        }
-        index += 1;
-
-        if !device
-            .StateFlags
-            .contains(DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)
-        {
-            continue;
-        }
-
-        let name = String::from_utf16_lossy(&device.DeviceString);
-        let name = name.trim_matches(char::from(0));
-        if let Some(marker) = find_marker(name, VIRTUAL_DISPLAY_MARKERS) {
-            return Some(format!("\"{name}\" matched \"{marker}\""));
-        }
-    }
-}
-
-fn find_marker(text: &str, markers: &[&'static str]) -> Option<&'static str> {
-    let lower = text.to_lowercase();
-    markers.iter().copied().find(|m| lower.contains(m))
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn overrides_preserve_auto_and_explicit_choices() {
-        for value in ["on", " ALWAYS ", "1"] {
-            assert_eq!(exclusion_override(value), Some(true));
-        }
-        for value in ["off", " NEVER ", "0"] {
-            assert_eq!(exclusion_override(value), Some(false));
-        }
-        for value in ["", "auto", "unknown"] {
-            assert_eq!(exclusion_override(value), None);
-        }
-    }
-
-    #[test]
-    fn explicit_override_does_not_probe_the_environment() {
-        for (value, expected) in [
-            ("on", None),
-            ("off", Some(format!("{ENV_OVERRIDE} env override"))),
-        ] {
-            assert_eq!(
-                streamed_display_reason_with(
-                    Some(value),
-                    || panic!("override must skip remote-session detection"),
-                    || panic!("override must skip SMBIOS detection"),
-                    || panic!("override must skip display detection"),
-                ),
-                expected
-            );
-        }
-    }
-
-    #[test]
-    fn remote_session_keeps_its_compatibility_exception() {
-        assert_eq!(
-            streamed_display_reason_with(
-                None,
-                || true,
-                || panic!("remote session must skip SMBIOS detection"),
-                || panic!("remote session must skip display detection"),
-            ),
-            Some("remote desktop session (SM_REMOTESESSION)".to_string())
-        );
-    }
-
-    #[test]
-    fn shadow_keeps_its_compatibility_exception() {
-        for computer in ["Shadow", "SHADOW COMPUTER"] {
-            assert_eq!(
-                streamed_display_reason_with(
-                    None,
-                    || false,
-                    || find_marker(computer, SMBIOS_MARKERS).map(str::to_string),
-                    || panic!("Shadow must skip display detection"),
-                ),
-                Some("streamed computer SMBIOS (shadow)".to_string())
-            );
-        }
-    }
-
-    #[test]
-    fn existing_streamed_adapters_keep_their_compatibility_exception() {
-        for adapter in [
-            "Parsec Virtual Display Adapter",
-            "spacedesk",
-            "IddSampleDriver",
-            "Virtual Display",
-            "usbmmidd",
-            "Amyuni",
-            "Shadow",
-        ] {
-            assert!(
-                streamed_display_reason_with(
-                    None,
-                    || false,
-                    || None,
-                    || find_marker(adapter, VIRTUAL_DISPLAY_MARKERS).map(str::to_string),
-                )
-                .is_some(),
-                "{adapter}"
-            );
-        }
-    }
-
-    #[test]
-    fn virtual_machine_hardware_keeps_capture_exclusion() {
-        for computer in [
-            "Amazon EC2",
-            "QEMU Standard PC (Q35 + ICH9, 2009)",
-            "KVM",
-            "VMware",
-            "VirtualBox",
-            "innotek",
-            "Xen",
-            "Bochs",
-            "Parallels",
-            "Microsoft Corporation Virtual Machine",
-            "HVM domU",
-            "Google Compute Engine",
-            "OpenStack",
-        ] {
-            assert_eq!(
-                streamed_display_reason_with(
-                    None,
-                    || false,
-                    || find_marker(computer, SMBIOS_MARKERS).map(str::to_string),
-                    || None,
-                ),
-                None,
-                "{computer}"
-            );
-        }
-    }
-
-    #[test]
-    fn physical_hardware_keeps_capture_exclusion() {
-        for name in [
-            "Dell Inc.",
-            "ASUSTeK COMPUTER INC.",
-            "NVIDIA GeForce RTX 3080",
-            "AMD Radeon RX 7900 XTX",
-            "Intel(R) UHD Graphics 770",
-            "LENOVO",
-            "Micro-Star International Co., Ltd.",
-        ] {
-            assert_eq!(find_marker(name, SMBIOS_MARKERS), None, "{name}");
-            assert_eq!(find_marker(name, VIRTUAL_DISPLAY_MARKERS), None, "{name}");
-        }
-        for override_value in [None, Some("auto"), Some("unknown")] {
-            assert_eq!(
-                streamed_display_reason_with(override_value, || false, || None, || None),
-                None
-            );
-        }
-    }
-}
diff --git a/apps/desktop/src-tauri/src/power_observer.rs b/apps/desktop/src-tauri/src/power_observer.rs
deleted file mode 100644
index 4bf8e0b7fe4..00000000000
--- a/apps/desktop/src-tauri/src/power_observer.rs
+++ /dev/null
@@ -1,278 +0,0 @@
-use std::sync::atomic::{AtomicBool, Ordering};
-use tauri::AppHandle;
-#[cfg(any(target_os = "macos", target_os = "windows"))]
-use tracing::info;
-
-static SYSTEM_ASLEEP: AtomicBool = AtomicBool::new(false);
-
-pub fn is_system_asleep() -> bool {
-    SYSTEM_ASLEEP.load(Ordering::Acquire)
-}
-
-#[cfg(any(target_os = "macos", target_os = "windows"))]
-fn mark_sleeping() {
-    SYSTEM_ASLEEP.store(true, Ordering::Release);
-}
-
-#[cfg(any(target_os = "macos", target_os = "windows"))]
-fn mark_awake() {
-    SYSTEM_ASLEEP.store(false, Ordering::Release);
-}
-
-#[cfg(any(target_os = "macos", target_os = "windows"))]
-pub fn on_system_will_sleep(_app: &AppHandle) {
-    mark_sleeping();
-    info!("System going to sleep");
-}
-
-#[cfg(any(target_os = "macos", target_os = "windows"))]
-pub fn on_system_did_wake(app: &AppHandle) {
-    mark_awake();
-    info!("System woke from sleep; scheduling recovery refresh");
-    crate::schedule_resume_recovery(app.clone());
-}
-
-pub fn install(app: &AppHandle) {
-    #[cfg(target_os = "macos")]
-    macos::install(app);
-
-    #[cfg(target_os = "windows")]
-    windows::install(app);
-
-    #[cfg(not(any(target_os = "macos", target_os = "windows")))]
-    {
-        let _ = app;
-    }
-}
-
-pub fn uninstall(app: &AppHandle) {
-    #[cfg(target_os = "macos")]
-    macos::uninstall(app);
-
-    #[cfg(target_os = "windows")]
-    windows::uninstall(app);
-
-    #[cfg(not(any(target_os = "macos", target_os = "windows")))]
-    {
-        let _ = app;
-    }
-}
-
-#[cfg(target_os = "macos")]
-mod macos {
-    use super::{on_system_did_wake, on_system_will_sleep};
-    use objc2::{
-        AnyThread, DeclaredClass, define_class, msg_send,
-        rc::{Retained, autoreleasepool},
-        runtime::{AnyObject, NSObject},
-    };
-    use objc2_app_kit::NSWorkspace;
-    use objc2_foundation::{NSNotification, ns_string};
-    use std::sync::{Mutex, OnceLock};
-    use tauri::AppHandle;
-    use tracing::warn;
-
-    struct ObserverIvars {
-        app: AppHandle,
-    }
-
-    define_class!(
-        #[unsafe(super(NSObject))]
-        #[name = "CapPowerObserver"]
-        #[ivars = ObserverIvars]
-        struct CapPowerObserver;
-
-        impl CapPowerObserver {
-            #[unsafe(method(handleWillSleep:))]
-            fn handle_will_sleep(&self, _notification: &NSNotification) {
-                on_system_will_sleep(&self.ivars().app);
-            }
-
-            #[unsafe(method(handleDidWake:))]
-            fn handle_did_wake(&self, _notification: &NSNotification) {
-                on_system_did_wake(&self.ivars().app);
-            }
-
-            #[unsafe(method(handleScreensDidSleep:))]
-            fn handle_screens_did_sleep(&self, _notification: &NSNotification) {
-                on_system_will_sleep(&self.ivars().app);
-            }
-
-            #[unsafe(method(handleScreensDidWake:))]
-            fn handle_screens_did_wake(&self, _notification: &NSNotification) {
-                on_system_did_wake(&self.ivars().app);
-            }
-        }
-    );
-
-    impl CapPowerObserver {
-        fn new(app: AppHandle) -> Retained {
-            let this = Self::alloc().set_ivars(ObserverIvars { app });
-            unsafe { msg_send![super(this), init] }
-        }
-    }
-
-    static OBSERVER: OnceLock>>> = OnceLock::new();
-
-    fn slot() -> &'static Mutex>> {
-        OBSERVER.get_or_init(|| Mutex::new(None))
-    }
-
-    pub fn install(app: &AppHandle) {
-        let app = app.clone();
-        let Err(err) = app.clone().run_on_main_thread(move || {
-            autoreleasepool(|_| unsafe {
-                let mut guard = slot().lock().unwrap_or_else(|e| e.into_inner());
-                if guard.is_some() {
-                    return;
-                }
-
-                let workspace = NSWorkspace::sharedWorkspace();
-                let center = workspace.notificationCenter();
-                let observer = CapPowerObserver::new(app.clone());
-
-                let observer_obj: &AnyObject = &observer;
-
-                center.addObserver_selector_name_object(
-                    observer_obj,
-                    objc2::sel!(handleWillSleep:),
-                    Some(ns_string!("NSWorkspaceWillSleepNotification")),
-                    None,
-                );
-                center.addObserver_selector_name_object(
-                    observer_obj,
-                    objc2::sel!(handleDidWake:),
-                    Some(ns_string!("NSWorkspaceDidWakeNotification")),
-                    None,
-                );
-                center.addObserver_selector_name_object(
-                    observer_obj,
-                    objc2::sel!(handleScreensDidSleep:),
-                    Some(ns_string!("NSWorkspaceScreensDidSleepNotification")),
-                    None,
-                );
-                center.addObserver_selector_name_object(
-                    observer_obj,
-                    objc2::sel!(handleScreensDidWake:),
-                    Some(ns_string!("NSWorkspaceScreensDidWakeNotification")),
-                    None,
-                );
-
-                *guard = Some(observer);
-            });
-        }) else {
-            return;
-        };
-        warn!("Failed to install power observer on main thread: {err}");
-    }
-
-    pub fn uninstall(app: &AppHandle) {
-        let Err(err) = app.clone().run_on_main_thread(move || {
-            autoreleasepool(|_| unsafe {
-                let mut guard = slot().lock().unwrap_or_else(|e| e.into_inner());
-                if let Some(observer) = guard.take() {
-                    let workspace = NSWorkspace::sharedWorkspace();
-                    let center = workspace.notificationCenter();
-                    let observer_obj: &AnyObject = &observer;
-                    center.removeObserver(observer_obj);
-                }
-            });
-        }) else {
-            return;
-        };
-        warn!("Failed to uninstall power observer on main thread: {err}");
-    }
-}
-
-#[cfg(target_os = "windows")]
-mod windows {
-    use super::{on_system_did_wake, on_system_will_sleep};
-    use ::windows::Win32::Foundation::{HANDLE, WIN32_ERROR};
-    use ::windows::Win32::System::Power::{
-        DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS, HPOWERNOTIFY, PowerRegisterSuspendResumeNotification,
-        PowerUnregisterSuspendResumeNotification,
-    };
-    use ::windows::Win32::UI::WindowsAndMessaging::{
-        DEVICE_NOTIFY_CALLBACK, PBT_APMRESUMEAUTOMATIC, PBT_APMSUSPEND,
-    };
-    use std::ffi::c_void;
-    use std::sync::{Mutex, OnceLock};
-    use tauri::AppHandle;
-    use tracing::warn;
-
-    struct RegistrationHandle {
-        handle: HPOWERNOTIFY,
-        app: Box,
-    }
-
-    unsafe impl Send for RegistrationHandle {}
-    unsafe impl Sync for RegistrationHandle {}
-
-    static REGISTRATION: OnceLock>> = OnceLock::new();
-
-    fn slot() -> &'static Mutex> {
-        REGISTRATION.get_or_init(|| Mutex::new(None))
-    }
-
-    unsafe extern "system" fn power_callback(
-        context: *const c_void,
-        event_type: u32,
-        _setting: *const c_void,
-    ) -> u32 {
-        if context.is_null() {
-            return 0;
-        }
-        let app = unsafe { &*(context as *const AppHandle) };
-        match event_type {
-            PBT_APMSUSPEND => on_system_will_sleep(app),
-            PBT_APMRESUMEAUTOMATIC => on_system_did_wake(app),
-            _ => {}
-        }
-        0
-    }
-
-    pub fn install(app: &AppHandle) {
-        let mut guard = slot().lock().unwrap_or_else(|e| e.into_inner());
-        if guard.is_some() {
-            return;
-        }
-
-        let boxed_app = Box::new(app.clone());
-        let context = Box::as_ref(&boxed_app) as *const AppHandle as *mut c_void;
-
-        let params = DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS {
-            Callback: Some(power_callback),
-            Context: context,
-        };
-
-        let mut raw_handle: *mut c_void = std::ptr::null_mut();
-        let result = unsafe {
-            PowerRegisterSuspendResumeNotification(
-                DEVICE_NOTIFY_CALLBACK,
-                HANDLE(¶ms as *const _ as *mut c_void),
-                &mut raw_handle,
-            )
-        };
-
-        if result != WIN32_ERROR(0) {
-            warn!(
-                code = result.0,
-                "PowerRegisterSuspendResumeNotification failed"
-            );
-            return;
-        }
-
-        *guard = Some(RegistrationHandle {
-            handle: HPOWERNOTIFY(raw_handle as isize),
-            app: boxed_app,
-        });
-    }
-
-    pub fn uninstall(_app: &AppHandle) {
-        let mut guard = slot().lock().unwrap_or_else(|e| e.into_inner());
-        if let Some(reg) = guard.take() {
-            let _ = unsafe { PowerUnregisterSuspendResumeNotification(reg.handle) };
-            drop(reg.app);
-        }
-    }
-}
diff --git a/apps/desktop/src-tauri/src/preparing_finalization.rs b/apps/desktop/src-tauri/src/preparing_finalization.rs
deleted file mode 100644
index 31abc24de62..00000000000
--- a/apps/desktop/src-tauri/src/preparing_finalization.rs
+++ /dev/null
@@ -1,588 +0,0 @@
-use super::{
-    FinalizationAttempt, FinalizationOrigin, FinalizationProject, FinalizationToken,
-    FinalizingRecordings, FinalizingRecordingsMap,
-};
-use cap_recording::{
-    recovery::{PreparingStudioJob, PreparingStudioObserver},
-    studio_recording::CompletedRecording,
-};
-use std::sync::{Arc, Mutex};
-
-#[derive(Clone, Default)]
-pub(super) enum PreparingFinalizationState {
-    #[default]
-    Waiting,
-    Declined,
-    Offered(PreparingStudioObserver),
-}
-
-#[derive(Clone)]
-pub(crate) struct FinalizationPreparing {
-    recordings: Arc>,
-    attempt: Arc,
-}
-
-impl FinalizationToken {
-    pub(crate) fn preparing(&self) -> FinalizationPreparing {
-        FinalizationPreparing {
-            recordings: self.recordings.clone(),
-            attempt: self.attempt.clone(),
-        }
-    }
-}
-
-impl FinalizingRecordings {
-    pub(crate) fn preparing_for_project(
-        &self,
-        project: &FinalizationProject,
-    ) -> Option {
-        let recordings = self.recordings.lock().unwrap();
-        let attempt = recordings.attempts.get(&project.identity)?;
-        if attempt.origin != FinalizationOrigin::Recording || attempt.result.borrow().is_some() {
-            return None;
-        }
-        Some(FinalizationPreparing {
-            recordings: self.recordings.clone(),
-            attempt: attempt.clone(),
-        })
-    }
-}
-
-impl FinalizationPreparing {
-    pub(crate) fn allows_preparing_continuation(&self) -> bool {
-        let recordings = self.recordings.lock().unwrap();
-        self.attempt.origin == FinalizationOrigin::Recording
-            && recordings
-                .attempts
-                .get(&self.attempt.project.identity)
-                .map_or_else(
-                    || matches!(&*self.attempt.result.borrow(), Some(Ok(()))),
-                    |current| Arc::ptr_eq(current, &self.attempt),
-                )
-            && self
-                .attempt
-                .result
-                .borrow()
-                .as_ref()
-                .is_none_or(Result::is_ok)
-            && matches!(&*self.attempt.preparing.borrow(), PreparingFinalizationState::Offered(observer) if observer.publication_succeeded())
-    }
-
-    pub(crate) fn is_pending(&self) -> bool {
-        self.is_current(&self.recordings.lock().unwrap())
-    }
-
-    pub(crate) fn set_presentation(
-        &self,
-        presentation: Result,
-    ) {
-        let recordings = self.recordings.lock().unwrap();
-        if self.is_current(&recordings) {
-            self.attempt
-                .preparing_presentation
-                .send_if_modified(|state| {
-                    if state.is_some() {
-                        return false;
-                    }
-                    *state = Some(presentation.map(Arc::new));
-                    true
-                });
-        }
-    }
-
-    pub(crate) async fn wait_for_presentation(
-        &self,
-    ) -> Option> {
-        let mut presentation = self.attempt.preparing_presentation.subscribe();
-        let mut result = self.attempt.result.subscribe();
-        loop {
-            let state = {
-                let recordings = self.recordings.lock().unwrap();
-                if !self.is_current(&recordings) {
-                    return None;
-                }
-                presentation.borrow_and_update().clone()
-            };
-            if let Some(state) = state {
-                return state.ok();
-            }
-            tokio::select! {
-                changed = presentation.changed() => if changed.is_err() { return None; },
-                changed = result.changed() => if changed.is_err() { return None; },
-            }
-        }
-    }
-
-    #[cfg(test)]
-    fn same_attempt(&self, other: &Self) -> bool {
-        Arc::ptr_eq(&self.attempt, &other.attempt)
-    }
-
-    fn is_current(&self, recordings: &FinalizingRecordingsMap) -> bool {
-        self.attempt.origin == FinalizationOrigin::Recording
-            && recordings
-                .attempts
-                .get(&self.attempt.project.identity)
-                .is_some_and(|current| Arc::ptr_eq(current, &self.attempt))
-            && self.attempt.result.borrow().is_none()
-    }
-
-    pub(crate) fn claim(&self, completed: &CompletedRecording) -> Option {
-        self.claim_with(completed, PreparingStudioJob::claim)
-    }
-
-    fn claim_with(
-        &self,
-        completed: &CompletedRecording,
-        claim: impl FnOnce(
-            &CompletedRecording,
-            u64,
-        ) -> Option<(PreparingStudioJob, PreparingStudioObserver)>,
-    ) -> Option {
-        let paths_match = completed.project_path == self.attempt.project.display_path()
-            && self.attempt.project.display_path() == self.attempt.project.work_path();
-        let directory_valid = paths_match
-            && self.attempt.preparing_generation.is_some()
-            && self.attempt.project.validate().is_ok();
-        let recordings = self.recordings.lock().unwrap();
-        if !self.is_current(&recordings) {
-            return None;
-        }
-        let mut job = None;
-        self.attempt.preparing.send_if_modified(|state| {
-            if !matches!(state, PreparingFinalizationState::Waiting) {
-                return false;
-            }
-            *state = PreparingFinalizationState::Declined;
-            if directory_valid
-                && let Some(generation) = self.attempt.preparing_generation
-                && let Some((claimed, observer)) = claim(completed, generation)
-            {
-                job = Some(claimed);
-                *state = PreparingFinalizationState::Offered(observer);
-            }
-            true
-        });
-        job
-    }
-
-    pub(crate) async fn wait_for_preparing(&self) -> Option {
-        let mut preparing = self.attempt.preparing.subscribe();
-        let mut result = self.attempt.result.subscribe();
-        loop {
-            let state = {
-                let recordings = self.recordings.lock().unwrap();
-                if !self.is_current(&recordings) {
-                    return None;
-                }
-                preparing.borrow_and_update().clone()
-            };
-            match state {
-                PreparingFinalizationState::Waiting => {}
-                PreparingFinalizationState::Declined => return None,
-                PreparingFinalizationState::Offered(observer) => return Some(observer),
-            }
-            tokio::select! {
-                changed = preparing.changed() => if changed.is_err() { return None; },
-                changed = result.changed() => if changed.is_err() { return None; },
-            }
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use crate::{FinalizationAccess, await_finalization_result, has_pending_finalizations};
-    use cap_project::RecordingMeta;
-    use std::path::Path;
-    use std::time::Duration;
-
-    fn project() -> (tempfile::TempDir, Arc) {
-        let directory = tempfile::tempdir().unwrap();
-        let project = FinalizationProject::capture(
-            directory.path().canonicalize().unwrap(),
-            FinalizationAccess::Write,
-        )
-        .unwrap();
-        (directory, project)
-    }
-
-    async fn wait_for_preparing(
-        preparing: &FinalizationPreparing,
-    ) -> Option {
-        tokio::time::timeout(Duration::from_secs(1), preparing.wait_for_preparing())
-            .await
-            .unwrap()
-    }
-
-    fn completed_without_receipt(path: &Path) -> CompletedRecording {
-        let metadata: RecordingMeta = serde_json::from_value(serde_json::json!({
-            "pretty_name": "Preparing finalization test", "sharing": null,
-            "segments": [{"display": {"path": "content/segments/segment-0/display", "fps": 30}}],
-            "status": {"status": "NeedsRemux"}
-        }))
-        .unwrap();
-        CompletedRecording {
-            project_path: path.to_path_buf(),
-            meta: metadata.studio_meta().unwrap().clone(),
-            cursor_data: Default::default(),
-            clean_stopped: None,
-        }
-    }
-
-    #[tokio::test]
-    async fn declined_receipt_is_not_finalization_success() {
-        let (_directory, project) = project();
-        let recordings = FinalizingRecordings::default();
-        let token = recordings.start_finalizing(project.clone()).unwrap();
-        let preparing = recordings.preparing_for_project(&project).unwrap();
-        assert!(preparing.same_attempt(&token.preparing()));
-        assert!(
-            preparing
-                .claim(&completed_without_receipt(project.display_path()))
-                .is_none()
-        );
-        assert!(wait_for_preparing(&preparing).await.is_none());
-        assert!(has_pending_finalizations(
-            &recordings.recordings.lock().unwrap()
-        ));
-        let result = token.attempt.result.subscribe();
-        token.finish(Err("configuration write failed".into()));
-        assert!(
-            await_finalization_result(result)
-                .await
-                .unwrap_err()
-                .contains("configuration write failed")
-        );
-        assert!(recordings.preparing_for_project(&project).is_none());
-    }
-
-    #[tokio::test]
-    async fn completion_before_admission_does_not_invoke_claim() {
-        let (_directory, project) = project();
-        let recordings = FinalizingRecordings::default();
-        let token = recordings.start_finalizing(project.clone()).unwrap();
-        let preparing = token.preparing();
-        token.finish(Ok(()));
-        assert!(
-            preparing
-                .claim_with(
-                    &completed_without_receipt(project.display_path()),
-                    |_, _| panic!("Completed attempts cannot claim")
-                )
-                .is_none()
-        );
-        assert!(wait_for_preparing(&preparing).await.is_none());
-        assert!(!has_pending_finalizations(
-            &recordings.recordings.lock().unwrap()
-        ));
-    }
-
-    #[tokio::test]
-    async fn failed_retry_has_a_new_attempt_and_rejects_stale_claims() {
-        let (_directory, project) = project();
-        let recordings = FinalizingRecordings::default();
-        let first = recordings.start_finalizing(project.clone()).unwrap();
-        assert_eq!(first.attempt.preparing_generation, Some(1));
-        let stale = first.preparing();
-        first.finish(Err("first failure".into()));
-        let second = recordings.start_finalizing(project.clone()).unwrap();
-        assert_eq!(second.attempt.preparing_generation, Some(2));
-        let current = second.preparing();
-        assert!(!stale.same_attempt(¤t));
-        assert!(
-            stale
-                .claim_with(
-                    &completed_without_receipt(project.display_path()),
-                    |_, _| panic!("Stale attempts cannot claim")
-                )
-                .is_none()
-        );
-        assert!(wait_for_preparing(&stale).await.is_none());
-        assert!(
-            tokio::time::timeout(Duration::from_millis(20), current.wait_for_preparing())
-                .await
-                .is_err()
-        );
-        second.finish(Ok(()));
-        assert!(wait_for_preparing(¤t).await.is_none());
-    }
-
-    #[tokio::test]
-    async fn token_drop_wakes_pending_observer_and_preserves_interrupted_error() {
-        let (_directory, project) = project();
-        let recordings = FinalizingRecordings::default();
-        let token = recordings.start_finalizing(project).unwrap();
-        let preparing = token.preparing();
-        let result = token.attempt.result.subscribe();
-        assert!(
-            tokio::time::timeout(Duration::from_millis(20), preparing.wait_for_preparing())
-                .await
-                .is_err()
-        );
-        drop(token);
-        assert!(
-            tokio::time::timeout(Duration::from_secs(1), preparing.wait_for_preparing())
-                .await
-                .unwrap()
-                .is_none()
-        );
-        assert!(
-            await_finalization_result(result)
-                .await
-                .unwrap_err()
-                .contains("interrupted")
-        );
-    }
-
-    #[test]
-    fn native_recording_attempt_allocates_generation_without_capture_coordinator() {
-        let (_directory, project) = project();
-        let recordings = FinalizingRecordings::default();
-        let token = recordings.start_finalizing(project.clone()).unwrap();
-        let preparing = token.preparing();
-        let clone = preparing.clone();
-        let completed = completed_without_receipt(project.display_path());
-        let called = std::cell::Cell::new(false);
-        assert!(
-            preparing
-                .claim_with(&completed, |actual, generation| {
-                    called.set(true);
-                    assert_eq!(actual.project_path, project.display_path());
-                    assert_eq!(generation, 1);
-                    None
-                })
-                .is_none()
-        );
-        assert!(called.get());
-        assert!(
-            clone
-                .claim_with(&completed, |_, _| panic!(
-                    "Duplicate admission cannot claim"
-                ))
-                .is_none()
-        );
-        assert!(token.attempt.result.borrow().is_none());
-        token.finish(Ok(()));
-    }
-
-    #[test]
-    fn lazy_open_and_recovery_origin_never_allocate_or_invoke_claim() {
-        let (_directory, project) = project();
-        for (origin, preparing_requested) in [
-            (FinalizationOrigin::Recording, false),
-            (FinalizationOrigin::Recovery, true),
-        ] {
-            let recordings = FinalizingRecordings::default();
-            let token = recordings
-                .start_with_origin(project.clone(), origin, preparing_requested)
-                .unwrap();
-            assert!(
-                token
-                    .preparing()
-                    .claim_with(
-                        &completed_without_receipt(project.display_path()),
-                        |_, _| panic!("Ineligible finalization cannot claim")
-                    )
-                    .is_none()
-            );
-            assert_eq!(
-                recordings
-                    .recordings
-                    .lock()
-                    .unwrap()
-                    .last_preparing_generation,
-                0
-            );
-            if origin == FinalizationOrigin::Recovery {
-                assert!(recordings.preparing_for_project(&project).is_none());
-            }
-            token.finish(Ok(()));
-        }
-    }
-
-    #[test]
-    fn duplicate_finalization_keeps_the_original_attempt_generation() {
-        let (_directory, project) = project();
-        let recordings = FinalizingRecordings::default();
-        let first = recordings.start_finalizing(project.clone()).unwrap();
-        assert!(recordings.start_finalizing(project.clone()).is_err());
-        let existing = recordings
-            .request(project.clone(), false, FinalizationOrigin::Recording, false)
-            .unwrap();
-        assert!(matches!(existing, crate::FinalizationRequest::Existing(_)));
-        assert_eq!(first.attempt.preparing_generation, Some(1));
-        assert_eq!(
-            recordings
-                .recordings
-                .lock()
-                .unwrap()
-                .last_preparing_generation,
-            1
-        );
-        assert!(
-            first
-                .preparing()
-                .same_attempt(&recordings.preparing_for_project(&project).unwrap())
-        );
-        first.finish(Err("retained retry".into()));
-        let next = recordings.start_finalizing(project).unwrap();
-        assert_eq!(next.attempt.preparing_generation, Some(2));
-        next.finish(Ok(()));
-    }
-
-    #[tokio::test]
-    async fn generation_exhaustion_declines_preview_and_preserves_finalization() {
-        let (_directory, project) = project();
-        let recordings = FinalizingRecordings::default();
-        recordings
-            .recordings
-            .lock()
-            .unwrap()
-            .last_preparing_generation = u64::MAX - 1;
-        let last = recordings.start_finalizing(project.clone()).unwrap();
-        assert_eq!(last.attempt.preparing_generation, Some(u64::MAX));
-        last.finish(Err("retained retry".into()));
-        let exhausted = recordings.start_finalizing(project.clone()).unwrap();
-        assert_eq!(exhausted.attempt.preparing_generation, None);
-        assert_eq!(
-            recordings
-                .recordings
-                .lock()
-                .unwrap()
-                .last_preparing_generation,
-            u64::MAX
-        );
-        let preparing = exhausted.preparing();
-        assert!(
-            preparing
-                .claim_with(
-                    &completed_without_receipt(project.display_path()),
-                    |_, _| { panic!("An exhausted sequence cannot claim") }
-                )
-                .is_none()
-        );
-        assert!(wait_for_preparing(&preparing).await.is_none());
-        assert!(has_pending_finalizations(
-            &recordings.recordings.lock().unwrap()
-        ));
-        let result = exhausted.attempt.result.subscribe();
-        exhausted.finish(Ok(()));
-        assert_eq!(await_finalization_result(result).await, Ok(()));
-        assert!(!has_pending_finalizations(
-            &recordings.recordings.lock().unwrap()
-        ));
-    }
-
-    #[test]
-    fn a_different_stopped_project_never_invokes_claim() {
-        let (_directory, project) = project();
-        let other = tempfile::tempdir().unwrap();
-        let recordings = FinalizingRecordings::default();
-        let token = recordings.start_finalizing(project).unwrap();
-        assert!(
-            token
-                .preparing()
-                .claim_with(&completed_without_receipt(other.path()), |_, _| panic!(
-                    "Wrong project cannot claim"
-                ))
-                .is_none()
-        );
-        token.finish(Ok(()));
-    }
-
-    #[test]
-    fn canonical_alias_declines_without_rewriting_the_stopped_path() {
-        let directory = tempfile::tempdir().unwrap();
-        std::fs::create_dir(directory.path().join("alias")).unwrap();
-        std::fs::create_dir(directory.path().join("project")).unwrap();
-        let display = directory.path().join("alias/../project");
-        let project =
-            FinalizationProject::capture(display.clone(), FinalizationAccess::Write).unwrap();
-        assert_ne!(project.display_path(), project.work_path());
-        let recordings = FinalizingRecordings::default();
-        let token = recordings.start_finalizing(project).unwrap();
-        let completed = completed_without_receipt(&display);
-        assert!(
-            token
-                .preparing()
-                .claim_with(&completed, |_, _| panic!(
-                    "Alias must not rebind a clean receipt"
-                ))
-                .is_none()
-        );
-        assert_eq!(completed.project_path, display);
-        token.finish(Ok(()));
-    }
-
-    #[test]
-    fn replaced_directory_declines_before_claim() {
-        let directory = tempfile::tempdir().unwrap();
-        let original = directory.path().join("project");
-        let moved = directory.path().join("moved");
-        std::fs::create_dir(&original).unwrap();
-        let project = FinalizationProject::capture(
-            original.canonicalize().unwrap(),
-            FinalizationAccess::Write,
-        )
-        .unwrap();
-        let recordings = FinalizingRecordings::default();
-        let token = recordings.start_finalizing(project.clone()).unwrap();
-        std::fs::rename(&original, &moved).unwrap();
-        std::fs::create_dir(&original).unwrap();
-        assert!(
-            token
-                .preparing()
-                .claim_with(
-                    &completed_without_receipt(project.display_path()),
-                    |_, _| panic!("Replaced directory cannot claim")
-                )
-                .is_none()
-        );
-        assert!(token.attempt.result.borrow().is_none());
-        token.finish(Err("directory replaced".into()));
-    }
-
-    #[tokio::test]
-    async fn missing_fragments_keep_the_existing_error_and_do_not_claim() {
-        let (_directory, project) = project();
-        let sentinel = project.work_path().join("retained-original.bin");
-        std::fs::write(&sentinel, b"retain original bytes").unwrap();
-        let completed = completed_without_receipt(project.display_path());
-        let recordings = FinalizingRecordings::default();
-        let token = recordings.start_finalizing(project.clone()).unwrap();
-        let preparing = token.preparing();
-        let ordinary = crate::recording::remux_fragmented_recording_with_trigger(
-            project.work_path(),
-            project.display_path(),
-            "recording_stop",
-            None,
-        );
-        let candidate = crate::recording::remux_fragmented_recording_with_preparing(
-            project.work_path(),
-            project.display_path(),
-            "recording_stop",
-            None,
-            Some((&preparing, &completed)),
-        );
-        assert_eq!(candidate, ordinary);
-        assert_eq!(
-            candidate.as_ref().unwrap_err(),
-            "Could not find fragments to remux"
-        );
-        assert!(matches!(
-            *token.attempt.preparing.borrow(),
-            PreparingFinalizationState::Waiting
-        ));
-        assert_eq!(std::fs::read(sentinel).unwrap(), b"retain original bytes");
-        assert!(
-            !project
-                .work_path()
-                .join(crate::recording::FRAGMENTED_EXPORT_FFMPEG_MARKER)
-                .exists()
-        );
-        token.finish(candidate);
-        assert!(wait_for_preparing(&preparing).await.is_none());
-    }
-}
diff --git a/apps/desktop/src-tauri/src/presets.rs b/apps/desktop/src-tauri/src/presets.rs
deleted file mode 100644
index c3d8d2f3c8c..00000000000
--- a/apps/desktop/src-tauri/src/presets.rs
+++ /dev/null
@@ -1,88 +0,0 @@
-use cap_project::{ProjectConfiguration, TimelineConfiguration};
-use serde::{Deserialize, Serialize};
-use serde_json::json;
-use specta::Type;
-use tauri::{AppHandle, Wry};
-use tauri_plugin_store::StoreExt;
-use tracing::error;
-
-#[derive(Serialize, Deserialize, Type, Debug, Default)]
-#[serde(rename_all = "camelCase")]
-pub struct PresetsStore {
-    presets: Vec,
-    default: Option,
-}
-
-#[derive(Serialize, Deserialize, Type, Debug, Clone)]
-#[serde(rename_all = "camelCase")]
-pub struct Preset {
-    name: String,
-    pub config: ProjectConfiguration,
-}
-
-impl PresetsStore {
-    fn get(app: &AppHandle) -> Result, String> {
-        match app.store("store").map(|s| s.get("presets")) {
-            Ok(Some(store)) => match serde_json::from_value(store.clone()) {
-                Ok(settings) => Ok(Some(settings)),
-                Err(e) => {
-                    error!(
-                        "Failed to deserialize presets store: {}. Raw value: {}",
-                        e,
-                        serde_json::to_string_pretty(&store).unwrap_or_default()
-                    );
-                    Ok(None)
-                }
-            },
-            _ => Ok(None),
-        }
-    }
-
-    pub fn clear(app: &AppHandle) -> Result<(), String> {
-        let store = app.store("store").map_err(|e| e.to_string())?;
-        store.delete("presets");
-        store.save().map_err(|e| e.to_string())?;
-        Ok(())
-    }
-
-    pub fn get_default_preset(app: &AppHandle) -> Result, String> {
-        let Some(this) = Self::get(app)? else {
-            return Ok(None);
-        };
-
-        let Some(default_i) = this.default else {
-            return Ok(None);
-        };
-
-        Ok(this.presets.get(default_i as usize).cloned())
-    }
-
-    pub fn get_by_name(app: &AppHandle, name: &str) -> Result, String> {
-        let Some(this) = Self::get(app)? else {
-            return Ok(None);
-        };
-
-        Ok(this.presets.into_iter().find(|p| p.name == name))
-    }
-
-    #[allow(unused)]
-    pub fn update(app: &AppHandle, update: impl FnOnce(&mut Self)) -> Result<(), String> {
-        let Ok(store) = app.store("store") else {
-            return Err("Store not found".to_string());
-        };
-
-        let mut settings = Self::get(app)?.unwrap_or_default();
-        update(&mut settings);
-        store.set("presets", json!(settings));
-        store.save().map_err(|e| e.to_string())
-    }
-}
-
-impl Preset {
-    #[allow(unused)]
-    fn resolve(&self, timeline: TimelineConfiguration) -> ProjectConfiguration {
-        let mut ret = self.config.clone();
-        ret.timeline = Some(timeline);
-        ret
-    }
-}
diff --git a/apps/desktop/src-tauri/src/recording.rs b/apps/desktop/src-tauri/src/recording.rs
deleted file mode 100644
index 03b8a1d9447..00000000000
--- a/apps/desktop/src-tauri/src/recording.rs
+++ /dev/null
@@ -1,10476 +0,0 @@
-use anyhow::anyhow;
-use cap_fail::fail;
-use cap_media_info::ffmpeg_sample_format_for;
-use cap_project::CursorMoveEvent;
-use cap_project::cursor::SHORT_CURSOR_SHAPE_DEBOUNCE_MS;
-use cap_project::{
-    CameraShape, CornerStyle, CursorClickEvent, GlideDirection, InstantRecordingMeta,
-    MultipleSegments, Platform, ProjectConfiguration, RecordingMeta, RecordingMetaInner,
-    SharingMeta, StudioRecordingMeta, StudioRecordingStatus, TimelineConfiguration,
-    TimelineSegment, ZoomMode, ZoomSegment, cursor::CursorEvents,
-};
-#[cfg(target_os = "macos")]
-use cap_recording::SendableShareableContent;
-use cap_recording::feeds::camera::CameraFeedLock;
-#[cfg(target_os = "macos")]
-use cap_recording::sources::screen_capture::SourceError;
-use cap_recording::{
-    RecordingMode,
-    feeds::{camera, microphone},
-    instant_recording,
-    recovery::RecoveryManager,
-    sources::MicrophoneSourceError,
-    sources::{
-        screen_capture,
-        screen_capture::{CaptureDisplay, CaptureWindow, ScreenCaptureTarget},
-    },
-    studio_recording,
-};
-use cap_rendering::ProjectRecordingsMeta;
-use cap_utils::{ensure_dir, moment_format_to_chrono, spawn_actor};
-use cpal::traits::DeviceTrait;
-use futures::{FutureExt, stream};
-use lazy_static::lazy_static;
-use regex::Regex;
-use serde::{Deserialize, Serialize};
-use specta::Type;
-use std::borrow::Cow;
-#[cfg(target_os = "macos")]
-use std::error::Error as StdError;
-use std::{
-    any::Any,
-    collections::BTreeSet,
-    panic::AssertUnwindSafe,
-    path::{Path, PathBuf},
-    str::FromStr,
-    sync::Arc,
-    time::Duration,
-};
-use tauri::{AppHandle, Listener, Manager, path::BaseDirectory};
-use tauri_plugin_dialog::{
-    DialogExt, MessageDialogBuilder, MessageDialogButtons, MessageDialogKind,
-};
-use tauri_plugin_store::StoreExt;
-use tauri_specta::Event;
-use tokio_util::sync::CancellationToken;
-use tracing::*;
-
-use crate::camera::CameraPreviewShape;
-#[cfg(target_os = "macos")]
-use crate::general_settings;
-use crate::permissions;
-use crate::web_api::AuthedApiError;
-#[cfg(target_os = "macos")]
-use crate::window_exclusion::WindowExclusion;
-use crate::{
-    App, CameraWindowOperationLock, CurrentRecordingChanged, EditorRecordingAdded,
-    FinalizingRecordings, MutableState, NewStudioRecordingAdded, RecordingStarted, RecordingState,
-    RecordingStopped, VideoUploadInfo,
-    api::PresignedS3PutRequestMethod,
-    audio::AppSounds,
-    auth::AuthStore,
-    create_screenshot, create_screenshot_source_from_segments,
-    general_settings::{GeneralSettingsStore, PostDeletionBehaviour, PostStudioRecordingBehaviour},
-    open_external_link,
-    presets::PresetsStore,
-    thumbnails::*,
-    upload::{SegmentUploader, compress_image},
-    web_api::ManagerExt,
-    windows::{
-        CapWindowId, EditorRecordingTarget, ShowCapWindow, editor_window_for_path, hide_overlay,
-    },
-};
-
-#[cfg(not(target_os = "linux"))]
-use crate::upload::InstantMultipartUpload;
-
-fn recording_stopped_share_url(link: &str) -> String {
-    if link.contains('?') {
-        format!("{link}&recordingStopped=1")
-    } else {
-        format!("{link}?recordingStopped=1")
-    }
-}
-
-const CURRENT_DESKTOP_BACKGROUND_BASENAME: &str = "current-desktop-background";
-const CURRENT_DESKTOP_BACKGROUND_FILENAME: &str = "current-desktop-background.jpg";
-const CURRENT_DESKTOP_BACKGROUND_PENDING_FILENAME: &str = "current-desktop-background.pending.jpg";
-const DESKTOP_BACKGROUND_MAX_DIMENSION: u32 = 2560;
-const DESKTOP_BACKGROUND_JPEG_QUALITY: u8 = 82;
-
-fn current_desktop_background_snapshot_path(recording_dir: &Path) -> PathBuf {
-    recording_dir
-        .join("assets")
-        .join(CURRENT_DESKTOP_BACKGROUND_FILENAME)
-}
-
-fn stored_current_desktop_background_path(recording_dir: &Path) -> Option {
-    let path = current_desktop_background_snapshot_path(recording_dir);
-    path.exists().then(|| path.to_string_lossy().into_owned())
-}
-
-fn pending_current_desktop_background_snapshot_path(recording_dir: &Path) -> PathBuf {
-    recording_dir
-        .join("assets")
-        .join(CURRENT_DESKTOP_BACKGROUND_PENDING_FILENAME)
-}
-
-fn spawn_current_desktop_background_snapshot(
-    recording_dir: PathBuf,
-    capture_target: ScreenCaptureTarget,
-) {
-    if matches!(capture_target, ScreenCaptureTarget::CameraOnly) {
-        return;
-    }
-
-    tokio::spawn(async move {
-        match store_current_desktop_background_snapshot(recording_dir, capture_target).await {
-            Ok(CurrentDesktopBackgroundSnapshot::Stored(path)) => debug!(
-                path = %path.display(),
-                "Stored current desktop background for recording"
-            ),
-            Ok(CurrentDesktopBackgroundSnapshot::SkippedProtectedLocation(path)) => debug!(
-                path = %path.display(),
-                "Skipped current desktop background from protected location"
-            ),
-            Err(reason) => debug!(
-                %reason,
-                "Current desktop background snapshot unavailable"
-            ),
-        }
-    });
-}
-
-enum CurrentDesktopBackgroundSnapshot {
-    Stored(PathBuf),
-    SkippedProtectedLocation(PathBuf),
-}
-
-enum CurrentDesktopBackgroundWrite {
-    Stored,
-    SkippedProtectedLocation(PathBuf),
-}
-
-async fn store_current_desktop_background_snapshot(
-    recording_dir: PathBuf,
-    capture_target: ScreenCaptureTarget,
-) -> Result {
-    let display_id = capture_target
-        .display()
-        .map(|display| display.id().to_string());
-
-    tokio::task::spawn_blocking(move || {
-        let output_path = current_desktop_background_snapshot_path(&recording_dir);
-        let pending_path = pending_current_desktop_background_snapshot_path(&recording_dir);
-        write_current_desktop_background_to(
-            &output_path,
-            &pending_path,
-            display_id.as_deref(),
-            true,
-        )
-        .map(|result| match result {
-            CurrentDesktopBackgroundWrite::Stored => {
-                CurrentDesktopBackgroundSnapshot::Stored(output_path)
-            }
-            CurrentDesktopBackgroundWrite::SkippedProtectedLocation(path) => {
-                CurrentDesktopBackgroundSnapshot::SkippedProtectedLocation(path)
-            }
-        })
-    })
-    .await
-    .map_err(|err| format!("Desktop background snapshot task failed: {err}"))?
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument]
-pub async fn import_current_desktop_background(project_path: String) -> Result {
-    let project_dir = PathBuf::from(project_path);
-
-    tokio::task::spawn_blocking(move || {
-        let source_path = current_desktop_background_source_path(None)
-            .ok_or_else(|| "Current desktop background path not found".to_string())?;
-        import_current_desktop_background_from_source(&project_dir, &source_path)
-    })
-    .await
-    .map_err(|err| format!("Desktop background snapshot task failed: {err}"))?
-}
-
-fn import_current_desktop_background_from_source(
-    project_dir: &Path,
-    source_path: &Path,
-) -> Result {
-    let assets_dir = project_dir.join("assets");
-    let timestamp = std::time::SystemTime::now()
-        .duration_since(std::time::UNIX_EPOCH)
-        .map(|elapsed| elapsed.as_nanos())
-        .unwrap_or(0);
-    let output_name = format!("{CURRENT_DESKTOP_BACKGROUND_BASENAME}-{timestamp}.jpg");
-    let output_path = assets_dir.join(&output_name);
-    let pending_path = assets_dir.join(format!(
-        "{CURRENT_DESKTOP_BACKGROUND_BASENAME}-{timestamp}.pending.jpg"
-    ));
-
-    if !matches!(
-        write_desktop_background_source_to(source_path, &output_path, &pending_path)?,
-        CurrentDesktopBackgroundWrite::Stored
-    ) {
-        return Err("Current desktop background snapshot was skipped".to_string());
-    }
-
-    Ok(output_path.to_string_lossy().into_owned())
-}
-
-fn write_current_desktop_background_to(
-    output_path: &Path,
-    pending_path: &Path,
-    display_id: Option<&str>,
-    enforce_protected_check: bool,
-) -> Result {
-    let source_path = current_desktop_background_source_path(display_id)
-        .ok_or_else(|| "Current desktop background path not found".to_string())?;
-
-    if enforce_protected_check && desktop_background_source_requires_user_prompt(&source_path) {
-        return Ok(CurrentDesktopBackgroundWrite::SkippedProtectedLocation(
-            source_path,
-        ));
-    }
-
-    write_desktop_background_source_to(&source_path, output_path, pending_path)
-}
-
-fn write_desktop_background_source_to(
-    source_path: &Path,
-    output_path: &Path,
-    pending_path: &Path,
-) -> Result {
-    if !source_path.exists() {
-        return Err(format!(
-            "Current desktop background does not exist: {}",
-            source_path.display()
-        ));
-    }
-
-    if let Some(parent) = output_path.parent() {
-        std::fs::create_dir_all(parent)
-            .map_err(|err| format!("Failed to create background assets directory: {err}"))?;
-    }
-
-    let _ = std::fs::remove_file(pending_path);
-    if let Err(error) = write_desktop_background_snapshot(source_path, pending_path) {
-        let _ = std::fs::remove_file(pending_path);
-        return Err(error);
-    }
-
-    if output_path.exists() {
-        std::fs::remove_file(output_path)
-            .map_err(|err| format!("Failed to replace current desktop background: {err}"))?;
-    }
-
-    std::fs::rename(pending_path, output_path)
-        .map_err(|err| format!("Failed to store current desktop background: {err}"))?;
-
-    Ok(CurrentDesktopBackgroundWrite::Stored)
-}
-
-#[cfg(target_os = "macos")]
-fn current_desktop_background_source_path(display_id: Option<&str>) -> Option {
-    use cocoa::appkit::NSScreen;
-    use cocoa::base::{id, nil};
-    use cocoa::foundation::NSString;
-    use objc::{class, msg_send, sel, sel_impl};
-    use std::ffi::CStr;
-
-    unsafe {
-        let screen =
-            macos_screen_for_display_id(display_id).unwrap_or_else(|| NSScreen::mainScreen(nil));
-        if screen == nil {
-            return None;
-        }
-
-        let workspace: id = msg_send![class!(NSWorkspace), sharedWorkspace];
-        if workspace == nil {
-            return None;
-        }
-
-        let url: id = msg_send![workspace, desktopImageURLForScreen: screen];
-        if url == nil {
-            return None;
-        }
-
-        let path: id = msg_send![url, path];
-        if path == nil {
-            return None;
-        }
-
-        let path = CStr::from_ptr(NSString::UTF8String(path))
-            .to_string_lossy()
-            .to_string();
-        (!path.is_empty()).then(|| PathBuf::from(path))
-    }
-}
-
-#[cfg(target_os = "macos")]
-fn macos_screen_for_display_id(display_id: Option<&str>) -> Option {
-    use cocoa::appkit::NSScreen;
-    use cocoa::base::{id, nil};
-    use cocoa::foundation::{NSArray, NSDictionary, NSString};
-    use objc::{msg_send, sel, sel_impl};
-
-    let expected_id = display_id?.parse::().ok()?;
-
-    unsafe {
-        let screens = NSScreen::screens(nil);
-        if screens == nil {
-            return None;
-        }
-
-        let screen_number_key = NSString::alloc(nil).init_str("NSScreenNumber");
-        for index in 0..NSArray::count(screens) {
-            let screen: id = screens.objectAtIndex(index);
-            if screen == nil {
-                continue;
-            }
-
-            let device_description = NSScreen::deviceDescription(screen);
-            let number = NSDictionary::valueForKey_(device_description, screen_number_key) as id;
-            if number == nil {
-                continue;
-            }
-
-            let number_value: u32 = msg_send![number, unsignedIntValue];
-            if number_value == expected_id {
-                return Some(screen);
-            }
-        }
-    }
-
-    None
-}
-
-#[cfg(target_os = "windows")]
-fn current_desktop_background_source_path(_display_id: Option<&str>) -> Option {
-    use std::{ffi::OsString, os::windows::ffi::OsStringExt};
-    use windows::Win32::UI::WindowsAndMessaging::{
-        SPI_GETDESKWALLPAPER, SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS, SystemParametersInfoW,
-    };
-
-    let mut buffer = vec![0u16; 32_768];
-    unsafe {
-        SystemParametersInfoW(
-            SPI_GETDESKWALLPAPER,
-            u32::try_from(buffer.len()).ok()?,
-            Some(buffer.as_mut_ptr().cast()),
-            SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS(0),
-        )
-        .ok()?;
-    }
-
-    let len = buffer
-        .iter()
-        .position(|character| *character == 0)
-        .unwrap_or(buffer.len());
-    (len > 0).then(|| PathBuf::from(OsString::from_wide(&buffer[..len])))
-}
-
-#[cfg(not(any(target_os = "macos", target_os = "windows")))]
-fn current_desktop_background_source_path(_display_id: Option<&str>) -> Option {
-    None
-}
-
-fn desktop_background_source_requires_user_prompt(source_path: &Path) -> bool {
-    #[cfg(target_os = "macos")]
-    {
-        dirs::home_dir().is_some_and(|home_dir| {
-            desktop_background_source_requires_user_prompt_for_home(source_path, &home_dir)
-        })
-    }
-
-    #[cfg(not(target_os = "macos"))]
-    {
-        let _ = source_path;
-        false
-    }
-}
-
-#[cfg(any(target_os = "macos", test))]
-fn desktop_background_source_requires_user_prompt_for_home(
-    source_path: &Path,
-    home_dir: &Path,
-) -> bool {
-    [
-        home_dir.join("Desktop"),
-        home_dir.join("Documents"),
-        home_dir.join("Downloads"),
-        home_dir.join("Library/Mobile Documents"),
-        home_dir.join("Library/CloudStorage"),
-    ]
-    .iter()
-    .any(|protected_dir| source_path.starts_with(protected_dir))
-}
-
-#[cfg(target_os = "macos")]
-fn macos_image_pixel_dimensions(path: &Path) -> Option<(u32, u32)> {
-    let output = std::process::Command::new("sips")
-        .arg("-g")
-        .arg("pixelWidth")
-        .arg("-g")
-        .arg("pixelHeight")
-        .arg(path)
-        .output()
-        .ok()?;
-
-    if !output.status.success() {
-        return None;
-    }
-
-    let text = String::from_utf8_lossy(&output.stdout);
-    let mut width = None;
-    let mut height = None;
-    for line in text.lines() {
-        let line = line.trim();
-        if let Some(value) = line.strip_prefix("pixelWidth:") {
-            width = value.trim().parse::().ok();
-        } else if let Some(value) = line.strip_prefix("pixelHeight:") {
-            height = value.trim().parse::().ok();
-        }
-    }
-
-    Some((width?, height?))
-}
-
-#[cfg(target_os = "macos")]
-fn write_desktop_background_snapshot(source_path: &Path, output_path: &Path) -> Result<(), String> {
-    // `sips -Z` resizes in both directions, so it upscales sources smaller than the
-    // target. Only cap dimensions when the source actually exceeds the limit.
-    let needs_downscale =
-        macos_image_pixel_dimensions(source_path).is_none_or(|(width, height)| {
-            width > DESKTOP_BACKGROUND_MAX_DIMENSION || height > DESKTOP_BACKGROUND_MAX_DIMENSION
-        });
-
-    let mut command = std::process::Command::new("sips");
-    command
-        .arg("-s")
-        .arg("format")
-        .arg("jpeg")
-        .arg("-s")
-        .arg("formatOptions")
-        .arg(DESKTOP_BACKGROUND_JPEG_QUALITY.to_string());
-
-    if needs_downscale {
-        command
-            .arg("-Z")
-            .arg(DESKTOP_BACKGROUND_MAX_DIMENSION.to_string());
-    }
-
-    let sips_result = command
-        .arg(source_path)
-        .arg("--out")
-        .arg(output_path)
-        .output();
-
-    if let Ok(output) = sips_result
-        && output.status.success()
-    {
-        return Ok(());
-    }
-
-    write_desktop_background_snapshot_with_image_crate(source_path, output_path)
-}
-
-#[cfg(not(target_os = "macos"))]
-fn write_desktop_background_snapshot(source_path: &Path, output_path: &Path) -> Result<(), String> {
-    write_desktop_background_snapshot_with_image_crate(source_path, output_path)
-}
-
-fn write_desktop_background_snapshot_with_image_crate(
-    source_path: &Path,
-    output_path: &Path,
-) -> Result<(), String> {
-    use image::ImageEncoder;
-    use std::io::Write;
-
-    let image = image::open(source_path)
-        .map_err(|err| format!("Failed to decode current desktop background: {err}"))?;
-
-    let image = if image.width() > DESKTOP_BACKGROUND_MAX_DIMENSION
-        || image.height() > DESKTOP_BACKGROUND_MAX_DIMENSION
-    {
-        image.resize(
-            DESKTOP_BACKGROUND_MAX_DIMENSION,
-            DESKTOP_BACKGROUND_MAX_DIMENSION,
-            image::imageops::FilterType::Triangle,
-        )
-    } else {
-        image
-    };
-
-    let rgb = image.to_rgb8();
-    let file = std::fs::File::create(output_path)
-        .map_err(|err| format!("Failed to create current desktop background: {err}"))?;
-    let mut writer = std::io::BufWriter::new(file);
-
-    image::codecs::jpeg::JpegEncoder::new_with_quality(
-        &mut writer,
-        DESKTOP_BACKGROUND_JPEG_QUALITY,
-    )
-    .write_image(
-        rgb.as_raw(),
-        rgb.width(),
-        rgb.height(),
-        image::ExtendedColorType::Rgb8,
-    )
-    .map_err(|err| format!("Failed to save current desktop background: {err}"))?;
-
-    writer
-        .flush()
-        .map_err(|err| format!("Failed to finalize current desktop background: {err}"))
-}
-
-pub fn spawn_heal_oversized_desktop_background_snapshots(recording_dir: PathBuf) {
-    tokio::task::spawn_blocking(move || {
-        heal_oversized_desktop_background_snapshots(&recording_dir);
-    });
-}
-
-fn heal_oversized_desktop_background_snapshots(recording_dir: &Path) {
-    let assets_dir = recording_dir.join("assets");
-    let Ok(entries) = std::fs::read_dir(&assets_dir) else {
-        return;
-    };
-
-    for entry in entries.flatten() {
-        let path = entry.path();
-        let Some(name) = path.file_name().and_then(|name| name.to_str()) else {
-            continue;
-        };
-
-        if !name.starts_with(CURRENT_DESKTOP_BACKGROUND_BASENAME)
-            || name.contains(".pending.")
-            || !name.ends_with(".jpg")
-        {
-            continue;
-        }
-
-        match downscale_background_snapshot_in_place(&path) {
-            Ok(true) => {
-                info!(path = %path.display(), "Recompressed oversized desktop background snapshot")
-            }
-            Ok(false) => {}
-            Err(error) => {
-                debug!(%error, path = %path.display(), "Failed to recompress desktop background snapshot")
-            }
-        }
-    }
-}
-
-fn downscale_background_snapshot_in_place(path: &Path) -> Result {
-    let (width, height) = image::image_dimensions(path)
-        .map_err(|err| format!("Failed to read background dimensions: {err}"))?;
-
-    if width <= DESKTOP_BACKGROUND_MAX_DIMENSION && height <= DESKTOP_BACKGROUND_MAX_DIMENSION {
-        return Ok(false);
-    }
-
-    let pending_path = path.with_extension("pending.jpg");
-    let _ = std::fs::remove_file(&pending_path);
-
-    if let Err(error) = write_desktop_background_snapshot_with_image_crate(path, &pending_path) {
-        let _ = std::fs::remove_file(&pending_path);
-        return Err(error);
-    }
-
-    std::fs::rename(&pending_path, path)
-        .map_err(|err| format!("Failed to replace desktop background snapshot: {err}"))?;
-
-    Ok(true)
-}
-
-#[derive(Clone)]
-pub struct InProgressRecordingCommon {
-    pub target_name: String,
-    pub inputs: StartRecordingInputs,
-    pub recording_dir: PathBuf,
-    pub health: Arc,
-    camera_snapshot: Arc>,
-}
-
-#[cfg(target_os = "linux")]
-type InstantUploader = Arc>;
-#[cfg(not(target_os = "linux"))]
-type InstantUploader = SegmentUploader;
-
-async fn await_instant_upload(
-    upload: InstantUploader,
-) -> Result, String> {
-    #[cfg(target_os = "linux")]
-    {
-        (&mut upload.lock().await.handle)
-            .await
-            .map_err(|error| error.to_string())
-    }
-    #[cfg(not(target_os = "linux"))]
-    {
-        upload.handle.await.map_err(|error| error.to_string())
-    }
-}
-
-pub struct StopFailureContext {
-    pub segment_upload: InstantUploader,
-    pub video_upload_info: VideoUploadInfo,
-}
-
-#[cfg(target_os = "linux")]
-type InstantActorHandle = Arc;
-#[cfg(not(target_os = "linux"))]
-type InstantActorHandle = instant_recording::ActorHandle;
-
-pub enum InProgressRecording {
-    Instant {
-        handle: InstantActorHandle,
-        segment_upload: InstantUploader,
-        video_upload_info: VideoUploadInfo,
-        common: InProgressRecordingCommon,
-        mic_feed: Option>,
-        camera_feed: Option>,
-    },
-    Studio {
-        handle: studio_recording::ActorHandle,
-        common: InProgressRecordingCommon,
-        mic_feed: Option>,
-        camera_feed: Option>,
-    },
-}
-
-#[cfg(target_os = "macos")]
-async fn acquire_shareable_content_for_target(
-    capture_target: &ScreenCaptureTarget,
-) -> anyhow::Result {
-    let mut available_display_ids = Vec::new();
-
-    for attempt in 0..3 {
-        let shareable_content = read_recording_shareable_content().await?;
-        available_display_ids = shareable_content_display_ids(&shareable_content);
-        if !shareable_content_missing_target_display(capture_target, &shareable_content) {
-            return Ok(shareable_content);
-        }
-
-        if attempt < 2 {
-            tokio::time::sleep(Duration::from_millis(150)).await;
-        }
-    }
-
-    let requested_display = capture_target
-        .display()
-        .map(|display| display.id().to_string())
-        .unwrap_or_else(|| "none".to_string());
-
-    Err(anyhow!(
-        "ScreenCaptureKit shareable content missing target display {requested_display}. Available display ids: {available_display_ids:?}"
-    ))
-}
-
-#[cfg(target_os = "macos")]
-async fn read_recording_shareable_content() -> anyhow::Result {
-    let content = cidre::sc::ShareableContent::current()
-        .await
-        .map_err(|e| anyhow!(format!("ReadShareableContent: {e}")))?;
-    if !content.displays().is_empty() {
-        return Ok(SendableShareableContent::from(content));
-    }
-
-    let process_content = cidre::sc::ShareableContent::current_process()
-        .await
-        .map_err(|e| anyhow!(format!("ReadCurrentProcessShareableContent: {e}")))?;
-    if !process_content.displays().is_empty() {
-        return Ok(SendableShareableContent::from(process_content));
-    }
-
-    Ok(SendableShareableContent::from(content))
-}
-
-#[cfg(target_os = "macos")]
-fn shareable_content_display_ids(shareable_content: &SendableShareableContent) -> Vec {
-    shareable_content
-        .retained()
-        .displays()
-        .iter()
-        .map(|display| display.display_id().0.to_string())
-        .collect()
-}
-#[cfg(target_os = "macos")]
-fn shareable_content_missing_target_display(
-    capture_target: &ScreenCaptureTarget,
-    shareable_content: &SendableShareableContent,
-) -> bool {
-    match capture_target.display() {
-        Some(display) => display
-            .raw_handle()
-            .as_sc(shareable_content.retained())
-            .is_none(),
-        None => false,
-    }
-}
-
-#[cfg(target_os = "macos")]
-fn is_shareable_content_error(err: &anyhow::Error) -> bool {
-    err.chain().any(|cause| {
-        let cause: &dyn StdError = cause;
-        if let Some(source_error) = cause.downcast_ref::() {
-            matches!(source_error, SourceError::AsContentFilter)
-        } else {
-            false
-        }
-    })
-}
-
-impl InProgressRecording {
-    pub fn capture_target(&self) -> &ScreenCaptureTarget {
-        match self {
-            Self::Instant { handle, .. } => &handle.capture_target,
-            Self::Studio { handle, .. } => &handle.capture_target,
-        }
-    }
-
-    pub fn inputs(&self) -> &StartRecordingInputs {
-        match self {
-            Self::Instant { common, .. } => &common.inputs,
-            Self::Studio { common, .. } => &common.inputs,
-        }
-    }
-
-    pub fn common(&self) -> &InProgressRecordingCommon {
-        match self {
-            Self::Instant { common, .. } => common,
-            Self::Studio { common, .. } => common,
-        }
-    }
-
-    pub async fn pause(&self) -> anyhow::Result<()> {
-        match self {
-            Self::Instant { handle, .. } => {
-                #[cfg(target_os = "linux")]
-                {
-                    let _ = handle;
-                    Err(anyhow!(
-                        "Instant recordings cannot pause or resume; use Stop"
-                    ))
-                }
-                #[cfg(not(target_os = "linux"))]
-                {
-                    handle.pause().await
-                }
-            }
-            Self::Studio { handle, .. } => handle.pause().await,
-        }
-    }
-
-    pub async fn resume(&self) -> anyhow::Result<()> {
-        match self {
-            Self::Instant { handle, .. } => {
-                #[cfg(target_os = "linux")]
-                {
-                    let _ = handle;
-                    Err(anyhow!(
-                        "Instant recordings cannot pause or resume; use Stop"
-                    ))
-                }
-                #[cfg(not(target_os = "linux"))]
-                {
-                    handle.resume().await
-                }
-            }
-            Self::Studio { handle, .. } => handle.resume().await,
-        }
-    }
-
-    pub async fn is_paused(&self) -> anyhow::Result {
-        match self {
-            Self::Instant { handle, .. } => handle.is_paused().await,
-            Self::Studio { handle, .. } => handle.is_paused().await,
-        }
-    }
-
-    pub fn recording_dir(&self) -> &PathBuf {
-        match self {
-            Self::Instant { common, .. } => &common.recording_dir,
-            Self::Studio { common, .. } => &common.recording_dir,
-        }
-    }
-
-    pub async fn stop(
-        self,
-    ) -> Result)> {
-        match self {
-            Self::Instant {
-                handle,
-                segment_upload,
-                video_upload_info,
-                common,
-                ..
-            } => match handle.stop().await {
-                Ok(recording) => Ok(CompletedRecording::Instant {
-                    #[cfg(target_os = "linux")]
-                    finalized: false,
-                    recording,
-                    segment_upload,
-                    video_upload_info,
-                    target_name: common.target_name,
-                }),
-                Err(e) => Err((
-                    e,
-                    Some(StopFailureContext {
-                        segment_upload,
-                        video_upload_info,
-                    }),
-                )),
-            },
-            Self::Studio { handle, common, .. } => match handle.stop().await {
-                Ok(recording) => Ok(CompletedRecording::Studio {
-                    recording,
-                    target_name: common.target_name,
-                    capture_target: common.inputs.capture_target,
-                }),
-                Err(e) => Err((e, None)),
-            },
-        }
-    }
-
-    pub fn done_fut(&self) -> cap_recording::DoneFut {
-        match self {
-            Self::Instant { handle, .. } => handle.done_fut(),
-            Self::Studio { handle, .. } => handle.done_fut(),
-        }
-    }
-
-    pub fn take_health_rx(&mut self) -> Option {
-        match self {
-            Self::Instant { handle, .. } => {
-                #[cfg(target_os = "linux")]
-                {
-                    Arc::get_mut(handle).and_then(instant_recording::ActorHandle::take_health_rx)
-                }
-                #[cfg(not(target_os = "linux"))]
-                {
-                    handle.take_health_rx()
-                }
-            }
-            Self::Studio { .. } => None,
-        }
-    }
-
-    pub async fn cancel(self) -> anyhow::Result<()> {
-        match self {
-            Self::Instant { handle, .. } => handle.cancel().await,
-            Self::Studio { handle, .. } => handle.cancel().await,
-        }
-    }
-
-    pub fn mode(&self) -> RecordingMode {
-        match self {
-            Self::Instant { .. } => RecordingMode::Instant,
-            Self::Studio { .. } => RecordingMode::Studio,
-        }
-    }
-}
-
-pub enum CompletedRecording {
-    Instant {
-        #[cfg(target_os = "linux")]
-        finalized: bool,
-        recording: instant_recording::CompletedRecording,
-        target_name: String,
-        segment_upload: InstantUploader,
-        video_upload_info: VideoUploadInfo,
-    },
-    Studio {
-        recording: studio_recording::CompletedRecording,
-        target_name: String,
-        capture_target: ScreenCaptureTarget,
-    },
-}
-
-impl CompletedRecording {
-    pub fn project_path(&self) -> &PathBuf {
-        match self {
-            Self::Instant { recording, .. } => &recording.project_path,
-            Self::Studio { recording, .. } => &recording.project_path,
-        }
-    }
-
-    pub fn target_name(&self) -> &String {
-        match self {
-            Self::Instant { target_name, .. } => target_name,
-            Self::Studio { target_name, .. } => target_name,
-        }
-    }
-}
-
-#[tauri::command(async)]
-#[specta::specta]
-pub async fn list_capture_displays() -> Vec {
-    screen_capture::list_displays()
-        .into_iter()
-        .map(|(v, _)| v)
-        .collect()
-}
-
-#[tauri::command(async)]
-#[specta::specta]
-pub async fn list_capture_windows(window: tauri::Window) -> Vec {
-    let windows = if window.label() == CapWindowId::Settings.label() {
-        screen_capture::list_excludable_windows()
-    } else {
-        screen_capture::list_windows()
-    };
-
-    windows.into_iter().map(|(v, _)| v).collect()
-}
-
-#[tauri::command(async)]
-#[specta::specta]
-pub fn list_cameras() -> Vec {
-    if !permissions::do_permissions_check(false).camera.permitted() {
-        return vec![];
-    }
-    cap_camera::list_cameras().collect()
-}
-
-#[derive(Debug, Clone, serde::Serialize, specta::Type)]
-#[serde(rename_all = "camelCase")]
-pub struct CameraFormatInfo {
-    pub width: u32,
-    pub height: u32,
-    pub frame_rate: f32,
-}
-
-#[derive(Debug, Clone, serde::Serialize, specta::Type)]
-#[serde(rename_all = "camelCase")]
-pub struct CameraWithFormats {
-    pub device_id: String,
-    pub display_name: String,
-    pub model_id: Option,
-    pub formats: Vec,
-    pub best_format: Option,
-}
-
-fn get_best_format(formats: &[CameraFormatInfo]) -> Option {
-    let preferred_rate = 59.0..=60.0;
-    let supported_rate = 24.0..=60.0;
-
-    let mut ideal_formats = formats
-        .iter()
-        .filter(|f| preferred_rate.contains(&f.frame_rate) && f.width <= 1280 && f.height <= 720)
-        .collect::>();
-
-    if ideal_formats.is_empty() {
-        ideal_formats = formats
-            .iter()
-            .filter(|f| preferred_rate.contains(&f.frame_rate) && f.width < 2000 && f.height < 2000)
-            .collect();
-    }
-
-    if ideal_formats.is_empty() {
-        ideal_formats = formats
-            .iter()
-            .filter(|f| {
-                supported_rate.contains(&f.frame_rate) && f.width <= 1280 && f.height <= 720
-            })
-            .collect();
-    }
-
-    if ideal_formats.is_empty() {
-        ideal_formats = formats
-            .iter()
-            .filter(|f| supported_rate.contains(&f.frame_rate) && f.width < 2000 && f.height < 2000)
-            .collect();
-    }
-
-    if ideal_formats.is_empty() {
-        ideal_formats = formats.iter().collect();
-    }
-
-    ideal_formats.sort_by(|a, b| {
-        let target_aspect_ratio = 16.0 / 9.0;
-        let aspect_ratio_a = a.width as f32 / a.height as f32;
-        let aspect_ratio_b = b.width as f32 / b.height as f32;
-        let aspect_cmp_a = (aspect_ratio_a - target_aspect_ratio).abs();
-        let aspect_cmp_b = (aspect_ratio_b - target_aspect_ratio).abs();
-        let resolution_cmp = (a.width * a.height).cmp(&(b.width * b.height));
-        let fr_cmp_a = (a.frame_rate - 60.0).abs();
-        let fr_cmp_b = (b.frame_rate - 60.0).abs();
-
-        aspect_cmp_a
-            .partial_cmp(&aspect_cmp_b)
-            .unwrap_or(std::cmp::Ordering::Equal)
-            .then(resolution_cmp.reverse())
-            .then(
-                fr_cmp_a
-                    .partial_cmp(&fr_cmp_b)
-                    .unwrap_or(std::cmp::Ordering::Equal),
-            )
-    });
-
-    ideal_formats.into_iter().next().cloned()
-}
-
-#[tauri::command(async)]
-#[specta::specta]
-pub fn get_camera_formats(device_id: String) -> Option {
-    if !permissions::do_permissions_check(false).camera.permitted() {
-        return None;
-    }
-
-    cap_camera::list_cameras()
-        .find(|c| c.device_id() == device_id)
-        .map(|camera| {
-            let formats: Vec = camera
-                .formats()
-                .unwrap_or_default()
-                .into_iter()
-                .map(|f| CameraFormatInfo {
-                    width: f.width(),
-                    height: f.height(),
-                    frame_rate: f.frame_rate(),
-                })
-                .collect();
-
-            let best_format = get_best_format(&formats);
-
-            CameraWithFormats {
-                device_id: camera.device_id().to_string(),
-                display_name: camera.display_name().to_string(),
-                model_id: camera.model_id().map(|m| m.to_string()),
-                formats,
-                best_format,
-            }
-        })
-}
-
-#[derive(Debug, Clone, serde::Serialize, specta::Type)]
-#[serde(rename_all = "camelCase")]
-pub struct MicrophoneInfo {
-    pub name: String,
-    pub sample_rate: u32,
-    pub channels: u16,
-    pub formats: Vec,
-}
-
-#[derive(Debug, Clone, serde::Serialize, specta::Type)]
-#[serde(rename_all = "camelCase")]
-pub struct MicrophoneFormatInfo {
-    pub sample_rate: u32,
-    pub channels: u16,
-}
-
-#[tauri::command(async)]
-#[specta::specta]
-pub fn get_microphone_info(name: String) -> Option {
-    if !permissions::do_permissions_check(false)
-        .microphone
-        .permitted()
-    {
-        return None;
-    }
-
-    microphone::MicrophoneFeed::device_with_settings(&name, None).map(|(device, config)| {
-        let formats = microphone_format_infos(&device);
-        MicrophoneInfo {
-            name,
-            sample_rate: config.sample_rate().0,
-            channels: config.channels(),
-            formats,
-        }
-    })
-}
-
-fn microphone_format_infos(device: &cpal::Device) -> Vec {
-    let Ok(configs) = device.supported_input_configs() else {
-        return vec![];
-    };
-    let mut formats = BTreeSet::new();
-
-    for config in configs {
-        if ffmpeg_sample_format_for(config.sample_format()).is_none() {
-            continue;
-        }
-
-        for sample_rate in [
-            config.min_sample_rate().0,
-            44_100,
-            48_000,
-            96_000,
-            config.max_sample_rate().0,
-        ] {
-            if config.min_sample_rate().0 <= sample_rate
-                && sample_rate <= config.max_sample_rate().0
-            {
-                formats.insert((sample_rate, config.channels()));
-            }
-        }
-    }
-
-    formats
-        .into_iter()
-        .map(|(sample_rate, channels)| MicrophoneFormatInfo {
-            sample_rate,
-            channels,
-        })
-        .collect()
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument]
-pub async fn list_displays_with_thumbnails() -> Result, String> {
-    run_non_send_thumbnail_future(collect_displays_with_thumbnails())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument]
-pub async fn list_windows_with_thumbnails() -> Result, String> {
-    run_non_send_thumbnail_future(collect_windows_with_thumbnails())
-}
-
-fn run_non_send_thumbnail_future(future: F) -> Result
-where
-    F: std::future::Future>,
-{
-    let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
-        if tokio::runtime::Handle::try_current().is_ok() {
-            tokio::task::block_in_place(|| tauri::async_runtime::block_on(future))
-        } else {
-            tauri::async_runtime::block_on(future)
-        }
-    }));
-
-    match result {
-        Ok(result) => result,
-        Err(panic) => {
-            let message = crate::panic_payload_message(&panic);
-            error!(panic = %message, "Suppressed panic while collecting capture thumbnails");
-            Err(format!("Failed to collect capture thumbnails: {message}"))
-        }
-    }
-}
-
-#[derive(Deserialize, Type, Clone, Debug)]
-pub struct StartRecordingInputs {
-    pub capture_target: ScreenCaptureTarget,
-    #[serde(default)]
-    pub capture_system_audio: bool,
-    pub mode: RecordingMode,
-    #[serde(default)]
-    pub organization_id: Option,
-}
-
-fn desktop_recording_defaults(
-    general_settings: Option<&GeneralSettingsStore>,
-) -> cap_recording::RecordingDefaults {
-    match general_settings {
-        Some(settings) => cap_recording::RecordingDefaults {
-            custom_cursor_capture: settings.custom_cursor_capture,
-            capture_keyboard_events: settings.capture_keyboard_events,
-            crash_recovery_recording: settings.crash_recovery_recording,
-            max_fps: settings.max_fps,
-            studio_recording_quality: settings.studio_recording_quality.into(),
-            out_of_process_muxer: settings.out_of_process_muxer,
-            instant_mode_max_resolution: cap_recording::DEFAULT_INSTANT_MODE_MAX_RESOLUTION,
-        },
-        None => cap_recording::RecordingDefaults::default(),
-    }
-}
-
-#[derive(Deserialize, Type, Serialize, Clone, Copy, Debug, PartialEq, Eq, Hash)]
-#[serde(rename_all = "camelCase")]
-pub enum RecordingInputKind {
-    Microphone,
-    Camera,
-}
-
-#[derive(tauri_specta::Event, specta::Type, Clone, Debug, serde::Serialize)]
-#[serde(tag = "variant")]
-pub enum RecordingEvent {
-    Countdown { value: u32 },
-    Started,
-    Stopped,
-    Paused,
-    Resumed,
-    Failed { error: String },
-    // Emitted when start_recording aborts before any recording exists. Distinct from
-    // `Failed` because the in-progress window treats `Failed` as "the active recording
-    // died", which would misreport a healthy recording when a second start is refused.
-    StartFailed { error: String },
-    InputLost { input: RecordingInputKind },
-    InputRestored { input: RecordingInputKind },
-    Degraded { reason: String },
-    Recovered,
-}
-
-/// Every abort path out of `start_recording` must be observable: in the log, and as an
-/// event the main window surfaces to the user. The picker overlay that invoked the
-/// command is often already closed (or being torn down) when the error comes back, so
-/// an error returned to the caller alone can vanish without a trace.
-fn notify_recording_start_failed(app: &AppHandle, error: &str) {
-    error!(%error, "Recording failed to start");
-    let _ = RecordingEvent::StartFailed {
-        error: error.to_string(),
-    }
-    .emit(app);
-}
-
-fn recording_start_mode_error(mode: RecordingMode, authenticated: bool) -> Option<&'static str> {
-    match mode {
-        RecordingMode::Instant if !authenticated => Some("Please sign in to use instant recording"),
-        RecordingMode::Screenshot => Some("Use take_screenshot for screenshots"),
-        RecordingMode::Studio | RecordingMode::Instant => None,
-    }
-}
-
-const RECORDING_START_CANCELLED: &str = "Recording cancelled before starting.";
-
-#[derive(Clone, Default)]
-struct RecordingStoragePrompt(Arc>>>);
-
-impl RecordingStoragePrompt {
-    fn begin(&self) -> Option {
-        let mut slot = self.0.lock().unwrap();
-        if slot.is_some() {
-            return None;
-        }
-        let cancelled = Arc::new(CancellationToken::new());
-        *slot = Some(cancelled.clone());
-        Some(RecordingStoragePromptLease {
-            slot: self.clone(),
-            cancelled,
-        })
-    }
-
-    fn cancel(&self) -> bool {
-        let slot = self.0.lock().unwrap();
-        if let Some(cancelled) = slot.as_ref() {
-            cancelled.cancel();
-            true
-        } else {
-            false
-        }
-    }
-}
-
-fn recording_storage_prompt(app: &AppHandle) -> RecordingStoragePrompt {
-    if app.try_state::().is_none() {
-        app.manage(RecordingStoragePrompt::default());
-    }
-    app.state::().inner().clone()
-}
-
-struct RecordingStoragePromptLease {
-    slot: RecordingStoragePrompt,
-    cancelled: Arc,
-}
-
-impl Drop for RecordingStoragePromptLease {
-    fn drop(&mut self) {
-        let mut slot = self.slot.0.lock().unwrap();
-        if slot
-            .as_ref()
-            .is_some_and(|current| Arc::ptr_eq(current, &self.cancelled))
-        {
-            *slot = None;
-        }
-    }
-}
-
-struct RecordingStorageEvents {
-    app: AppHandle,
-    id: tauri::EventId,
-}
-
-impl Drop for RecordingStorageEvents {
-    fn drop(&mut self) {
-        self.app.unlisten(self.id);
-    }
-}
-
-async fn recording_storage_answer(
-    cancelled: &CancellationToken,
-    answer: tokio::sync::oneshot::Receiver,
-) -> Result {
-    tokio::select! {
-        biased;
-        _ = cancelled.cancelled() => Err(RECORDING_START_CANCELLED.to_string()),
-        answer = answer => Ok(answer.unwrap_or(false)),
-    }
-}
-
-async fn check_recording_start_storage(
-    directory: &Path,
-    mut sample: impl FnMut(&Path) -> std::io::Result,
-    confirm: impl FnOnce(u64) -> F,
-) -> Result<(), String>
-where
-    F: std::future::Future>,
-{
-    use cap_utils::disk_space::{DiskSpaceStatus, RecordingStorage};
-
-    let mut read = || {
-        sample(directory).map_err(|error| {
-            format!(
-                "Could not check available disk space at {}: {error}",
-                directory.display()
-            )
-        })
-    };
-    let status = |available_bytes| {
-        RecordingStorage {
-            available_bytes,
-            recording_bytes: 0,
-        }
-        .status()
-    };
-    let exhausted = |bytes| {
-        format!(
-            "Not enough disk space to start recording ({:.2} GiB free). Free up space so more than {} MiB is available at {} and try again.",
-            bytes as f64 / 1_073_741_824.0,
-            cap_utils::disk_space::RECORDING_DISK_RESERVE_BYTES / (1024 * 1024),
-            directory.display(),
-        )
-    };
-    let bytes = read()?;
-    match status(bytes) {
-        DiskSpaceStatus::Ok => Ok(()),
-        DiskSpaceStatus::Exhausted => Err(exhausted(bytes)),
-        DiskSpaceStatus::Low => {
-            if !confirm(bytes).await? {
-                return Err(RECORDING_START_CANCELLED.to_string());
-            }
-            let bytes = read()?;
-            if status(bytes) == DiskSpaceStatus::Exhausted {
-                Err(exhausted(bytes))
-            } else {
-                Ok(())
-            }
-        }
-    }
-}
-
-async fn cancel_recording_storage_prompt(app: &AppHandle, state: &MutableState<'_, App>) -> bool {
-    let state = state.read().await;
-    matches!(state.recording_state, RecordingState::Pending { .. })
-        && app
-            .try_state::()
-            .is_some_and(|prompt| prompt.cancel())
-}
-
-#[cfg(any(target_os = "linux", test))]
-fn storage_preflight_control_result(
-    result: Result<(), String>,
-    has_capture: bool,
-) -> Result<(), String> {
-    match result {
-        Err(error) if error == RECORDING_START_CANCELLED && !has_capture => Ok(()),
-        result => result,
-    }
-}
-
-#[cfg(test)]
-mod recording_storage_preflight_tests {
-    use super::*;
-    use cap_utils::disk_space::{RECORDING_DISK_RESERVE_BYTES, RECORDING_DISK_WARN_BYTES};
-    use std::cell::Cell;
-
-    #[tokio::test]
-    async fn thresholds_match_recording_storage_policy() {
-        for (bytes, asks, starts) in [
-            (RECORDING_DISK_WARN_BYTES + 1, false, true),
-            (RECORDING_DISK_WARN_BYTES, true, true),
-            (RECORDING_DISK_RESERVE_BYTES + 1, true, true),
-            (RECORDING_DISK_RESERVE_BYTES, false, false),
-            (0, false, false),
-        ] {
-            let prompted = Cell::new(false);
-            let result = check_recording_start_storage(
-                Path::new("recordings"),
-                |_| Ok(bytes),
-                |_| {
-                    prompted.set(true);
-                    async { Ok(true) }
-                },
-            )
-            .await;
-            assert_eq!(prompted.get(), asks);
-            assert_eq!(result.is_ok(), starts);
-        }
-    }
-
-    #[tokio::test]
-    async fn confirmation_rechecks_same_recordings_drive() {
-        let directory = Path::new("external-drive/custom-recordings");
-        let reads = Cell::new(0);
-        check_recording_start_storage(
-            directory,
-            |path| {
-                assert_eq!(path, directory);
-                reads.set(reads.get() + 1);
-                Ok(RECORDING_DISK_WARN_BYTES)
-            },
-            |_| async { Ok(true) },
-        )
-        .await
-        .unwrap();
-        assert_eq!(reads.get(), 2);
-    }
-
-    #[tokio::test]
-    async fn confirmation_cannot_override_new_reserve_exhaustion() {
-        let mut bytes = [RECORDING_DISK_WARN_BYTES, RECORDING_DISK_RESERVE_BYTES].into_iter();
-        let result = check_recording_start_storage(
-            Path::new("recordings"),
-            |_| Ok(bytes.next().unwrap()),
-            |_| async { Ok(true) },
-        )
-        .await;
-        assert!(result.unwrap_err().contains("more than 512 MiB"));
-    }
-
-    #[tokio::test]
-    async fn go_back_skips_second_probe() {
-        let reads = Cell::new(0);
-        let result = check_recording_start_storage(
-            Path::new("recordings"),
-            |_| {
-                reads.set(reads.get() + 1);
-                Ok(RECORDING_DISK_WARN_BYTES)
-            },
-            |_| async { Ok(false) },
-        )
-        .await;
-        assert_eq!(result.unwrap_err(), RECORDING_START_CANCELLED);
-        assert_eq!(reads.get(), 1);
-    }
-
-    #[tokio::test]
-    async fn unknown_storage_never_admits_capture() {
-        for fail_at in [1, 2] {
-            let mut reads = 0;
-            let result = check_recording_start_storage(
-                Path::new("recordings"),
-                |_| {
-                    reads += 1;
-                    if reads == fail_at {
-                        Err(std::io::Error::from_raw_os_error(5))
-                    } else {
-                        Ok(RECORDING_DISK_WARN_BYTES)
-                    }
-                },
-                |_| async { Ok(true) },
-            )
-            .await;
-            assert!(
-                result
-                    .unwrap_err()
-                    .starts_with("Could not check available disk space")
-            );
-        }
-    }
-
-    #[tokio::test]
-    async fn closed_native_callback_declines() {
-        let (sender, receiver) = tokio::sync::oneshot::channel();
-        drop(sender);
-        assert!(
-            !recording_storage_answer(&CancellationToken::new(), receiver)
-                .await
-                .unwrap()
-        );
-    }
-
-    #[tokio::test]
-    async fn cancellation_wins_simultaneous_affirmative() {
-        let token = CancellationToken::new();
-        let (sender, receiver) = tokio::sync::oneshot::channel();
-        sender.send(true).unwrap();
-        token.cancel();
-        assert_eq!(
-            recording_storage_answer(&token, receiver)
-                .await
-                .unwrap_err(),
-            RECORDING_START_CANCELLED
-        );
-    }
-
-    #[tokio::test]
-    async fn stop_unblocks_wait_and_late_answer_is_inert() {
-        let slot = RecordingStoragePrompt::default();
-        let lease = slot.begin().unwrap();
-        let (sender, receiver) = tokio::sync::oneshot::channel();
-        let answer = recording_storage_answer(&lease.cancelled, receiver);
-        tokio::pin!(answer);
-        tokio::select! {
-            biased;
-            _ = &mut answer => panic!("Prompt resolved without an answer"),
-            _ = std::future::ready(()) => {},
-        }
-        assert!(slot.cancel());
-        assert_eq!(answer.await.unwrap_err(), RECORDING_START_CANCELLED);
-        assert!(sender.send(true).is_err());
-    }
-
-    #[test]
-    fn repeated_requests_do_not_replace_active_prompt() {
-        let slot = RecordingStoragePrompt::default();
-        let first = slot.begin().unwrap();
-        assert!(slot.begin().is_none());
-        assert!(slot.cancel());
-        assert!(first.cancelled.is_cancelled());
-        assert!(slot.begin().is_none());
-        drop(first);
-        let second = slot.begin().unwrap();
-        assert!(!second.cancelled.is_cancelled());
-    }
-
-    #[test]
-    fn retired_prompt_cannot_cancel_admitted_recording() {
-        let slot = RecordingStoragePrompt::default();
-        let lease = slot.begin().unwrap();
-        let token = lease.cancelled.clone();
-        drop(lease);
-        assert!(!slot.cancel());
-        assert!(!token.is_cancelled());
-    }
-
-    #[test]
-    fn stale_drop_does_not_remove_replacement_prompt() {
-        let slot = RecordingStoragePrompt::default();
-        let first = slot.begin().unwrap();
-        *slot.0.lock().unwrap() = None;
-        let second = slot.begin().unwrap();
-        drop(first);
-        assert!(slot.cancel());
-        assert!(second.cancelled.is_cancelled());
-    }
-
-    #[test]
-    fn instant_control_normalizes_only_confirmed_pre_capture_cancellation() {
-        assert!(
-            storage_preflight_control_result(Err(RECORDING_START_CANCELLED.into()), false).is_ok()
-        );
-        assert_eq!(
-            storage_preflight_control_result(Err(RECORDING_START_CANCELLED.into()), true)
-                .unwrap_err(),
-            RECORDING_START_CANCELLED
-        );
-        assert_eq!(
-            storage_preflight_control_result(Err("cleanup unconfirmed".into()), false).unwrap_err(),
-            "cleanup unconfirmed"
-        );
-        assert!(storage_preflight_control_result(Ok(()), true).is_ok());
-    }
-}
-
-#[derive(Serialize, Type)]
-pub enum RecordingAction {
-    Started,
-    InvalidAuthentication,
-    UpgradeRequired,
-}
-
-const MICROPHONE_INPUT_PROBE_TIMEOUT: Duration = Duration::from_millis(1500);
-const CAMERA_INPUT_PROBE_TIMEOUT: Duration = Duration::from_millis(1500);
-
-pub(crate) fn camera_id_label(id: &camera::DeviceOrModelID) -> String {
-    match id {
-        camera::DeviceOrModelID::DeviceID(device_id) => device_id.clone(),
-        camera::DeviceOrModelID::ModelID(model_id) => format!("{model_id:?}"),
-    }
-}
-
-fn validate_selected_camera_for_start(
-    selected_id: Option<&camera::DeviceOrModelID>,
-    is_available: impl FnOnce(&camera::DeviceOrModelID) -> bool,
-) -> anyhow::Result<()> {
-    if let Some(id) = selected_id
-        && !is_available(id)
-    {
-        return Err(anyhow!(
-            "Selected camera '{}' is no longer available. Reconnect it or choose another camera before recording.",
-            camera_id_label(id)
-        ));
-    }
-    Ok(())
-}
-
-fn selected_microphone_for_start(
-    selected_label: Option,
-    available_names: &[String],
-) -> anyhow::Result> {
-    let Some(label) = selected_label else {
-        return Ok(None);
-    };
-    if !available_names.contains(&label) {
-        return Err(anyhow!(
-            "Selected microphone '{label}' is no longer available. Reconnect it or choose another microphone before recording."
-        ));
-    }
-    Ok(Some(label))
-}
-
-fn camera_lock_matches_id(lock: &CameraFeedLock, selected_id: &camera::DeviceOrModelID) -> bool {
-    let camera_info = lock.camera_info();
-    match selected_id {
-        camera::DeviceOrModelID::DeviceID(device_id) => camera_info.device_id() == device_id,
-        camera::DeviceOrModelID::ModelID(model_id) => camera_info.model_id() == Some(model_id),
-    }
-}
-
-async fn initialize_selected_camera(
-    camera_feed: &kameo::actor::ActorRef,
-    id: &camera::DeviceOrModelID,
-    settings: Option,
-) -> anyhow::Result<()> {
-    let label = camera_id_label(id);
-    let ready = camera_feed
-        .ask(camera::SetInput {
-            id: id.clone(),
-            settings,
-        })
-        .await
-        .map_err(|err| anyhow!("Failed to initialize selected camera '{label}': {err}"))?;
-
-    ready.await.map(|_| ()).map_err(|err| match err {
-        camera::SetInputError::DeviceNotFound => {
-            anyhow!("Selected camera '{label}' is no longer available")
-        }
-        err => anyhow!("Failed to initialize selected camera '{label}': {err}"),
-    })
-}
-
-async fn lock_initialized_camera(
-    camera_feed: &kameo::actor::ActorRef,
-    id: &camera::DeviceOrModelID,
-) -> anyhow::Result {
-    let label = camera_id_label(id);
-    match camera_feed.ask(camera::Lock).await {
-        Ok(lock) if camera_lock_matches_id(&lock, id) => Ok(lock),
-        Ok(_) => Err(anyhow!(
-            "Selected camera '{label}' changed during initialization. Select the camera again before recording."
-        )),
-        Err(kameo::error::SendError::HandlerError(camera::LockFeedError::NoInput)) => Err(anyhow!(
-            "Selected camera '{label}' did not become ready after initialization"
-        )),
-        Err(err) => Err(anyhow!("Failed to lock selected camera '{label}': {err}")),
-    }
-}
-
-#[cfg(not(target_os = "macos"))]
-async fn validate_camera_receiving(
-    lock: &CameraFeedLock,
-    id: &camera::DeviceOrModelID,
-) -> anyhow::Result<()> {
-    let label = camera_id_label(id);
-    let (tx, rx) = flume::bounded(1);
-    let remove_sender = tx.clone();
-
-    tokio::time::timeout(CAMERA_INPUT_PROBE_TIMEOUT, lock.ask(camera::AddSender(tx)))
-        .await
-        .map_err(|_| anyhow!("Timed out attaching selected camera '{label}' probe"))?
-        .map_err(|err| anyhow!("Failed to probe selected camera '{label}': {err}"))?;
-
-    let result = tokio::time::timeout(CAMERA_INPUT_PROBE_TIMEOUT, rx.recv_async()).await;
-    let _ = tokio::time::timeout(
-        CAMERA_INPUT_PROBE_TIMEOUT,
-        lock.ask(camera::RemoveSender(remove_sender)),
-    )
-    .await;
-
-    match result {
-        Ok(Ok(_)) => Ok(()),
-        Ok(Err(_)) => Err(anyhow!(
-            "Selected camera '{label}' stopped before sending a frame"
-        )),
-        Err(_) => Err(anyhow!(
-            "Selected camera '{label}' is not sending video frames"
-        )),
-    }
-}
-
-#[cfg(target_os = "macos")]
-async fn validate_camera_receiving(
-    lock: &CameraFeedLock,
-    id: &camera::DeviceOrModelID,
-) -> anyhow::Result<()> {
-    let label = camera_id_label(id);
-    let (tx, rx) = flume::bounded(1);
-    let remove_sender = tx.clone();
-
-    tokio::time::timeout(
-        CAMERA_INPUT_PROBE_TIMEOUT,
-        lock.ask(camera::AddNativeSender(tx)),
-    )
-    .await
-    .map_err(|_| anyhow!("Timed out attaching selected camera '{label}' probe"))?
-    .map_err(|err| anyhow!("Failed to probe selected camera '{label}': {err}"))?;
-
-    let result = tokio::time::timeout(CAMERA_INPUT_PROBE_TIMEOUT, rx.recv_async()).await;
-    let _ = tokio::time::timeout(
-        CAMERA_INPUT_PROBE_TIMEOUT,
-        lock.ask(camera::RemoveNativeSender(remove_sender)),
-    )
-    .await;
-
-    match result {
-        Ok(Ok(_)) => Ok(()),
-        Ok(Err(_)) => Err(anyhow!(
-            "Selected camera '{label}' stopped before sending a frame"
-        )),
-        Err(_) => Err(anyhow!(
-            "Selected camera '{label}' is not sending video frames"
-        )),
-    }
-}
-
-async fn lock_selected_camera(
-    camera_feed: &kameo::actor::ActorRef,
-    selected_id: Option,
-    selected_settings: Option,
-    capture_target: &ScreenCaptureTarget,
-) -> anyhow::Result>> {
-    let Some(id) = selected_id else {
-        if matches!(capture_target, ScreenCaptureTarget::CameraOnly) {
-            return Err(anyhow!(
-                "Camera-only recording requires a selected camera. Please select a camera before starting."
-            ));
-        }
-
-        return Ok(None);
-    };
-
-    crate::permissions::check_camera_access().map_err(anyhow::Error::msg)?;
-
-    let existing_lock = match camera_feed.ask(camera::Lock).await {
-        Ok(lock) if camera_lock_matches_id(&lock, &id) => Some(lock),
-        Ok(lock) => {
-            drop(lock);
-            tokio::time::sleep(Duration::from_millis(50)).await;
-            None
-        }
-        Err(kameo::error::SendError::HandlerError(camera::LockFeedError::NoInput)) => None,
-        Err(err) => {
-            return Err(anyhow!(
-                "Failed to lock selected camera '{}': {err}",
-                camera_id_label(&id)
-            ));
-        }
-    };
-
-    let lock = if let Some(lock) = existing_lock {
-        lock
-    } else {
-        initialize_selected_camera(camera_feed, &id, selected_settings).await?;
-        lock_initialized_camera(camera_feed, &id).await?
-    };
-
-    validate_camera_receiving(&lock, &id).await?;
-    Ok(Some(Arc::new(lock)))
-}
-
-async fn initialize_selected_microphone(
-    mic_feed: &kameo::actor::ActorRef,
-    label: &str,
-    settings: Option,
-) -> anyhow::Result<()> {
-    let ready = mic_feed
-        .ask(microphone::SetInput {
-            label: label.to_string(),
-            settings,
-        })
-        .await
-        .map_err(|err| anyhow!("Failed to initialize selected microphone '{label}': {err}"))?;
-
-    ready.await.map(|_| ()).map_err(|err| match err {
-        microphone::SetInputError::DeviceNotFound => {
-            anyhow!("Selected microphone '{label}' is no longer available")
-        }
-        err => anyhow!("Failed to initialize selected microphone '{label}': {err}"),
-    })
-}
-
-async fn lock_initialized_microphone(
-    mic_feed: &kameo::actor::ActorRef,
-    label: &str,
-) -> anyhow::Result {
-    match mic_feed.ask(microphone::Lock).await {
-        Ok(lock) if lock.device_name() == label => Ok(lock),
-        Ok(_) => Err(anyhow!(
-            "Selected microphone '{label}' changed during initialization. Select the microphone again before recording."
-        )),
-        Err(kameo::error::SendError::HandlerError(microphone::LockFeedError::NoInput)) => Err(
-            anyhow!("Selected microphone '{label}' did not become ready after initialization"),
-        ),
-        Err(err) => Err(anyhow!(
-            "Failed to lock selected microphone '{label}': {err}"
-        )),
-    }
-}
-
-async fn validate_microphone_receiving(
-    lock: µphone::MicrophoneFeedLock,
-    label: &str,
-) -> anyhow::Result<()> {
-    let (tx, rx) = flume::bounded(1);
-    let remove_sender = tx.clone();
-
-    lock.ask(microphone::AddSender(tx))
-        .await
-        .map_err(|err| anyhow!("Failed to probe selected microphone '{label}': {err}"))?;
-
-    let result = tokio::time::timeout(MICROPHONE_INPUT_PROBE_TIMEOUT, rx.recv_async()).await;
-    let _ = lock.ask(microphone::RemoveSender(remove_sender)).await;
-
-    match result {
-        Ok(Ok(_)) => Ok(()),
-        Ok(Err(_)) => Err(anyhow!(
-            "Selected microphone '{label}' stopped before sending audio"
-        )),
-        Err(_) => Err(anyhow!(
-            "Selected microphone '{label}' is not sending audio"
-        )),
-    }
-}
-
-pub fn format_project_name<'a>(
-    template: Option<&str>,
-    target_name: &'a str,
-    target_kind: &'a str,
-    recording_mode: RecordingMode,
-    datetime: Option>,
-) -> String {
-    const DEFAULT_FILENAME_TEMPLATE: &str = "{target_name} ({target_kind}) {date} {time}";
-    const MAX_TARGET_NAME_CHARS: usize = 180;
-    let datetime = datetime.unwrap_or(chrono::Local::now());
-
-    let truncated_target_name: std::borrow::Cow<'_, str> =
-        if target_name.chars().count() > MAX_TARGET_NAME_CHARS {
-            std::borrow::Cow::Owned(
-                target_name
-                    .chars()
-                    .take(MAX_TARGET_NAME_CHARS)
-                    .collect::()
-                    + "...",
-            )
-        } else {
-            std::borrow::Cow::Borrowed(target_name)
-        };
-
-    lazy_static! {
-        static ref DATE_REGEX: Regex = Regex::new(r"\{date(?::([^}]+))?\}").unwrap();
-        static ref TIME_REGEX: Regex = Regex::new(r"\{time(?::([^}]+))?\}").unwrap();
-        static ref MOMENT_REGEX: Regex = Regex::new(r"\{moment(?::([^}]+))?\}").unwrap();
-        static ref RANDOM_REGEX: Regex = Regex::new(r"\{random(?::(\d+))?\}").unwrap();
-        static ref AC: aho_corasick::AhoCorasick = {
-            aho_corasick::AhoCorasick::new([
-                "{recording_mode}",
-                "{mode}",
-                "{target_kind}",
-                "{target_name}",
-            ])
-            .expect("Failed to build AhoCorasick automaton")
-        };
-    }
-    let haystack = template.unwrap_or(DEFAULT_FILENAME_TEMPLATE);
-    let haystack = RANDOM_REGEX.replace_all(haystack, |caps: ®ex::Captures| {
-        let length = match caps.get(1) {
-            Some(value) => match value.as_str().parse::() {
-                Ok(length) => length,
-                Err(_) => return caps.get(0).unwrap().as_str().to_owned(),
-            },
-            None => 10,
-        };
-        if !(1..=32).contains(&length) {
-            return caps.get(0).unwrap().as_str().to_owned();
-        }
-        uuid::Uuid::new_v4().simple().to_string()[..length].to_owned()
-    });
-
-    // Get recording mode information
-    let (recording_mode, mode) = match recording_mode {
-        RecordingMode::Studio => ("Studio", "studio"),
-        RecordingMode::Instant => ("Instant", "instant"),
-        RecordingMode::Screenshot => ("Screenshot", "screenshot"),
-    };
-
-    let result = AC
-        .try_replace_all(
-            &haystack,
-            &[recording_mode, mode, target_kind, &truncated_target_name],
-        )
-        .expect("AhoCorasick replace should never fail with default configuration");
-
-    let result = DATE_REGEX.replace_all(&result, |caps: ®ex::Captures| {
-        datetime
-            .format(
-                &caps
-                    .get(1)
-                    .map(|m| m.as_str())
-                    .map(moment_format_to_chrono)
-                    .unwrap_or(Cow::Borrowed("%Y-%m-%d")),
-            )
-            .to_string()
-    });
-
-    let result = TIME_REGEX.replace_all(&result, |caps: ®ex::Captures| {
-        datetime
-            .format(
-                &caps
-                    .get(1)
-                    .map(|m| m.as_str())
-                    .map(moment_format_to_chrono)
-                    .unwrap_or(Cow::Borrowed("%I:%M %p")),
-            )
-            .to_string()
-    });
-
-    let result = MOMENT_REGEX.replace_all(&result, |caps: ®ex::Captures| {
-        datetime
-            .format(
-                &caps
-                    .get(1)
-                    .map(|m| m.as_str())
-                    .map(moment_format_to_chrono)
-                    .unwrap_or(Cow::Borrowed("%Y-%m-%d %H:%M")),
-            )
-            .to_string()
-    });
-
-    result.into_owned()
-}
-
-#[tauri::command]
-#[specta::specta]
-#[tracing::instrument(name = "recording", skip_all)]
-pub async fn start_recording(
-    app: AppHandle,
-    state_mtx: MutableState<'_, App>,
-    inputs: StartRecordingInputs,
-) -> Result {
-    #[cfg(target_os = "linux")]
-    if inputs.mode != RecordingMode::Instant && linux_instant::current(&app).is_some() {
-        return Err("Finish the pending Instant cleanup before recording".into());
-    }
-    #[cfg(target_os = "linux")]
-    if inputs.mode == RecordingMode::Instant && EditorRecordingTarget::current(&app).is_none() {
-        return linux_instant::start(app, state_mtx, inputs).await;
-    }
-    start_recording_inner(app, state_mtx, inputs).await
-}
-
-async fn start_recording_inner(
-    app: AppHandle,
-    state_mtx: MutableState<'_, App>,
-    inputs: StartRecordingInputs,
-) -> Result {
-    let mut inputs = inputs;
-
-    #[cfg(target_os = "linux")]
-    let has_instant_owner = linux_instant::current(&app).is_some();
-    #[cfg(not(target_os = "linux"))]
-    let has_instant_owner = false;
-    if EditorRecordingTarget::current(&app).is_some() && !has_instant_owner {
-        inputs.mode = RecordingMode::Studio;
-    }
-
-    let requested_state = app.state::();
-    let requested_inputs = match requested_state.ready_snapshot() {
-        Ok(snapshot) => snapshot,
-        Err(error) => {
-            notify_recording_start_failed(&app, &error);
-            return Err(error);
-        }
-    };
-    #[cfg(target_os = "linux")]
-    linux_instant::validate_screen_request(&inputs, &requested_inputs).inspect_err(|error| {
-        notify_recording_start_failed(&app, error);
-    })?;
-    let clean_generation = crate::clean_capture::prepare(&app, &inputs, None)
-        .await
-        .inspect_err(|error| {
-            notify_recording_start_failed(&app, error);
-        })?;
-    let result = start_recording_prepared(
-        app.clone(),
-        state_mtx.clone(),
-        inputs,
-        requested_inputs,
-        clean_generation,
-    )
-    .await;
-    if !matches!(&result, Ok(RecordingAction::Started))
-        && let Some(generation) = clean_generation
-    {
-        let mut state = state_mtx.write().await;
-        if crate::clean_capture::is_current(&app, generation) {
-            state.clear_pending_recording();
-            drop(state);
-            crate::clean_capture::release(&app, generation, false);
-        }
-    }
-    result
-}
-
-async fn start_recording_prepared(
-    app: AppHandle,
-    state_mtx: MutableState<'_, App>,
-    mut inputs: StartRecordingInputs,
-    requested_inputs: crate::RequestedInputs,
-    clean_generation: Option,
-) -> Result {
-    let requested_state = app.state::();
-    let mut _input_operation = Some(requested_state.operation.lock().await);
-    if let Err(error) = requested_state.ready_snapshot() {
-        notify_recording_start_failed(&app, &error);
-        return Err(error);
-    }
-    if !requested_state.is_current(&requested_inputs) {
-        let error = "Input selection changed before recording could start. Try recording again."
-            .to_string();
-        notify_recording_start_failed(&app, &error);
-        return Err(error);
-    }
-
-    let is_camera_only = matches!(inputs.capture_target, ScreenCaptureTarget::CameraOnly);
-
-    #[cfg(target_os = "linux")]
-    linux_instant::validate_inputs(&inputs)?;
-
-    if is_camera_only {
-        inputs.capture_system_audio = false;
-    }
-
-    {
-        let mut app_state = state_mtx.write().await;
-        let pending_result = if let Some(generation) = clean_generation {
-            if crate::clean_capture::is_current(&app, generation)
-                && matches!(app_state.recording_state, RecordingState::Pending { .. })
-            {
-                Ok(())
-            } else {
-                Err("Recording preflight was cancelled or superseded".to_string())
-            }
-        } else {
-            app_state.set_pending_recording(inputs.mode, inputs.capture_target.clone())
-        };
-        if let Err(error) = pending_result {
-            drop(app_state);
-            // Deliberately no clear_pending_recording: the pending/active state that
-            // caused the refusal belongs to another recording and must survive.
-            notify_recording_start_failed(&app, &error);
-            return Err(error);
-        }
-        if is_camera_only {
-            app_state.was_camera_only_recording = true;
-        }
-    }
-
-    let storage_generation = crate::clean_capture::generation(&app);
-    #[cfg(target_os = "linux")]
-    let storage_instant = linux_instant::current(&app);
-
-    if cfg!(target_os = "linux") && inputs.mode == RecordingMode::Instant {
-        drop(_input_operation.take());
-    }
-
-    let instant_auth = if matches!(inputs.mode, RecordingMode::Instant) {
-        AuthStore::get(&app).ok().flatten()
-    } else {
-        None
-    };
-    if let Some(error) = recording_start_mode_error(inputs.mode, instant_auth.is_some()) {
-        state_mtx.write().await.clear_pending_recording();
-        notify_recording_start_failed(&app, error);
-        return Err(error.to_string());
-    }
-
-    macro_rules! pending_try {
-        ($expr:expr, $map_err:expr) => {
-            match $expr {
-                Ok(value) => value,
-                Err(err) => {
-                    let error = ($map_err)(err);
-                    state_mtx.write().await.clear_pending_recording();
-                    notify_recording_start_failed(&app, &error);
-                    return Err(error);
-                }
-            }
-        };
-    }
-
-    if is_camera_only {
-        let operation_lock = app.state::();
-        let _operation_guard = operation_lock.lock().await;
-        if let Err(err) = (ShowCapWindow::Camera { centered: true }).show(&app).await {
-            let error = format!("Failed to show centered camera window: {err}");
-            state_mtx.write().await.clear_pending_recording();
-            notify_recording_start_failed(&app, &error);
-            return Err(error);
-        }
-    }
-
-    let general_settings = GeneralSettingsStore::get(&app).ok().flatten();
-    let general_settings = general_settings.as_ref();
-
-    let project_name = format_project_name(
-        general_settings
-            .and_then(|s| s.default_project_name_template.clone())
-            .as_deref(),
-        inputs
-            .capture_target
-            .title()
-            .as_deref()
-            .unwrap_or("Unknown"),
-        inputs.capture_target.kind_str(),
-        inputs.mode,
-        None,
-    );
-
-    let filename = project_name.replace(":", ".");
-    let filename = format!("{}.cap", sanitize_filename::sanitize(&filename));
-
-    let recordings_base_dir = GeneralSettingsStore::recordings_dir(&app);
-
-    pending_try!(ensure_dir(&recordings_base_dir), |e| format!(
-        "Failed to create recordings directory: {e}"
-    ));
-
-    let storage_prompt = recording_storage_prompt(&app)
-        .begin()
-        .ok_or(RECORDING_START_CANCELLED)?;
-    let event_app = app.clone();
-    let cancelled = storage_prompt.cancelled.clone();
-    let storage_events = RecordingStorageEvents {
-        app: app.clone(),
-        id: app.listen(CurrentRecordingChanged::NAME, move |_| {
-            if crate::clean_capture::generation(&event_app) != storage_generation
-                || clean_generation.is_some_and(|generation| {
-                    crate::clean_capture::stop_requested(&event_app, generation)
-                })
-            {
-                cancelled.cancel();
-            }
-        }),
-    };
-    if crate::clean_capture::generation(&app) != storage_generation
-        || clean_generation
-            .is_some_and(|generation| crate::clean_capture::stop_requested(&app, generation))
-    {
-        storage_prompt.cancelled.cancel();
-    }
-    let prompt_app = &app;
-    let prompt_cancelled = &storage_prompt.cancelled;
-    let storage_work = check_recording_start_storage(
-        &recordings_base_dir,
-        cap_utils::disk_space::free_bytes_for_path,
-        |bytes| async move {
-            if prompt_cancelled.is_cancelled() {
-                return Err(RECORDING_START_CANCELLED.to_string());
-            }
-            let (sender, receiver) = tokio::sync::oneshot::channel();
-            prompt_app.dialog()
-                .message(format!(
-                    "Only {:.2} GiB is available on your recordings drive. The recording may stop early if space runs out. Free up space, or record anyway.",
-                    bytes as f64 / 1_073_741_824.0,
-                ))
-                .title("Low storage space")
-                .kind(MessageDialogKind::Warning)
-                .buttons(MessageDialogButtons::OkCancelCustom(
-                    "Record anyway".to_string(),
-                    "Go back".to_string(),
-                ))
-                .show(move |confirmed| {
-                    let _ = sender.send(confirmed);
-                });
-            recording_storage_answer(prompt_cancelled, receiver).await
-        },
-    );
-    #[cfg(target_os = "linux")]
-    let storage_result = if let Some(attempt) = &storage_instant {
-        attempt.while_active(storage_work).await.map_err(|error| {
-            if attempt.cancelled() {
-                RECORDING_START_CANCELLED.to_string()
-            } else {
-                error
-            }
-        })
-    } else {
-        storage_work.await
-    };
-    #[cfg(not(target_os = "linux"))]
-    let storage_result = storage_work.await;
-    {
-        let mut app_state = state_mtx.write().await;
-        let owns_pending = matches!(app_state.recording_state, RecordingState::Pending { .. })
-            && crate::clean_capture::generation(&app) == storage_generation
-            && clean_generation
-                .is_none_or(|generation| crate::clean_capture::is_current(&app, generation));
-        #[cfg(target_os = "linux")]
-        let owns_pending = owns_pending
-            && match (&storage_instant, linux_instant::current(&app)) {
-                (Some(expected), Some(current)) => expected.same(¤t),
-                (None, None) => true,
-                _ => false,
-            };
-        #[cfg(target_os = "linux")]
-        let instant_cancelled = storage_instant
-            .as_ref()
-            .is_some_and(|attempt| attempt.cancelled());
-        #[cfg(not(target_os = "linux"))]
-        let instant_cancelled = false;
-        let storage_result = if !owns_pending
-            || storage_prompt.cancelled.is_cancelled()
-            || instant_cancelled
-            || clean_generation
-                .is_some_and(|generation| crate::clean_capture::stop_requested(&app, generation))
-        {
-            Err(RECORDING_START_CANCELLED.to_string())
-        } else if !requested_state.is_current(&requested_inputs) {
-            Err(
-                "Input selection changed before recording could start. Try recording again."
-                    .to_string(),
-            )
-        } else {
-            storage_result.and_then(|()| requested_state.ready_snapshot().map(|_| ()))
-        };
-        // Stop checks Pending under the same App lock before cancelling this lease.
-        // Retire it here so a successful Stop cannot race admission to capture setup.
-        drop(storage_prompt);
-        if let Err(error) = storage_result {
-            if owns_pending {
-                app_state.clear_pending_recording();
-            }
-            drop(app_state);
-            drop(storage_events);
-            if owns_pending {
-                notify_recording_start_failed(&app, &error);
-            }
-            return Err(error);
-        }
-    }
-    drop(storage_events);
-
-    let project_file_path = recordings_base_dir.join(&pending_try!(
-        cap_utils::ensure_unique_filename(&filename, &recordings_base_dir,),
-        |e| e
-    ));
-    #[cfg(target_os = "linux")]
-    if inputs.mode == RecordingMode::Instant
-        && let Some(attempt) = linux_instant::current(&app)
-    {
-        attempt.set_directory(project_file_path.clone());
-        if attempt.cancelled() {
-            return Err("Instant startup cancelled".into());
-        }
-    }
-
-    pending_try!(ensure_dir(&project_file_path), |e| format!(
-        "Failed to create recording directory: {e}"
-    ));
-    if let Some(generation) = clean_generation {
-        crate::clean_capture::set_start_directory(&app, generation, project_file_path.clone())?;
-    }
-    pending_try!(
-        state_mtx
-            .write()
-            .await
-            .add_recording_logging_handle(&project_file_path.join("recording-logs.log"))
-            .await,
-        |e| e
-    );
-
-    if let Some(window) = CapWindowId::Camera.get(&app)
-        && let Err(error) = window.set_content_protected(
-            matches!(inputs.mode, RecordingMode::Studio)
-                && !crate::windows::capture_exclusion_hides_ui(),
-        )
-    {
-        warn!(%error, "Failed to update camera window content protection");
-    }
-
-    let (video_upload_info, instant_mode_max_resolution) = match inputs.mode {
-        RecordingMode::Instant => {
-            let Some(auth) = instant_auth else {
-                let error = "Please sign in to use instant recording".to_string();
-                state_mtx.write().await.clear_pending_recording();
-                notify_recording_start_failed(&app, &error);
-                return Err(error);
-            };
-            let instant_mode_max_resolution = if auth.is_upgraded() {
-                general_settings
-                    .map_or(cap_recording::PRO_INSTANT_MODE_MAX_RESOLUTION, |settings| {
-                        settings.instant_mode_max_resolution
-                    })
-            } else {
-                cap_recording::FREE_INSTANT_MODE_MAX_RESOLUTION
-            };
-            let upload_mode = if matches!(inputs.capture_target, ScreenCaptureTarget::CameraOnly) {
-                "desktopMP4"
-            } else {
-                "desktopSegments"
-            };
-
-            let created = match crate::upload::create_or_get_video_with_mode(
-                &app,
-                false,
-                None,
-                Some(project_name.clone()),
-                None,
-                inputs.organization_id.clone(),
-                upload_mode,
-            )
-            .await
-            {
-                Ok(meta) => meta,
-                Err(AuthedApiError::InvalidAuthentication) => {
-                    state_mtx.write().await.clear_pending_recording();
-                    // Returned as an action rather than an error, but the picker that
-                    // invoked us may already be gone — surface it as a start failure too.
-                    notify_recording_start_failed(
-                        &app,
-                        "Your session has expired. Please sign in again to use instant recording.",
-                    );
-                    return Ok(RecordingAction::InvalidAuthentication);
-                }
-                Err(AuthedApiError::UpgradeRequired) => {
-                    state_mtx.write().await.clear_pending_recording();
-                    notify_recording_start_failed(
-                        &app,
-                        "Instant recording requires an upgraded plan.",
-                    );
-                    return Ok(RecordingAction::UpgradeRequired);
-                }
-                Err(err) => {
-                    let error = format!("Could not create the shareable link: {err}");
-                    state_mtx.write().await.clear_pending_recording();
-                    notify_recording_start_failed(&app, &error);
-                    return Err(error);
-                }
-            };
-
-            let link = created.link(&app).await;
-            let s3_config = created.config;
-            info!("Pre-created shareable link: {}", link);
-
-            (
-                Some(VideoUploadInfo {
-                    id: s3_config.id.to_string(),
-                    link: link.clone(),
-                    config: s3_config,
-                }),
-                instant_mode_max_resolution,
-            )
-        }
-        RecordingMode::Studio => (None, cap_recording::PRO_INSTANT_MODE_MAX_RESOLUTION),
-        RecordingMode::Screenshot => {
-            let error = "Use take_screenshot for screenshots".to_string();
-            state_mtx.write().await.clear_pending_recording();
-            notify_recording_start_failed(&app, &error);
-            return Err(error);
-        }
-    };
-
-    let meta = RecordingMeta {
-        platform: Some(Platform::default()),
-        project_path: project_file_path.clone(),
-        pretty_name: project_name.clone(),
-        inner: match inputs.mode {
-            RecordingMode::Studio => {
-                RecordingMetaInner::Studio(Box::new(StudioRecordingMeta::MultipleSegments {
-                    inner: MultipleSegments {
-                        segments: Default::default(),
-                        cursors: Default::default(),
-                        status: Some(StudioRecordingStatus::InProgress),
-                    },
-                }))
-            }
-            RecordingMode::Instant => {
-                RecordingMetaInner::Instant(InstantRecordingMeta::InProgress { recording: true })
-            }
-            RecordingMode::Screenshot => {
-                state_mtx.write().await.clear_pending_recording();
-                return Err("Use take_screenshot for screenshots".to_string());
-            }
-        },
-        sharing: None,
-        upload: None,
-    };
-
-    pending_try!(meta.save_for_project(), |e| format!(
-        "Failed to save recording meta: {e}"
-    ));
-
-    if clean_generation.is_none() {
-        match &inputs.capture_target {
-            ScreenCaptureTarget::Window { id: _id } => {
-                if let Some(show) = inputs
-                    .capture_target
-                    .display()
-                    .map(|d| ShowCapWindow::WindowCaptureOccluder { screen_id: d.id() })
-                {
-                    let _ = show.show(&app).await;
-                }
-            }
-            ScreenCaptureTarget::Area { screen, .. } => {
-                let _ = ShowCapWindow::WindowCaptureOccluder {
-                    screen_id: screen.clone(),
-                }
-                .show(&app)
-                .await;
-            }
-            _ => {}
-        }
-    }
-    let countdown = general_settings.and_then(|v| v.recording_countdown);
-    crate::target_select_overlay::close_target_select_overlay_windows(&app);
-    if clean_generation.is_none() {
-        let _ = ShowCapWindow::InProgressRecording {
-            countdown,
-            capture_target: Some(inputs.capture_target.clone()),
-        }
-        .show(&app)
-        .await;
-
-        if let Some(window) = CapWindowId::Main.get(&app) {
-            let _ = general_settings
-                .map(|v| v.main_window_recording_start_behaviour)
-                .unwrap_or_default()
-                .perform(&window);
-        }
-    }
-    let start_gate = cap_recording::RecordingStartGate::new();
-    let start_cue = crate::audio::prime_recording_start_sound();
-    let start_cancelled: Arc> = Arc::default();
-    crate::windows::apply_content_protection(&app, true);
-
-    if let Some(editor_target) = EditorRecordingTarget::current(&app)
-        && let Some(editor_window) = editor_window_for_path(&app, &editor_target)
-    {
-        let _ = editor_window.set_content_protected(!crate::windows::capture_exclusion_hides_ui());
-        let _ = editor_window.minimize();
-    }
-
-    let start_cancel_reason = {
-        let app = app.clone();
-        #[cfg(target_os = "linux")]
-        let mode = inputs.mode;
-        move || -> Option<&'static str> {
-            if clean_generation
-                .is_some_and(|generation| crate::clean_capture::stop_requested(&app, generation))
-            {
-                return Some("Recording cancelled");
-            }
-            #[cfg(target_os = "linux")]
-            if mode == RecordingMode::Instant
-                && linux_instant::current(&app).is_none_or(|attempt| attempt.cancelled())
-            {
-                return Some("Instant startup cancelled");
-            }
-            None
-        }
-    };
-
-    let countdown = countdown.unwrap_or(0);
-    // Every countdown second but the last elapses before the pipeline is
-    // primed; the last one overlaps its warm-up so capture is live at the cue.
-    for t in 0..countdown.saturating_sub(1) {
-        if let Some(reason) = start_cancel_reason() {
-            return Err(reason.into());
-        }
-        let _ = RecordingEvent::Countdown {
-            value: countdown - t,
-        }
-        .emit(&app);
-        countdown_tick(&start_cancel_reason).await?;
-    }
-
-    let start_cue_flow = {
-        let app = app.clone();
-        let start_gate = start_gate.clone();
-        let start_cancelled = start_cancelled.clone();
-        let start_cancel_reason = start_cancel_reason.clone();
-        async move {
-            if countdown >= 1 {
-                let _ = RecordingEvent::Countdown { value: 1 }.emit(&app);
-                if let Err(reason) = countdown_tick(&start_cancel_reason).await {
-                    let _ = start_cancelled.set(reason);
-                    start_gate.arm();
-                    return;
-                }
-                let _ = RecordingEvent::Countdown { value: 0 }.emit(&app);
-            }
-            let cue = crate::audio::play_recording_start_sound(start_cue, start_gate);
-            tokio::pin!(cue);
-            loop {
-                tokio::select! {
-                    _ = &mut cue => break,
-                    _ = tokio::time::sleep(Duration::from_millis(50)) => {}
-                }
-                if let Some(reason) = start_cancel_reason() {
-                    let _ = start_cancelled.set(reason);
-                    break;
-                }
-            }
-        }
-    };
-
-    let (finish_upload_tx, finish_upload_rx) = flume::bounded(1);
-    #[cfg(target_os = "linux")]
-    drop(finish_upload_rx);
-
-    if _input_operation.is_none() {
-        _input_operation = Some(requested_state.operation.lock().await);
-        if !requested_state.is_current(&requested_inputs) {
-            return Err("Input selection changed during startup".into());
-        }
-    }
-
-    debug!("spawning start_recording actor");
-
-    let app_handle = app.clone();
-    let actor_task = {
-        let state_mtx = Arc::clone(&state_mtx);
-        let general_settings = general_settings.cloned();
-        let recording_dir = project_file_path.clone();
-        let inputs = inputs.clone();
-        let start_gate = start_gate.clone();
-        let start_cancelled = start_cancelled.clone();
-        async move {
-            fail!("recording::spawn_actor");
-
-            let (camera_feed_actor, selected_camera_id, selected_camera_settings) = {
-                let state = state_mtx.read().await;
-                let selected_camera_settings =
-                    requested_inputs.camera.value.as_ref().and_then(|id| {
-                        crate::recording_settings::RecordingSettingsStore::camera_settings_for(
-                            &state.handle,
-                            id,
-                        )
-                    });
-                (
-                    state.camera_feed.clone(),
-                    requested_inputs.camera.value.clone(),
-                    selected_camera_settings,
-                )
-            };
-
-            crate::check_requested_camera_permission(
-                selected_camera_id.as_ref(),
-                crate::permissions::check_camera_access,
-            )
-            .map_err(anyhow::Error::msg)?;
-            validate_selected_camera_for_start(
-                selected_camera_id.as_ref(),
-                crate::is_camera_available,
-            )?;
-
-            let camera_feed = lock_selected_camera(
-                &camera_feed_actor,
-                selected_camera_id,
-                selected_camera_settings,
-                &inputs.capture_target,
-            )
-            .await?;
-            debug!(
-                camera_selected = camera_feed.is_some(),
-                "Selected camera locked for recording"
-            );
-
-            let has_camera_feed = camera_feed.is_some();
-
-            #[cfg(target_os = "macos")]
-            let mut shareable_content = match inputs.capture_target {
-                ScreenCaptureTarget::CameraOnly => None,
-                _ => {
-                    debug!("Acquiring shareable content for recording target");
-                    let content =
-                        acquire_shareable_content_for_target(&inputs.capture_target).await?;
-                    debug!("Acquired shareable content for recording target");
-                    Some(content)
-                }
-            };
-
-            let health = crate::recording_telemetry::RecordingHealthAccumulator::new();
-            let common = InProgressRecordingCommon {
-                target_name: project_name,
-                inputs: inputs.clone(),
-                recording_dir: recording_dir.clone(),
-                health,
-                camera_snapshot: Arc::new(std::sync::OnceLock::new()),
-            };
-
-            #[cfg(target_os = "macos")]
-            let excluded_windows = {
-                let window_exclusions = general_settings
-                    .as_ref()
-                    .map_or_else(general_settings::default_excluded_windows, |settings| {
-                        settings.excluded_windows.clone()
-                    });
-
-                let window_exclusions = if matches!(inputs.mode, RecordingMode::Instant) {
-                    let camera_title = CapWindowId::Camera.title();
-                    crate::window_exclusion::filter_for_instant_mode(
-                        window_exclusions,
-                        &camera_title,
-                    )
-                } else {
-                    window_exclusions
-                };
-
-                let teleprompter_exclusion = WindowExclusion {
-                    bundle_identifier: None,
-                    owner_name: None,
-                    window_title: Some(CapWindowId::Teleprompter.title()),
-                };
-                let mut window_exclusions = window_exclusions;
-                if !window_exclusions.contains(&teleprompter_exclusion) {
-                    window_exclusions.push(teleprompter_exclusion);
-                }
-
-                let mut excluded_window_ids =
-                    crate::window_exclusion::resolve_window_ids(&window_exclusions);
-                crate::window_exclusion::append_matching_webview_window_ids(
-                    &mut excluded_window_ids,
-                    &app_handle,
-                    &window_exclusions,
-                );
-                info!(
-                    configured_exclusions = window_exclusions.len(),
-                    resolved_window_ids = excluded_window_ids.len(),
-                    "Resolved macOS recording window exclusions"
-                );
-                excluded_window_ids
-            };
-
-            let mut mic_restart_attempts = 0;
-
-            let (done_fut, health_rx, automatic_stop) = loop {
-                let actor_result: Result = async {
-                    if !app_handle
-                        .state::()
-                        .is_current(&requested_inputs)
-                    {
-                        return Err(anyhow!(
-                            "Input selection changed during recording startup. Try recording again."
-                        ));
-                    }
-                    let selected_mic_label = match requested_inputs.microphone.value.clone() {
-                        Some(label) => selected_microphone_for_start(
-                            Some(label),
-                            µphone::MicrophoneFeed::list_names(),
-                        )?,
-                        None => None,
-                    };
-                    let (mic_actor, selected_mic_settings) = {
-                        let mut state = state_mtx.write().await;
-                        let settings = selected_mic_label
-                            .as_ref()
-                            .and_then(|label| state.microphone_settings_for_label(label));
-                        state.applied_mic_input.invalidate();
-                        (state.mic_feed.clone(), settings)
-                    };
-                    debug!(
-                        mic_selected = selected_mic_label.is_some(),
-                        "Locking selected microphone for recording"
-                    );
-                    let mic_feed = lock_selected_microphone(
-                        &mic_actor,
-                        selected_mic_label,
-                        selected_mic_settings,
-                    )
-                    .await?;
-                    debug!(
-                        mic_selected = mic_feed.is_some(),
-                        "Selected microphone locked for recording"
-                    );
-                    let defaults = desktop_recording_defaults(general_settings.as_ref());
-
-                    match inputs.mode {
-                        RecordingMode::Studio => {
-                            let mut builder = defaults.apply_to_studio_builder(
-                                studio_recording::Actor::builder(
-                                    recording_dir.clone(),
-                                    inputs.capture_target.clone(),
-                                )
-                                .with_system_audio(inputs.capture_system_audio),
-                                camera_feed.is_some(),
-                                None,
-                            );
-
-                            builder = builder.with_start_gate(start_gate.clone());
-
-                            #[cfg(target_os = "macos")]
-                            {
-                                builder = builder.with_excluded_windows(excluded_windows.clone());
-                            }
-
-                            if let Some(camera_feed) = camera_feed.clone() {
-                                builder = builder.with_camera_feed(camera_feed);
-                            }
-
-                            if let Some(mic_feed) = mic_feed.clone() {
-                                builder = builder.with_mic_feed(mic_feed);
-                            }
-
-                            debug!("Building studio recording actor");
-                            let handle = builder
-                                .build(
-                                    #[cfg(target_os = "macos")]
-                                    shareable_content.clone(),
-                                )
-                                .await
-                                .map_err(|e| {
-                                    error!("Failed to spawn studio recording actor: {e:#}");
-                                    e
-                                })?;
-
-                            debug!("Studio recording actor built");
-                            Ok(InProgressRecording::Studio {
-                                handle,
-                                common: common.clone(),
-                                mic_feed: mic_feed.clone(),
-                                camera_feed: camera_feed.clone(),
-                            })
-                        }
-                        RecordingMode::Instant => {
-                            let Some(video_upload_info) = video_upload_info.clone() else {
-                                return Err(anyhow!("Video upload info not found"));
-                            };
-
-                            let mut builder = instant_recording::Actor::builder(
-                                recording_dir.clone(),
-                                inputs.capture_target.clone(),
-                            )
-                            .with_system_audio(inputs.capture_system_audio)
-                            .with_max_output_size(instant_mode_max_resolution);
-
-                            builder = builder.with_start_gate(start_gate.clone());
-
-                            #[cfg(target_os = "macos")]
-                            {
-                                builder = builder.with_excluded_windows(excluded_windows.clone());
-                            }
-
-                            if let Some(camera_feed) = camera_feed.clone() {
-                                builder = builder.with_camera_feed(camera_feed);
-                            }
-
-                            if let Some(mic_feed) = mic_feed.clone() {
-                                builder = builder.with_mic_feed(mic_feed);
-                            }
-
-                            #[cfg(target_os = "linux")]
-                            let attempt = linux_instant::current(&app_handle)
-                                .ok_or_else(|| anyhow!("Instant startup owner was lost"))?;
-                            #[cfg(target_os = "linux")]
-                            attempt
-                                .attach(recording_dir.clone(), builder.lifecycle())
-                                .await
-                                .map_err(anyhow::Error::msg)?;
-                            #[cfg(target_os = "linux")]
-                            {
-                                let prepared = match clean_generation {
-                                    Some(generation) => linux_instant::prepare_screen_camera(
-                                        &app_handle,
-                                        &attempt,
-                                        generation,
-                                        &inputs,
-                                        &requested_inputs,
-                                        camera_feed.clone(),
-                                    )
-                                    .await
-                                    .map_err(anyhow::Error::msg)?,
-                                    None => None,
-                                };
-                                builder = linux_instant::configure_screen_camera(
-                                    builder,
-                                    &inputs.capture_target,
-                                    requested_inputs.camera.value.is_some(),
-                                    prepared,
-                                )
-                                .map_err(anyhow::Error::msg)?;
-                                attempt.checked(Ok(())).map_err(anyhow::Error::msg)?;
-                            }
-                            let upload_session = crate::upload::lifecycle::prepare(
-                                &app_handle,
-                                &recording_dir,
-                                &video_upload_info.id,
-                                inputs.capture_system_audio || mic_feed.is_some(),
-                            )
-                            .await
-                            .map_err(anyhow::Error::from)?;
-                            let handle = builder
-                                .build(
-                                    #[cfg(target_os = "macos")]
-                                    shareable_content.clone(),
-                                )
-                                .await
-                                .map_err(|e| {
-                                    error!("Failed to spawn instant recording actor: {e:#}");
-                                    e
-                                })?;
-
-                            #[cfg(target_os = "linux")]
-                            let handle = Arc::new(handle);
-                            #[cfg(target_os = "linux")]
-                            let segment_upload = {
-                                let events = handle.take_segment_rx();
-                                linux_instant::persist_upload_start(
-                                    &recording_dir,
-                                    &video_upload_info,
-                                    events.is_some(),
-                                )
-                                .map_err(anyhow::Error::msg)?;
-                                attempt.upload_started();
-                                Arc::new(tokio::sync::Mutex::new(
-                                    crate::upload::strict_instant::spawn(
-                                        app_handle.clone(),
-                                        upload_session,
-                                        video_upload_info.clone(),
-                                        events,
-                                        attempt.upload(),
-                                        inputs.capture_system_audio || mic_feed.is_some(),
-                                    ),
-                                ))
-                            };
-                            #[cfg(not(target_os = "linux"))]
-                            let segment_upload = {
-                                let segment_rx = handle.take_segment_rx();
-
-                                if let Some(rx) = segment_rx {
-                                    SegmentUploader::spawn(
-                                        app_handle.clone(),
-                                        rx,
-                                        Some(finish_upload_rx.clone()),
-                                        upload_session,
-                                        video_upload_info.clone(),
-                                        inputs.capture_system_audio || mic_feed.is_some(),
-                                    )
-                                } else {
-                                    let progressive_upload = InstantMultipartUpload::spawn(
-                                        app_handle.clone(),
-                                        recording_dir.join("content/output.mp4"),
-                                        video_upload_info.clone(),
-                                        upload_session,
-                                        Some(finish_upload_rx.clone()),
-                                        inputs.capture_system_audio || mic_feed.is_some(),
-                                    );
-                                    SegmentUploader {
-                                        handle: progressive_upload.handle,
-                                        session: progressive_upload.session,
-                                    }
-                                }
-                            };
-
-                            Ok(InProgressRecording::Instant {
-                                handle,
-                                segment_upload,
-                                video_upload_info,
-                                common: common.clone(),
-                                mic_feed: mic_feed.clone(),
-                                camera_feed: camera_feed.clone(),
-                            })
-                        }
-                        RecordingMode::Screenshot => Err(anyhow!(
-                            "Screenshot mode should be handled via take_screenshot"
-                        )),
-                    }
-                }
-                .await;
-
-                match actor_result {
-                    Ok(mut actor) => {
-                        // The recording stays out of app state until the cue has
-                        // armed the gate, so nothing reports "recording" while the
-                        // primed pipeline is still discarding frames.
-                        while !start_gate.is_armed() && start_cancelled.get().is_none() {
-                            tokio::time::sleep(Duration::from_millis(10)).await;
-                        }
-                        let mut state = state_mtx.write().await;
-                        if let Some(reason) = start_cancelled.get().copied() {
-                            drop(state);
-                            let _ = cancel_discarded_recording(&app_handle, actor).await;
-                            return Err(anyhow!(reason));
-                        }
-                        if clean_generation.is_some_and(|generation| {
-                            !crate::clean_capture::is_current(&app_handle, generation)
-                        }) || !matches!(state.recording_state, RecordingState::Pending { .. })
-                        {
-                            drop(state);
-                            let _ = cancel_discarded_recording(&app_handle, actor).await;
-                            return Err(anyhow!("Recording startup was cancelled or superseded"));
-                        }
-                        #[cfg(target_os = "linux")]
-                        if inputs.mode == RecordingMode::Instant
-                            && (linux_instant::current(&app_handle).is_none_or(|attempt| {
-                                attempt.cancelled() || !attempt.owns_directory(&recording_dir)
-                            }) || clean_generation.is_some_and(|generation| {
-                                crate::clean_capture::stop_requested(&app_handle, generation)
-                            }) || !app_handle
-                                .state::()
-                                .is_current(&requested_inputs))
-                        {
-                            drop(state);
-                            let _ = cancel_discarded_recording(&app_handle, actor).await;
-                            return Err(anyhow!("Instant startup was cancelled"));
-                        }
-                        let done_fut = actor.done_fut();
-                        let health_rx = actor.take_health_rx();
-                        let mut candidate = Some(actor);
-                        let published = app_handle
-                            .state::()
-                            .publish_if_current(&requested_inputs, || {
-                                state.selected_mic_label =
-                                    requested_inputs.microphone.value.clone();
-                                state.selected_camera_id = requested_inputs.camera.value.clone();
-                                state.camera_in_use = has_camera_feed;
-                                state.applied_mic_input.confirm();
-                                state.set_current_recording(candidate.take().unwrap());
-                                if let Some(generation) = clean_generation {
-                                    crate::clean_capture::publish(
-                                        &app_handle,
-                                        generation,
-                                        recording_dir.clone(),
-                                    );
-                                }
-                            });
-                        if !published {
-                            drop(state);
-                            let _ =
-                                cancel_discarded_recording(&app_handle, candidate.take().unwrap())
-                                    .await;
-                            return Err(anyhow!(
-                                "Input selection changed during recording startup. Try recording again."
-                            ));
-                        }
-                        #[cfg(any(target_os = "linux", target_os = "macos", windows))]
-                        let automatic_stop = match state.current_recording() {
-                            Some(InProgressRecording::Studio { handle, common, .. }) => {
-                                Some(enroll_studio_stop(
-                                    &app_handle,
-                                    &state_mtx,
-                                    handle,
-                                    &common.recording_dir,
-                                    crate::clean_capture::owner(&app_handle, &common.recording_dir),
-                                    StudioStopOrigin::Automatic,
-                                ))
-                            }
-                            _ => None,
-                        };
-                        #[cfg(not(any(target_os = "linux", target_os = "macos", windows)))]
-                        let automatic_stop = ();
-                        break (done_fut, health_rx, automatic_stop);
-                    }
-                    #[cfg(target_os = "macos")]
-                    Err(err) if is_shareable_content_error(&err) => {
-                        shareable_content = Some(
-                            acquire_shareable_content_for_target(&inputs.capture_target).await?,
-                        );
-                        continue;
-                    }
-                    Err(err)
-                        if mic_restart_attempts < 3
-                            && !(inputs.mode == RecordingMode::Instant
-                                && clean_generation.is_some())
-                            && (mic_actor_not_running(&err) || mic_feed_locked(&err)) =>
-                    {
-                        mic_restart_attempts += 1;
-                        warn!(
-                            attempt = mic_restart_attempts,
-                            error = %err,
-                            "Recovering microphone feed before retrying recording start"
-                        );
-                        if clean_generation.is_some() {
-                            if mic_feed_locked(&err) {
-                                tokio::time::sleep(Duration::from_millis(50)).await;
-                                continue;
-                            }
-                            return Err(anyhow!(
-                                "The selected microphone stopped during startup. Reselect it before recording: {err:#}"
-                            ));
-                        }
-                        state_mtx
-                            .write()
-                            .await
-                            .restart_mic_feed()
-                            .await
-                            .map_err(|restart_err| anyhow!(restart_err))?;
-                        tokio::time::sleep(Duration::from_millis(250)).await;
-                    }
-                    Err(err) => return Err(err),
-                }
-            };
-
-            Ok::<_, anyhow::Error>((done_fut, health_rx, automatic_stop))
-        }
-    };
-
-    let (actor_task_res, ()) =
-        futures::join!(AssertUnwindSafe(actor_task).catch_unwind(), start_cue_flow);
-
-    let (actor_done_fut, health_rx, automatic_stop) = match actor_task_res {
-        Ok(Ok(v)) => v,
-        Ok(Err(err))
-            if start_cancelled
-                .get()
-                .is_some_and(|reason| err.to_string() == *reason) =>
-        {
-            return Err(err.to_string());
-        }
-        Ok(Err(err)) => {
-            let message = format!("{err:#}");
-            handle_spawn_failure(
-                &app,
-                &state_mtx,
-                project_file_path.as_path(),
-                message.clone(),
-            )
-            .await?;
-            return Err(message);
-        }
-        Err(panic) => {
-            let panic_msg = panic_message(panic);
-            let message = format!("Failed to spawn recording actor: {panic_msg}");
-            handle_spawn_failure(
-                &app,
-                &state_mtx,
-                project_file_path.as_path(),
-                message.clone(),
-            )
-            .await?;
-            return Err(message);
-        }
-    };
-
-    let (watcher_started_tx, watcher_started_rx) = tokio::sync::oneshot::channel::<()>();
-    spawn_actor({
-        let app = app.clone();
-        let state_mtx = Arc::clone(&state_mtx);
-        let project_file_path = project_file_path.clone();
-        #[cfg(any(target_os = "linux", target_os = "macos", windows))]
-        let instant_watch = inputs.mode == RecordingMode::Instant;
-        async move {
-            let _ = watcher_started_rx.await;
-            fail!("recording::wait_actor_done");
-            let disposition = {
-                let res = actor_done_fut.await;
-                #[cfg(target_os = "linux")]
-                if instant_watch {
-                    if let Some(attempt) = linux_instant::current(&app)
-                        && attempt.owns_directory(&project_file_path)
-                        && attempt.terminal_needs_cleanup()
-                    {
-                        let _ = linux_instant::control(app.clone(), attempt, false).await;
-                    }
-                    return;
-                }
-                #[cfg(any(target_os = "linux", target_os = "macos", windows))]
-                if !instant_watch {
-                    let terminal_started = {
-                        let state = state_mtx.read().await;
-                        let Some(InProgressRecording::Studio { handle, common, .. }) =
-                            state.current_recording()
-                        else {
-                            return;
-                        };
-                        if common.recording_dir != project_file_path
-                            || automatic_stop.as_ref().is_none_or(|participant| {
-                                !participant.cohort.identity.matches(
-                                    handle,
-                                    &common.recording_dir,
-                                    crate::clean_capture::owner(&app, &common.recording_dir),
-                                )
-                            })
-                        {
-                            return;
-                        }
-                        #[cfg(target_os = "linux")]
-                        let started = handle.lifecycle().terminal_started();
-                        #[cfg(any(target_os = "macos", windows))]
-                        let started = handle.terminal_started();
-                        started
-                    };
-                    if clean_generation.is_some_and(|generation| {
-                        crate::clean_capture::owner(&app, &project_file_path) != Some(generation)
-                    }) {
-                        return;
-                    }
-                    let follow_stop = automatic_stop.as_ref().is_some_and(|participant| {
-                        participant.cohort.flight.lock().unwrap().explicit_seen
-                    }) || matches!(
-                        crate::clean_capture::phase(&app),
-                        Some(
-                            crate::clean_capture::Phase::Stopping
-                                | crate::clean_capture::Phase::Restoring
-                        )
-                    );
-                    if terminal_started && !follow_stop {
-                        return;
-                    }
-                    let failure = if follow_stop {
-                        res.err().map(|error| error.to_string())
-                    } else {
-                        match classify_actor_done_result(res, true) {
-                            ActorDoneDisposition::UnexpectedStop { error }
-                            | ActorDoneDisposition::Failed { error } => Some(error),
-                            ActorDoneDisposition::UserInitiatedStop => None,
-                        }
-                    };
-                    if let Some(completion) = control_studio_recording(
-                        &app,
-                        &state_mtx,
-                        Some(&project_file_path),
-                        StudioTerminalAction::Stop,
-                        failure,
-                        automatic_stop,
-                    )
-                    .await
-                    {
-                        completion.present_automatic();
-                    }
-                    return;
-                }
-                if let Some(generation) = clean_generation
-                    && (crate::clean_capture::owner(&app, &project_file_path) != Some(generation)
-                        || matches!(
-                            crate::clean_capture::phase(&app),
-                            Some(
-                                crate::clean_capture::Phase::Stopping
-                                    | crate::clean_capture::Phase::Restoring
-                            )
-                        ))
-                {
-                    return;
-                }
-                info!("recording wait actor done: {:?}", &res);
-                let recording_still_active = matches!(
-                    state_mtx.read().await.recording_state,
-                    RecordingState::Active(_)
-                );
-                classify_actor_done_result(res, recording_still_active)
-            };
-            match disposition {
-                ActorDoneDisposition::UserInitiatedStop => {
-                    let _ = finish_upload_tx.send(());
-                    let _ = RecordingEvent::Stopped.emit(&app);
-                }
-                ActorDoneDisposition::UnexpectedStop { error }
-                | ActorDoneDisposition::Failed { error } => {
-                    let mut state = state_mtx.write().await;
-                    if let Some(generation) = clean_generation
-                        && (crate::clean_capture::owner(&app, &project_file_path)
-                            != Some(generation)
-                            || state.current_recording().is_none_or(|recording| {
-                                recording.recording_dir() != &project_file_path
-                            })
-                            || matches!(
-                                crate::clean_capture::phase(&app),
-                                Some(
-                                    crate::clean_capture::Phase::Stopping
-                                        | crate::clean_capture::Phase::Restoring
-                                )
-                            ))
-                    {
-                        return;
-                    }
-
-                    let _ = RecordingEvent::Failed {
-                        error: error.clone(),
-                    }
-                    .emit(&app);
-
-                    let mut dialog = MessageDialogBuilder::new(
-                        app.dialog().clone(),
-                        "An error occurred".to_string(),
-                        error.clone(),
-                    )
-                    .kind(tauri_plugin_dialog::MessageDialogKind::Error);
-
-                    if let Some(window) = CapWindowId::RecordingControls.get(&app) {
-                        dialog = dialog.parent(&window);
-                    }
-
-                    if crate::clean_capture::phase(&app).is_none() {
-                        dialog.blocking_show();
-                    }
-
-                    handle_recording_end(app, Err(error), &mut state, project_file_path)
-                        .await
-                        .ok();
-                }
-            }
-        }
-    });
-
-    drop(_input_operation);
-    if clean_generation
-        .is_some_and(|generation| crate::clean_capture::stop_requested(&app, generation))
-    {
-        #[cfg(target_os = "linux")]
-        if inputs.mode == RecordingMode::Instant {
-            if let Some(attempt) = linux_instant::current(&app) {
-                attempt.cancel();
-            }
-            return Err("Instant startup cancelled".into());
-        }
-        if inputs.mode == RecordingMode::Studio {
-            if let Some(generation) = clean_generation
-                && let Some(identity) =
-                    studio_stop_registry(&app).active_identity(&project_file_path, generation)
-            {
-                Box::pin(stop_clean_studio_recording(
-                    app.clone(),
-                    identity.handle,
-                    generation,
-                    project_file_path.clone(),
-                ))
-                .await?;
-            }
-        } else {
-            Box::pin(stop_recording(app.clone(), state_mtx.clone())).await?;
-        }
-        return Ok(RecordingAction::Started);
-    }
-
-    if matches!(inputs.mode, RecordingMode::Studio) {
-        spawn_current_desktop_background_snapshot(
-            project_file_path.clone(),
-            inputs.capture_target.clone(),
-        );
-    }
-
-    let _ = RecordingEvent::Started.emit(&app);
-    let _ = RecordingStarted.emit(&app);
-    let _ = watcher_started_tx.send(());
-
-    emit_recording_started_telemetry(&app, &state_mtx).await;
-
-    if let Some(mut health_rx) = health_rx {
-        let accumulator_mode = {
-            let state = state_mtx.read().await;
-            state
-                .current_recording()
-                .map(|r| (r.common().health.clone(), r.inputs().mode))
-        };
-
-        spawn_actor({
-            let app = app.clone();
-            async move {
-                let mut is_degraded = false;
-                while let Some(event) = health_rx.recv().await {
-                    if let Some((health, mode)) = accumulator_mode.as_ref()
-                        && let Some((reason_text, critical)) = health.record_event(&event)
-                    {
-                        use crate::recording_telemetry::{CriticalEvent, mode_label};
-                        use crate::telemetry::{AnalyticsEvent, async_capture_event};
-                        match critical {
-                            CriticalEvent::MuxerCrashed {
-                                seconds_into_recording,
-                                ..
-                            } => {
-                                async_capture_event(
-                                    &app,
-                                    AnalyticsEvent::RecordingMuxerCrashed {
-                                        mode: mode_label(*mode),
-                                        reason: reason_text,
-                                        seconds_into_recording,
-                                    },
-                                );
-                            }
-                            CriticalEvent::AudioDegraded {
-                                seconds_into_recording,
-                                ..
-                            } => {
-                                async_capture_event(
-                                    &app,
-                                    AnalyticsEvent::RecordingAudioDegraded {
-                                        mode: mode_label(*mode),
-                                        reason: reason_text,
-                                        seconds_into_recording,
-                                    },
-                                );
-                            }
-                        }
-                    }
-
-                    if let Some((_, mode)) = accumulator_mode.as_ref() {
-                        use crate::recording_telemetry::mode_label;
-                        use crate::telemetry::{AnalyticsEvent, async_capture_event};
-                        let mode_str = mode_label(*mode);
-                        match &event {
-                            cap_recording::PipelineHealthEvent::DiskSpaceLow {
-                                bytes_remaining,
-                                ..
-                            } => async_capture_event(
-                                &app,
-                                AnalyticsEvent::RecordingDiskSpaceLow {
-                                    mode: mode_str,
-                                    bytes_remaining: *bytes_remaining,
-                                },
-                            ),
-                            cap_recording::PipelineHealthEvent::DiskSpaceExhausted {
-                                bytes_remaining,
-                            } => async_capture_event(
-                                &app,
-                                AnalyticsEvent::RecordingDiskSpaceExhausted {
-                                    mode: mode_str,
-                                    bytes_remaining: *bytes_remaining,
-                                },
-                            ),
-                            cap_recording::PipelineHealthEvent::DeviceLost { subsystem } => {
-                                async_capture_event(
-                                    &app,
-                                    AnalyticsEvent::RecordingDeviceLost {
-                                        mode: mode_str,
-                                        subsystem: subsystem.clone(),
-                                    },
-                                )
-                            }
-                            cap_recording::PipelineHealthEvent::EncoderRebuilt {
-                                backend,
-                                attempt,
-                            } => async_capture_event(
-                                &app,
-                                AnalyticsEvent::RecordingEncoderRebuilt {
-                                    mode: mode_str,
-                                    backend: backend.clone(),
-                                    attempt: *attempt,
-                                },
-                            ),
-                            cap_recording::PipelineHealthEvent::SourceAudioReset {
-                                source,
-                                starvation_ms,
-                            } => async_capture_event(
-                                &app,
-                                AnalyticsEvent::RecordingSourceAudioReset {
-                                    mode: mode_str,
-                                    source: source.clone(),
-                                    starvation_ms: *starvation_ms,
-                                },
-                            ),
-                            cap_recording::PipelineHealthEvent::CaptureTargetLost { target } => {
-                                async_capture_event(
-                                    &app,
-                                    AnalyticsEvent::RecordingCaptureTargetLost {
-                                        mode: mode_str,
-                                        target: target.clone(),
-                                    },
-                                )
-                            }
-                            cap_recording::PipelineHealthEvent::RecoveryFragmentCorrupt {
-                                ..
-                            } => {}
-                            _ => {}
-                        }
-                    }
-
-                    let reason = match &event {
-                        cap_recording::PipelineHealthEvent::FrameDropRateHigh {
-                            source,
-                            rate_pct,
-                        } => Some(format!("High frame drop rate on {source}: {rate_pct:.0}%")),
-                        cap_recording::PipelineHealthEvent::AudioGapDetected { gap_ms } => {
-                            Some(format!("Audio gap detected: {gap_ms}ms"))
-                        }
-                        cap_recording::PipelineHealthEvent::SourceRestarting => {
-                            Some("Capture source restarting".to_string())
-                        }
-                        cap_recording::PipelineHealthEvent::AudioDegradedToVideoOnly { reason } => {
-                            Some(format!("Audio lost: {reason}"))
-                        }
-                        cap_recording::PipelineHealthEvent::Stalled { source, waited_ms } => {
-                            Some(format!("Pipeline stalled on {source} ({waited_ms}ms)"))
-                        }
-                        cap_recording::PipelineHealthEvent::MuxerCrashed { reason } => {
-                            Some(format!("Muxer crashed: {reason}"))
-                        }
-                        cap_recording::PipelineHealthEvent::DiskSpaceLow {
-                            bytes_remaining,
-                            ..
-                        } => Some(format!(
-                            "Low disk space: {:.2} GB remaining",
-                            *bytes_remaining as f64 / 1_073_741_824.0
-                        )),
-                        cap_recording::PipelineHealthEvent::DiskSpaceExhausted {
-                            bytes_remaining,
-                        } => Some(format!(
-                            "Disk full: {:.2} GB remaining",
-                            *bytes_remaining as f64 / 1_073_741_824.0
-                        )),
-                        cap_recording::PipelineHealthEvent::DeviceLost { subsystem } => {
-                            Some(format!("Graphics device lost: {subsystem}"))
-                        }
-                        cap_recording::PipelineHealthEvent::EncoderRebuilt { backend, attempt } => {
-                            Some(format!("Encoder rebuilt: {backend} (attempt {attempt})"))
-                        }
-                        cap_recording::PipelineHealthEvent::SourceAudioReset {
-                            source,
-                            starvation_ms,
-                        } => Some(format!("Audio source reset: {source} ({starvation_ms}ms)")),
-                        cap_recording::PipelineHealthEvent::RecoveryFragmentCorrupt {
-                            path,
-                            reason,
-                        } => Some(format!(
-                            "Corrupt recovery fragment skipped: {path} ({reason})"
-                        )),
-                        cap_recording::PipelineHealthEvent::CaptureTargetLost { target } => {
-                            Some(format!("Capture target lost: {target}"))
-                        }
-                        cap_recording::PipelineHealthEvent::MicrophoneDigitalSilence => Some(
-                            "Microphone is recording silence. Another app, like a call, may be using it."
-                                .to_string(),
-                        ),
-                        cap_recording::PipelineHealthEvent::SourceRestarted => None,
-                    };
-
-                    if let Some(reason) = reason {
-                        if !is_degraded {
-                            is_degraded = true;
-                            RecordingEvent::Degraded { reason }.emit(&app).ok();
-                        }
-                    } else if matches!(event, cap_recording::PipelineHealthEvent::SourceRestarted)
-                        && is_degraded
-                    {
-                        is_degraded = false;
-                        RecordingEvent::Recovered.emit(&app).ok();
-                    }
-                }
-            }
-        });
-    }
-
-    Ok(RecordingAction::Started)
-}
-
-async fn countdown_tick(
-    cancel_reason: &impl Fn() -> Option<&'static str>,
-) -> Result<(), &'static str> {
-    let tick = tokio::time::sleep(Duration::from_secs(1));
-    tokio::pin!(tick);
-    loop {
-        tokio::select! {
-            _ = &mut tick => break,
-            _ = tokio::time::sleep(Duration::from_millis(50)) => {}
-        }
-        if let Some(reason) = cancel_reason() {
-            return Err(reason);
-        }
-    }
-    cancel_reason().map_or(Ok(()), Err)
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app, state))]
-pub async fn get_recording_pause_state(
-    app: AppHandle,
-    state: MutableState<'_, App>,
-) -> Result, String> {
-    let query: std::pin::Pin> + Send>> =
-        if crate::clean_capture::phase(&app).is_some() {
-            Box::pin(async move { crate::clean_capture::is_paused(&app).await })
-        } else {
-            let state = state.read().await;
-            match state.current_recording() {
-                Some(InProgressRecording::Studio { handle, .. }) => {
-                    let handle = handle.clone();
-                    Box::pin(
-                        async move { handle.is_paused().await.map_err(|error| error.to_string()) },
-                    )
-                }
-                Some(InProgressRecording::Instant { handle, .. }) => {
-                    let query = handle.is_paused();
-                    Box::pin(async move { query.await.map_err(|error| error.to_string()) })
-                }
-                None => return Ok(None),
-            }
-        };
-    tokio::time::timeout(Duration::from_secs(2), query)
-        .await
-        .map_err(|_| "Timed out confirming recording pause state".to_string())?
-        .map(Some)
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app, state))]
-pub async fn pause_recording(app: AppHandle, state: MutableState<'_, App>) -> Result<(), String> {
-    if crate::clean_capture::phase(&app).is_some() {
-        return crate::clean_capture::control(&app, false).await;
-    }
-    let mut state = state.write().await;
-
-    if let Some(recording) = state.current_recording_mut() {
-        recording.pause().await.map_err(|e| e.to_string())?;
-        RecordingEvent::Paused.emit(&app).ok();
-    }
-
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app, state))]
-pub async fn resume_recording(app: AppHandle, state: MutableState<'_, App>) -> Result<(), String> {
-    let requested = app.state::();
-    let _input_operation = requested.try_resume_guard()?;
-    if crate::clean_capture::phase(&app).is_some() {
-        requested.ensure_ready_for_resume()?;
-        return crate::clean_capture::control(&app, true).await;
-    }
-    let mut state = state.write().await;
-    requested.ensure_ready_for_resume()?;
-
-    if let Some(recording) = state.current_recording_mut() {
-        recording.resume().await.map_err(|e| e.to_string())?;
-        RecordingEvent::Resumed.emit(&app).ok();
-    }
-
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(state))]
-pub async fn set_mic_recording_muted(
-    state: MutableState<'_, App>,
-    muted: bool,
-) -> Result<(), String> {
-    let state = state.read().await;
-
-    let Some(recording) = state.current_recording() else {
-        return Err("No recording in progress".to_string());
-    };
-
-    let mic_feed = match recording {
-        InProgressRecording::Instant { mic_feed, .. } => mic_feed.as_ref(),
-        // Studio records the mic as an editable track; muting would silently
-        // bake zeros into it. The bar only offers mute for instant mode —
-        // enforce the same contract here so no future caller can corrupt a
-        // studio track.
-        InProgressRecording::Studio { .. } => {
-            return Err("Mic mute is only available for instant recordings".to_string());
-        }
-    };
-
-    let Some(mic_feed) = mic_feed else {
-        return Err("Recording has no microphone".to_string());
-    };
-
-    mic_feed.set_recording_muted(muted);
-    info!(muted, "Recording microphone mute set");
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app, state))]
-pub async fn toggle_pause_recording(
-    app: AppHandle,
-    state: MutableState<'_, App>,
-) -> Result<(), String> {
-    if crate::clean_capture::phase(&app).is_some() {
-        if crate::clean_capture::is_paused(&app).await? {
-            let requested = app.state::();
-            let _input_operation = requested.try_resume_guard()?;
-            return crate::clean_capture::control(&app, true).await;
-        }
-        return crate::clean_capture::control(&app, false).await;
-    }
-    let state = state.read().await;
-
-    if let Some(recording) = state.current_recording() {
-        if recording.is_paused().await.map_err(|e| e.to_string())? {
-            let requested = app.state::();
-            let _input_operation = requested.try_resume_guard()?;
-            recording.resume().await.map_err(|e| e.to_string())?;
-            RecordingEvent::Resumed.emit(&app).ok();
-        } else {
-            recording.pause().await.map_err(|e| e.to_string())?;
-            RecordingEvent::Paused.emit(&app).ok();
-        }
-    }
-
-    Ok(())
-}
-
-async fn handle_spawn_failure(
-    app: &AppHandle,
-    state_mtx: &MutableState<'_, App>,
-    recording_dir: &Path,
-    message: String,
-) -> Result<(), String> {
-    #[cfg(target_os = "linux")]
-    if linux_instant::current(app).is_some_and(|attempt| attempt.owns_directory(recording_dir)) {
-        notify_recording_start_failed(app, &message);
-        return Err(message);
-    }
-    error!(
-        recording_dir = %recording_dir.display(),
-        error = %message,
-        "Recording actor spawn failed"
-    );
-
-    let _ = RecordingEvent::Failed {
-        error: message.clone(),
-    }
-    .emit(app);
-
-    // DeviceNotFound errors are surfaced to the user via the frontend toast; skip the
-    // blocking native dialog so the overlay stays responsive and the error isn't repeated.
-    let is_device_not_found =
-        message.contains("no longer available") || message.contains("DeviceNotFound");
-
-    if !is_device_not_found && crate::clean_capture::phase(app).is_none() {
-        let mut dialog = MessageDialogBuilder::new(
-            app.dialog().clone(),
-            "An error occurred".to_string(),
-            message.clone(),
-        )
-        .kind(tauri_plugin_dialog::MessageDialogKind::Error);
-
-        if let Some(window) = CapWindowId::RecordingControls.get(app) {
-            dialog = dialog.parent(&window);
-        }
-
-        dialog.blocking_show();
-    }
-
-    let mut state = state_mtx.write().await;
-    let _ = handle_recording_end(
-        app.clone(),
-        Err(message),
-        &mut state,
-        recording_dir.to_path_buf(),
-    )
-    .await;
-
-    Ok(())
-}
-
-fn panic_message(panic: Box) -> String {
-    if let Some(msg) = panic.downcast_ref::<&str>() {
-        msg.to_string()
-    } else if let Some(msg) = panic.downcast_ref::() {
-        msg.clone()
-    } else {
-        "unknown panic".to_string()
-    }
-}
-
-async fn lock_selected_microphone(
-    mic_feed: &kameo::actor::ActorRef,
-    selected_label: Option,
-    selected_settings: Option,
-) -> anyhow::Result>> {
-    let Some(label) = selected_label else {
-        return Ok(None);
-    };
-
-    permissions::check_microphone_access().map_err(anyhow::Error::msg)?;
-
-    let existing_lock = match mic_feed.ask(microphone::Lock).await {
-        Ok(lock) if lock.device_name() == label => Some(lock),
-        Ok(lock) => {
-            drop(lock);
-            tokio::time::sleep(Duration::from_millis(50)).await;
-            None
-        }
-        Err(kameo::error::SendError::HandlerError(microphone::LockFeedError::NoInput)) => None,
-        Err(err) => {
-            return Err(anyhow!(
-                "Failed to lock selected microphone '{label}': {err}"
-            ));
-        }
-    };
-
-    let lock = if let Some(lock) = existing_lock {
-        lock
-    } else {
-        initialize_selected_microphone(mic_feed, &label, selected_settings).await?;
-        lock_initialized_microphone(mic_feed, &label).await?
-    };
-
-    validate_microphone_receiving(&lock, &label).await?;
-    Ok(Some(Arc::new(lock)))
-}
-
-fn mic_actor_not_running(err: &anyhow::Error) -> bool {
-    err.chain().any(|cause| {
-        if let Some(source) = cause.downcast_ref::() {
-            matches!(source, MicrophoneSourceError::ActorNotRunning)
-        } else {
-            false
-        }
-    })
-}
-
-fn mic_feed_locked(err: &anyhow::Error) -> bool {
-    err.chain().any(|cause| {
-        cause
-            .downcast_ref::()
-            .is_some()
-            || cause
-                .downcast_ref::()
-                .is_some_and(|err| matches!(err, microphone::LockFeedError::Locked(_)))
-            || cause
-                .downcast_ref::()
-                .is_some_and(|err| matches!(err, microphone::SetInputError::Locked(_)))
-    }) || err.to_string().contains("FeedLocked")
-}
-
-#[derive(Debug, PartialEq, Eq)]
-enum ActorDoneDisposition {
-    UserInitiatedStop,
-    UnexpectedStop { error: String },
-    Failed { error: String },
-}
-
-fn classify_actor_done_result(
-    result: Result<(), E>,
-    recording_still_active: bool,
-) -> ActorDoneDisposition
-where
-    E: ToString,
-{
-    match result {
-        Ok(()) if recording_still_active => ActorDoneDisposition::UnexpectedStop {
-            error: "Recording stopped unexpectedly before it was ended.".to_string(),
-        },
-        Ok(()) => ActorDoneDisposition::UserInitiatedStop,
-        Err(error) => ActorDoneDisposition::Failed {
-            error: error.to_string(),
-        },
-    }
-}
-
-async fn cancel_discarded_recording(
-    app: &AppHandle,
-    recording: InProgressRecording,
-) -> Option {
-    match recording {
-        InProgressRecording::Instant {
-            handle,
-            segment_upload,
-            video_upload_info,
-            ..
-        } => {
-            let video_id = video_upload_info.id;
-            #[cfg(target_os = "linux")]
-            {
-                if let Some(attempt) = linux_instant::current(app) {
-                    attempt.cancel();
-                }
-                if let Err(error) = handle.cancel().await {
-                    warn!(%error, "Instant cancellation failed");
-                }
-                if handle.lifecycle().wait_for_quiescence().await
-                    != instant_recording::InstantQuiescence::Joined
-                {
-                    return None;
-                }
-                if let Some(attempt) = linux_instant::current(app)
-                    && !attempt.upload_cleanup().await
-                {
-                    return None;
-                }
-                let _ = await_instant_upload(segment_upload).await;
-            }
-            #[cfg(not(target_os = "linux"))]
-            {
-                segment_upload.session.mark_cancelled().ok();
-                if let Err(err) = handle.cancel().await {
-                    warn!("Failed to cancel instant recording while discarding: {err:#}");
-                }
-                match segment_upload.handle.await {
-                    Ok(Ok(())) => {}
-                    Ok(Err(err)) => warn!("Instant upload ended while discarding recording: {err}"),
-                    Err(err) if err.is_cancelled() => {}
-                    Err(err) => {
-                        warn!("Failed to join instant upload while discarding recording: {err}")
-                    }
-                }
-            }
-            crate::upload::emit_upload_complete(app, &video_id);
-            Some(video_id)
-        }
-        InProgressRecording::Studio { handle, .. } => {
-            if let Err(err) = handle.cancel().await {
-                warn!("Failed to cancel studio recording while discarding: {err:#}");
-            }
-
-            None
-        }
-    }
-}
-
-async fn remove_recording_dir(recording_dir: &Path) -> Result<(), String> {
-    match tokio::fs::remove_dir_all(recording_dir).await {
-        Ok(()) => Ok(()),
-        Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(()),
-        Err(err) => Err(format!("Failed to delete recording files: {err}")),
-    }
-}
-
-async fn delete_remote_instant_video(app: &AppHandle, video_id: &str) -> Result<(), String> {
-    let response = app
-        .authed_api_request(
-            format!("/api/desktop/video/delete?videoId={video_id}"),
-            |client, url| client.delete(url),
-        )
-        .await
-        .map_err(|err| format!("Failed to delete instant recording: {err}"))?;
-
-    let status = response.status();
-    if status.is_success() || status == reqwest::StatusCode::NOT_FOUND {
-        return Ok(());
-    }
-
-    let body = response
-        .text()
-        .await
-        .unwrap_or_else(|err| format!("Failed to read response body: {err}"));
-
-    Err(format!(
-        "Failed to delete instant recording {video_id}: {status}: {body}"
-    ))
-}
-
-async fn discard_recording(app: &AppHandle, recording: InProgressRecording) -> Result<(), String> {
-    let recording_dir = recording.recording_dir().clone();
-    let video_id = cancel_discarded_recording(app, recording).await;
-    if let Some(video_id) = video_id {
-        delete_remote_instant_video(app, &video_id).await?;
-    }
-    remove_recording_dir(&recording_dir).await
-}
-
-#[cfg(target_os = "linux")]
-async fn after_studio_join(
-    stop: impl std::future::Future,
-    finish: impl FnOnce(Result) -> F,
-) -> Result
-where
-    F: std::future::Future>,
-{
-    let report = stop.await;
-    if report.quiescence != studio_recording::StudioQuiescence::Joined {
-        return Err(format!(
-            "Studio cleanup is unconfirmed; recording and Stop control retained: {}",
-            report
-                .result
-                .err()
-                .unwrap_or_else(|| "terminal acknowledgement missing".into())
-        ));
-    }
-    if !report.accepted_intent {
-        return Err("Another Studio terminal action owns cleanup".into());
-    }
-    finish(report.result).await
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-#[derive(Clone, Copy, PartialEq, Eq)]
-enum StudioTerminalAction {
-    Stop,
-    Discard,
-    Restart,
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-#[derive(Clone, Copy, PartialEq, Eq)]
-enum StudioStopOrigin {
-    Automatic,
-    Explicit,
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-#[derive(Clone)]
-struct StudioStopIdentity {
-    handle: studio_recording::ActorHandle,
-    directory: PathBuf,
-    generation: Option,
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-impl StudioStopIdentity {
-    fn matches(
-        &self,
-        handle: &studio_recording::ActorHandle,
-        directory: &Path,
-        generation: Option,
-    ) -> bool {
-        #[cfg(target_os = "linux")]
-        let same = self.handle.lifecycle().same_attempt(&handle.lifecycle());
-        #[cfg(any(target_os = "macos", windows))]
-        let same = self.handle.same_attempt(handle);
-        same && self.directory == directory && self.generation == generation
-    }
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-#[derive(Default)]
-struct StudioStopFlight {
-    participants: usize,
-    explicit: usize,
-    explicit_seen: bool,
-    presentation_claimed: bool,
-    automatic_error: Option,
-    cleanup_completed: bool,
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-struct StudioStopCohort {
-    identity: StudioStopIdentity,
-    notice: crate::clean_capture::StopNoticeTicket,
-    flight: std::sync::Mutex,
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-#[derive(Clone, Default)]
-struct StudioStopRegistry(Arc>);
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-#[derive(Default)]
-struct StudioStopRegistryState {
-    cohorts: Vec>,
-    active: Option<(StudioStopIdentity, crate::clean_capture::StopNoticeOwner)>,
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-#[derive(Clone)]
-struct StudioStopError {
-    kind: crate::clean_capture::StopNoticeKind,
-    message: String,
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-type StudioStopPresenter =
-    Arc;
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-impl StudioStopRegistry {
-    fn retire(&self, owner: &crate::clean_capture::StopNoticeOwner) {
-        let mut entries = self.0.lock().unwrap();
-        if entries
-            .active
-            .as_ref()
-            .is_some_and(|(_, active)| active.same_attempt(owner))
-        {
-            entries.active = None;
-        }
-    }
-
-    fn active_identity(&self, directory: &Path, generation: u32) -> Option {
-        self.0
-            .lock()
-            .unwrap()
-            .active
-            .as_ref()
-            .and_then(|(identity, _)| {
-                (identity.directory == directory && identity.generation == Some(generation))
-                    .then(|| identity.clone())
-            })
-    }
-
-    fn retire_identity(
-        &self,
-        handle: &studio_recording::ActorHandle,
-        directory: &Path,
-        generation: Option,
-    ) -> Option {
-        let mut entries = self.0.lock().unwrap();
-        if entries
-            .active
-            .as_ref()
-            .is_some_and(|(identity, _)| identity.matches(handle, directory, generation))
-        {
-            entries.active.take().map(|(_, owner)| owner)
-        } else {
-            None
-        }
-    }
-
-    fn enroll(
-        &self,
-        identity: StudioStopIdentity,
-        origin: StudioStopOrigin,
-        present: StudioStopPresenter,
-        new_owner: impl FnOnce(&StudioStopIdentity) -> crate::clean_capture::StopNoticeOwner,
-        new_ticket: impl FnOnce(
-            crate::clean_capture::StopNoticeOwner,
-        ) -> crate::clean_capture::StopNoticeTicket,
-    ) -> StudioStopParticipant {
-        let mut entries = self.0.lock().unwrap();
-        let cohort = match entries.cohorts.iter().find(|entry| {
-            entry
-                .identity
-                .matches(&identity.handle, &identity.directory, identity.generation)
-        }) {
-            Some(entry) => entry.clone(),
-            None => {
-                let owner = match &entries.active {
-                    Some((active, owner))
-                        if active.matches(
-                            &identity.handle,
-                            &identity.directory,
-                            identity.generation,
-                        ) =>
-                    {
-                        owner.clone()
-                    }
-                    _ => {
-                        let owner = new_owner(&identity);
-                        entries.active = Some((identity.clone(), owner.clone()));
-                        owner
-                    }
-                };
-                let entry = Arc::new(StudioStopCohort {
-                    identity,
-                    notice: new_ticket(owner),
-                    flight: std::sync::Mutex::new(StudioStopFlight::default()),
-                });
-                entries.cohorts.push(entry.clone());
-                entry
-            }
-        };
-        {
-            let mut flight = cohort.flight.lock().unwrap();
-            flight.participants += 1;
-            if origin == StudioStopOrigin::Explicit {
-                flight.explicit += 1;
-                flight.explicit_seen = true;
-            }
-        }
-        StudioStopParticipant {
-            registry: self.clone(),
-            cohort,
-            origin,
-            present,
-        }
-    }
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-fn studio_stop_registry(app: &AppHandle) -> StudioStopRegistry {
-    if app.try_state::().is_none() {
-        app.manage(StudioStopRegistry::default());
-    }
-    app.state::().inner().clone()
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-fn enroll_studio_stop(
-    app: &AppHandle,
-    _state: &Arc>,
-    handle: &studio_recording::ActorHandle,
-    directory: &Path,
-    generation: Option,
-    origin: StudioStopOrigin,
-) -> StudioStopParticipant {
-    let retained_app = app.clone();
-    let registry = studio_stop_registry(app);
-    registry.enroll(
-        StudioStopIdentity {
-            handle: handle.clone(),
-            directory: directory.to_owned(),
-            generation,
-        },
-        origin,
-        Arc::new(move |ticket, error| {
-            crate::clean_capture::retain_stop_notice(
-                &retained_app,
-                ticket,
-                error.kind,
-                error.message,
-            );
-        }),
-        |identity| {
-            crate::clean_capture::reserve_stop_notice_owner(
-                app,
-                identity.directory.clone(),
-                identity.generation,
-            )
-        },
-        |owner| crate::clean_capture::reserve_stop_notice_ticket(app, owner),
-    )
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-struct StudioStopParticipant {
-    registry: StudioStopRegistry,
-    cohort: Arc,
-    origin: StudioStopOrigin,
-    present: StudioStopPresenter,
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-impl StudioStopParticipant {
-    fn claim_presentation(&self) {
-        let mut flight = self.cohort.flight.lock().unwrap();
-        flight.presentation_claimed = true;
-        flight.automatic_error = None;
-    }
-
-    fn hand_off_error(&self) {
-        if self.origin == StudioStopOrigin::Explicit {
-            self.claim_presentation();
-        }
-    }
-
-    fn defer_error(&self, error: StudioStopError) {
-        let mut flight = self.cohort.flight.lock().unwrap();
-        if !flight.presentation_claimed && flight.automatic_error.is_none() {
-            flight.automatic_error = Some(error.clone());
-        }
-        drop(flight);
-        (self.present)(&self.cohort.notice, error);
-    }
-
-    fn stale_completion(self) -> StudioTerminalCompletion {
-        let outcome = stale_studio_completion(
-            Some(&self.cohort),
-            self.origin == StudioStopOrigin::Automatic,
-        );
-        StudioTerminalCompletion {
-            outcome,
-            participant: Some(self),
-        }
-    }
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-impl Drop for StudioStopParticipant {
-    fn drop(&mut self) {
-        let error = {
-            let mut entries = self.registry.0.lock().unwrap();
-            let mut flight = self.cohort.flight.lock().unwrap();
-            flight.participants -= 1;
-            if self.origin == StudioStopOrigin::Explicit {
-                flight.explicit -= 1;
-            }
-            let error = if flight.explicit == 0 && !flight.presentation_claimed {
-                let error = flight.automatic_error.take();
-                if error.is_some() {
-                    flight.presentation_claimed = true;
-                }
-                error
-            } else {
-                None
-            };
-            if flight.participants == 0 {
-                entries
-                    .cohorts
-                    .retain(|entry| !Arc::ptr_eq(entry, &self.cohort));
-            }
-            error
-        };
-        if let Some(error) = error {
-            (self.present)(&self.cohort.notice, error);
-        }
-    }
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-enum StudioControlFailure {
-    Unconfirmed(String),
-    TaskFailed(String),
-    RejectedConfirmed(String),
-    Other(String),
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-enum StudioTerminalOutcome {
-    AppliedCompletion(Result<(), String>),
-    SupersededConfirmedStop,
-    ControlFailure(StudioControlFailure),
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-fn stale_studio_completion(
-    cohort: Option<&Arc>,
-    automatic: bool,
-) -> StudioTerminalOutcome {
-    if cohort.is_some_and(|cohort| {
-        cohort.flight.lock().unwrap().cleanup_completed
-            || automatic && cohort.notice.owner.is_confirmed()
-    }) {
-        StudioTerminalOutcome::SupersededConfirmedStop
-    } else {
-        StudioTerminalOutcome::ControlFailure(StudioControlFailure::Other(
-            "Studio terminal completion is stale".into(),
-        ))
-    }
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-fn complete_studio_cleanup(
-    app: &AppHandle,
-    cohort: Option<&Arc>,
-    state: &App,
-    result: Result<(), String>,
-) -> StudioTerminalOutcome {
-    if let Some(cohort) = cohort {
-        if let Some(InProgressRecording::Studio { handle, common, .. }) = state.current_recording()
-            && cohort
-                .identity
-                .matches(handle, &common.recording_dir, cohort.identity.generation)
-        {
-            return StudioTerminalOutcome::ControlFailure(StudioControlFailure::Other(
-                result
-                    .err()
-                    .unwrap_or_else(|| "Studio cleanup did not retire the recording".into()),
-            ));
-        }
-        cohort.flight.lock().unwrap().cleanup_completed = true;
-        studio_stop_registry(app).retire(&cohort.notice.owner);
-        crate::clean_capture::confirm_stop_notice(app, &cohort.notice.owner);
-    }
-    StudioTerminalOutcome::AppliedCompletion(result)
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-struct StudioTerminalCompletion {
-    outcome: StudioTerminalOutcome,
-    participant: Option,
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-impl StudioTerminalCompletion {
-    #[cfg(any(target_os = "macos", windows))]
-    fn error(&self) -> Option<&String> {
-        match &self.outcome {
-            StudioTerminalOutcome::ControlFailure(StudioControlFailure::RejectedConfirmed(_))
-                if self.participant.as_ref().is_some_and(|participant| {
-                    participant.origin == StudioStopOrigin::Automatic
-                }) =>
-            {
-                None
-            }
-            StudioTerminalOutcome::AppliedCompletion(Err(error))
-            | StudioTerminalOutcome::ControlFailure(StudioControlFailure::Unconfirmed(error))
-            | StudioTerminalOutcome::ControlFailure(StudioControlFailure::TaskFailed(error))
-            | StudioTerminalOutcome::ControlFailure(StudioControlFailure::Other(error))
-            | StudioTerminalOutcome::ControlFailure(StudioControlFailure::RejectedConfirmed(
-                error,
-            )) => Some(error),
-            _ => None,
-        }
-    }
-
-    fn from_report(
-        result: Result,
-        accepted: bool,
-        confirmed: bool,
-        participant: Option,
-    ) -> Self {
-        let outcome = match result {
-            Ok(outcome) => outcome,
-            Err(error) => StudioTerminalOutcome::ControlFailure(if !confirmed {
-                StudioControlFailure::Unconfirmed(error)
-            } else if !accepted && confirmed {
-                StudioControlFailure::RejectedConfirmed(error)
-            } else {
-                StudioControlFailure::Other(error)
-            }),
-        };
-        Self {
-            outcome,
-            participant: None,
-        }
-        .with_participant(participant)
-    }
-
-    fn with_participant(mut self, participant: Option) -> Self {
-        let error = match &self.outcome {
-            StudioTerminalOutcome::AppliedCompletion(Err(message)) => Some(StudioStopError {
-                kind: crate::clean_capture::StopNoticeKind::ConfirmedFailure,
-                message: message.clone(),
-            }),
-            StudioTerminalOutcome::ControlFailure(StudioControlFailure::Unconfirmed(message)) => {
-                Some(StudioStopError {
-                    kind: crate::clean_capture::StopNoticeKind::Unconfirmed,
-                    message: message.clone(),
-                })
-            }
-            StudioTerminalOutcome::ControlFailure(
-                StudioControlFailure::TaskFailed(message) | StudioControlFailure::Other(message),
-            ) => Some(StudioStopError {
-                kind: crate::clean_capture::StopNoticeKind::ControlFailure,
-                message: message.clone(),
-            }),
-            StudioTerminalOutcome::ControlFailure(StudioControlFailure::RejectedConfirmed(
-                message,
-            )) if participant
-                .as_ref()
-                .is_some_and(|participant| participant.origin == StudioStopOrigin::Explicit) =>
-            {
-                Some(StudioStopError {
-                    kind: crate::clean_capture::StopNoticeKind::ControlFailure,
-                    message: message.clone(),
-                })
-            }
-            _ => None,
-        };
-        if let (Some(error), Some(participant)) = (error, &participant) {
-            participant.defer_error(error);
-        }
-        self.participant = participant;
-        self
-    }
-
-    fn into_result(self) -> Result<(), String> {
-        let Self {
-            outcome,
-            participant,
-        } = self;
-        let completion = Self {
-            outcome,
-            participant: None,
-        }
-        .with_participant(participant);
-        match completion.outcome {
-            StudioTerminalOutcome::AppliedCompletion(result) => {
-                if result.is_err()
-                    && let Some(participant) = &completion.participant
-                {
-                    participant.hand_off_error();
-                }
-                result
-            }
-            StudioTerminalOutcome::SupersededConfirmedStop => Ok(()),
-            StudioTerminalOutcome::ControlFailure(StudioControlFailure::Unconfirmed(error))
-            | StudioTerminalOutcome::ControlFailure(StudioControlFailure::TaskFailed(error)) => {
-                if let Some(participant) = &completion.participant {
-                    participant.hand_off_error();
-                }
-                Err(error)
-            }
-            StudioTerminalOutcome::ControlFailure(StudioControlFailure::Other(error))
-            | StudioTerminalOutcome::ControlFailure(StudioControlFailure::RejectedConfirmed(
-                error,
-            )) => Err(error),
-        }
-    }
-
-    fn present_automatic(self) {
-        let participant = self.participant;
-        drop(
-            Self {
-                outcome: self.outcome,
-                participant: None,
-            }
-            .with_participant(participant),
-        );
-    }
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-async fn run_owned_studio_stop(
-    work: impl std::future::Future> + Send + 'static,
-    participant: Option,
-) -> Option {
-    let failed_task_presenter = participant
-        .as_ref()
-        .map(|participant| (participant.cohort.clone(), participant.present.clone()));
-    let owned = async move {
-        let completion = match AssertUnwindSafe(work).catch_unwind().await {
-            Ok(completion) => completion,
-            Err(panic) => Some(StudioTerminalCompletion {
-                outcome: StudioTerminalOutcome::ControlFailure(StudioControlFailure::TaskFailed(
-                    format!(
-                        "Studio Stop task failed; cleanup may be incomplete: {}",
-                        panic_message(panic)
-                    ),
-                )),
-                participant: None,
-            }),
-        };
-        completion.map(|completion| completion.with_participant(participant))
-    };
-    match tauri::async_runtime::spawn(owned).await {
-        Ok(completion) => completion,
-        Err(error) => {
-            let error = format!("Studio Stop task failed; cleanup may be incomplete: {error}");
-            if let Some((cohort, present)) = failed_task_presenter {
-                present(
-                    &cohort.notice,
-                    StudioStopError {
-                        kind: crate::clean_capture::StopNoticeKind::ControlFailure,
-                        message: error.clone(),
-                    },
-                );
-            }
-            Some(StudioTerminalCompletion {
-                outcome: StudioTerminalOutcome::ControlFailure(StudioControlFailure::TaskFailed(
-                    error,
-                )),
-                participant: None,
-            })
-        }
-    }
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-fn stopped_studio_error(error: &str, directory: &Path, action: StudioTerminalAction) -> String {
-    if action != StudioTerminalAction::Stop {
-        return error.to_owned();
-    }
-    let lower = error.to_ascii_lowercase();
-    let disk_full = lower.contains("disk full:")
-        || lower.contains("no space left on device")
-        || !cfg!(windows) && lower.contains("(os error 28)")
-        || cfg!(windows) && (lower.contains("(os error 112)") || lower.contains("(os error 39)"));
-    if disk_full {
-        format!(
-            "Recording stopped because your disk is full. Your recording files have been kept at {}. Free up space before recording again.",
-            directory.display()
-        )
-    } else {
-        error.to_owned()
-    }
-}
-
-#[cfg(target_os = "linux")]
-async fn control_studio_recording(
-    app: &AppHandle,
-    state: &Arc>,
-    expected_directory: Option<&Path>,
-    action: StudioTerminalAction,
-    failure: Option,
-    automatic: Option,
-) -> Option {
-    let (handle, directory, target_name, capture_target, generation, participant) = {
-        let current_state = state.read().await;
-        let Some(InProgressRecording::Studio { handle, common, .. }) =
-            current_state.current_recording()
-        else {
-            return automatic.map(StudioStopParticipant::stale_completion);
-        };
-        if expected_directory.is_some_and(|expected| expected != common.recording_dir) {
-            return Some(match automatic {
-                Some(participant) => participant.stale_completion(),
-                None => StudioTerminalCompletion {
-                    outcome: StudioTerminalOutcome::ControlFailure(StudioControlFailure::Other(
-                        "Studio terminal operation belongs to an older recording".into(),
-                    )),
-                    participant: None,
-                },
-            });
-        }
-        let generation = crate::clean_capture::owner(app, &common.recording_dir);
-        let participant = if action == StudioTerminalAction::Stop {
-            match automatic {
-                Some(participant) => {
-                    if !participant.cohort.identity.matches(
-                        handle,
-                        &common.recording_dir,
-                        generation,
-                    ) || participant.origin == StudioStopOrigin::Explicit
-                        && !studio_stop_retry_is_current(app, &common.recording_dir, generation)
-                    {
-                        return Some(participant.stale_completion());
-                    }
-                    Some(participant)
-                }
-                None => Some(enroll_studio_stop(
-                    app,
-                    state,
-                    handle,
-                    &common.recording_dir,
-                    generation,
-                    StudioStopOrigin::Explicit,
-                )),
-            }
-        } else {
-            None
-        };
-        if action == StudioTerminalAction::Stop {
-            common.camera_snapshot.get_or_init(|| {
-                StudioCameraSnapshot::capture(app, ¤t_state, &common.inputs.capture_target)
-            });
-        }
-        (
-            handle.clone(),
-            common.recording_dir.clone(),
-            common.target_name.clone(),
-            common.inputs.capture_target.clone(),
-            generation,
-            participant,
-        )
-    };
-
-    let automatic = participant
-        .as_ref()
-        .is_some_and(|participant| participant.origin == StudioStopOrigin::Automatic);
-    let cohort = participant
-        .as_ref()
-        .map(|participant| participant.cohort.clone());
-    let app = app.clone();
-    let state = state.clone();
-    #[cfg(any(target_os = "macos", windows))]
-    let expected_directory = expected_directory.map(Path::to_owned);
-    let work = async move {
-        let app = &app;
-        let state = &state;
-        #[cfg(any(target_os = "macos", windows))]
-        let expected_directory = expected_directory.as_deref();
-        let discard = action != StudioTerminalAction::Stop;
-        let intent = if discard {
-            studio_recording::StudioStopIntent::Discard
-        } else {
-            studio_recording::StudioStopIntent::Preserve
-        };
-
-        let stopping = handle.clone();
-        let report = stopping.stop_with_intent(intent).await;
-        let accepted = report.accepted_intent;
-        let confirmed = report.quiescence == studio_recording::StudioQuiescence::Joined;
-        let result = after_studio_join(
-            async move { report },
-            |result| async move {
-                let outcome = match failure {
-                    Some(error) => Err(error),
-                    None => result,
-                };
-                if discard && let Err(error) = &outcome {
-                    return Err(error.clone());
-                }
-                let finalization_project = if !discard && outcome.is_ok() {
-                    Some(crate::FinalizationProject::admit(directory.clone()).await)
-                } else {
-                    None
-                };
-                let mut state = state.write().await;
-                let current = match state.current_recording() {
-                    Some(InProgressRecording::Studio {
-                        handle: current,
-                        common,
-                        ..
-                    }) => {
-                        common.recording_dir == directory
-                            && current.lifecycle().same_attempt(&handle.lifecycle())
-                            && crate::clean_capture::owner(app, &directory) == generation
-                    }
-                    _ => false,
-                };
-                if !current {
-                    return Ok(stale_studio_completion(cohort.as_ref(), automatic));
-                }
-                if discard && let Err(error) = remove_recording_dir(&directory).await {
-                    return Err(error);
-                }
-                let error = outcome.as_ref().err().cloned();
-                let completed = if discard {
-                    Err("Recording discarded after confirmed capture shutdown".into())
-                } else {
-                    outcome.map(|recording| CompletedRecording::Studio {
-                        recording,
-                        target_name,
-                        capture_target,
-                    })
-                };
-                let display_error = error.as_deref().map(|error| {
-                    tracing::error!(error, directory = %directory.display(), "Studio stopped with a recording failure");
-                    stopped_studio_error(error, &directory, action)
-                });
-                if let Some(error) = &display_error {
-                    let _ = RecordingEvent::Failed {
-                        error: error.clone(),
-                    }
-                    .emit(app);
-                }
-                let cleanup = handle_recording_end_inner(
-                    app.clone(),
-                    completed,
-                    &mut state,
-                    directory,
-                    action == StudioTerminalAction::Restart,
-                    finalization_project,
-                )
-                .await;
-                let result = match display_error {
-                    Some(error) => Err(error),
-                    None => cleanup,
-                };
-                let outcome = complete_studio_cleanup(app, cohort.as_ref(), &state, result);
-                drop(state);
-                Ok(outcome)
-            },
-        )
-        .await;
-        Some(StudioTerminalCompletion::from_report(
-            result, accepted, confirmed, None,
-        ))
-    };
-    if action == StudioTerminalAction::Stop {
-        run_owned_studio_stop(work, participant).await
-    } else {
-        work.await
-    }
-}
-
-#[cfg(any(target_os = "macos", windows))]
-async fn after_studio_capture_stop(
-    stop: impl std::future::Future,
-    finish: impl FnOnce(Result) -> F,
-) -> Result
-where
-    F: std::future::Future>,
-{
-    let report = stop.await;
-    if !report.stop_acknowledged {
-        return Err(format!(
-            "Studio cleanup is unconfirmed; recording and Stop control retained: {}",
-            report
-                .result
-                .err()
-                .unwrap_or_else(|| "terminal acknowledgement missing".into())
-        ));
-    }
-    if !report.accepted_intent {
-        return Err("Another Studio terminal action owns cleanup".into());
-    }
-    finish(report.result).await
-}
-
-#[cfg(any(target_os = "macos", windows))]
-async fn control_studio_recording(
-    app: &AppHandle,
-    state: &Arc>,
-    expected_directory: Option<&Path>,
-    action: StudioTerminalAction,
-    failure: Option,
-    automatic: Option,
-) -> Option {
-    let (handle, directory, target_name, capture_target, generation, participant) = {
-        let current_state = state.read().await;
-        let Some(InProgressRecording::Studio { handle, common, .. }) =
-            current_state.current_recording()
-        else {
-            return automatic.map(StudioStopParticipant::stale_completion);
-        };
-        if expected_directory.is_some_and(|expected| expected != common.recording_dir) {
-            return Some(match automatic {
-                Some(participant) => participant.stale_completion(),
-                None => StudioTerminalCompletion {
-                    outcome: StudioTerminalOutcome::ControlFailure(StudioControlFailure::Other(
-                        "Studio terminal operation belongs to an older recording".into(),
-                    )),
-                    participant: None,
-                },
-            });
-        }
-        let generation = crate::clean_capture::owner(app, &common.recording_dir);
-        let participant = if action == StudioTerminalAction::Stop {
-            match automatic {
-                Some(participant) => {
-                    if !participant.cohort.identity.matches(
-                        handle,
-                        &common.recording_dir,
-                        generation,
-                    ) || participant.origin == StudioStopOrigin::Explicit
-                        && !studio_stop_retry_is_current(app, &common.recording_dir, generation)
-                    {
-                        return Some(participant.stale_completion());
-                    }
-                    Some(participant)
-                }
-                None => Some(enroll_studio_stop(
-                    app,
-                    state,
-                    handle,
-                    &common.recording_dir,
-                    generation,
-                    StudioStopOrigin::Explicit,
-                )),
-            }
-        } else {
-            None
-        };
-        if action == StudioTerminalAction::Stop {
-            common.camera_snapshot.get_or_init(|| {
-                StudioCameraSnapshot::capture(app, ¤t_state, &common.inputs.capture_target)
-            });
-        }
-        (
-            handle.clone(),
-            common.recording_dir.clone(),
-            common.target_name.clone(),
-            common.inputs.capture_target.clone(),
-            generation,
-            participant,
-        )
-    };
-    let automatic = participant
-        .as_ref()
-        .is_some_and(|participant| participant.origin == StudioStopOrigin::Automatic);
-    let cohort = participant
-        .as_ref()
-        .map(|participant| participant.cohort.clone());
-    let app = app.clone();
-    let state = state.clone();
-    #[cfg(any(target_os = "macos", windows))]
-    let expected_directory = expected_directory.map(Path::to_owned);
-    let work = async move {
-        let app = &app;
-        let state = &state;
-        #[cfg(any(target_os = "macos", windows))]
-        let expected_directory = expected_directory.as_deref();
-        let discard = action != StudioTerminalAction::Stop;
-        let intent = if discard {
-            studio_recording::StudioStopIntent::Discard
-        } else {
-            studio_recording::StudioStopIntent::Preserve
-        };
-
-        let stopping = handle.clone();
-        let finishing = handle.clone();
-        let report = stopping.stop_with_intent(intent).await;
-        let accepted = report.accepted_intent;
-        let confirmed = report.stop_acknowledged;
-        let result = after_studio_capture_stop(
-        async move { report },
-        |result| async move {
-            let outcome = match (failure, result) {
-                (Some(failure), Err(error)) => Err(format!("{failure}; {error}")),
-                (Some(error), _) => Err(error),
-                (None, result) => result,
-            };
-            let finalization_project = if !discard && outcome.is_ok() {
-                Some(crate::FinalizationProject::admit(directory.clone()).await)
-            } else {
-                None
-            };
-            let mut state = state.write().await;
-            let current = match state.current_recording() {
-                Some(InProgressRecording::Studio {
-                    handle: current,
-                    common,
-                    ..
-                }) => {
-                    common.recording_dir == directory
-                        && current.same_attempt(&finishing)
-                        && crate::clean_capture::owner(app, &directory) == generation
-                }
-                _ => false,
-            };
-            if !current {
-                return Ok(stale_studio_completion(cohort.as_ref(), automatic));
-            }
-            let mut error = outcome.as_ref().err().cloned();
-            if discard && error.is_none() {
-                error = remove_recording_dir(&directory).await.err();
-            }
-            #[cfg(target_os = "macos")]
-            if action == StudioTerminalAction::Restart && error.is_none() {
-                drop(state.clear_current_recording());
-                if let Some(owner) = studio_stop_registry(app).retire_identity(&finishing, &directory, generation) {
-                    crate::clean_capture::confirm_stop_notice(app, &owner);
-                }
-                CurrentRecordingChanged.emit(app).ok();
-                return Ok(StudioTerminalOutcome::AppliedCompletion(Ok(())));
-            }
-            let completed = if let Some(error) = &error {
-                Err(error.clone())
-            } else if discard {
-                Err("Recording discarded after Studio stop acknowledgement".into())
-            } else {
-                outcome.map(|recording| CompletedRecording::Studio {
-                    recording,
-                    target_name,
-                    capture_target,
-                })
-            };
-            let display_error = error.as_deref().map(|error| {
-                tracing::error!(error, directory = %directory.display(), "Studio stopped with a recording failure");
-                stopped_studio_error(error, &directory, action)
-            });
-            if let Some(error) = &display_error {
-                let _ = RecordingEvent::Failed {
-                    error: error.clone(),
-                }
-                .emit(app);
-            }
-            let cleanup = handle_recording_end_inner(
-                app.clone(),
-                completed,
-                &mut state,
-                directory,
-                action == StudioTerminalAction::Restart && error.is_none(),
-                finalization_project,
-            )
-            .await;
-            let result = match display_error {
-                Some(error) => Err(error),
-                None => cleanup,
-            };
-            let outcome = complete_studio_cleanup(app, cohort.as_ref(), &state, result);
-            drop(state);
-            Ok(outcome)
-        },
-    )
-    .await;
-        let completion = StudioTerminalCompletion::from_report(result, accepted, confirmed, None);
-        if action != StudioTerminalAction::Stop
-            && !(automatic
-                && matches!(
-                    &completion.outcome,
-                    StudioTerminalOutcome::ControlFailure(StudioControlFailure::RejectedConfirmed(
-                        _
-                    ))
-                ))
-            && let Some(error) = completion.error()
-        {
-            let state = state.read().await;
-            if let Some(InProgressRecording::Studio {
-                handle: current,
-                common,
-                ..
-            }) = state.current_recording()
-                && current.same_attempt(&handle)
-                && expected_directory.is_none_or(|expected| expected == common.recording_dir)
-            {
-                let _ = RecordingEvent::Failed {
-                    error: error.clone(),
-                }
-                .emit(app);
-            }
-        }
-        Some(completion)
-    };
-    if action == StudioTerminalAction::Stop {
-        run_owned_studio_stop(work, participant).await
-    } else {
-        work.await
-    }
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-fn studio_stop_retry_is_current(
-    app: &AppHandle,
-    directory: &Path,
-    generation: Option,
-) -> bool {
-    let Some(generation) = generation else {
-        return false;
-    };
-    let snapshot = crate::clean_capture::get_clean_capture_state(app.clone());
-    snapshot.generation == generation
-        && matches!(snapshot.phase, Some(crate::clean_capture::Phase::Stopping))
-        && matches!(snapshot.mode, Some(RecordingMode::Studio))
-        && crate::clean_capture::owner(app, directory) == Some(generation)
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-pub(crate) fn queue_clean_studio_stop(app: &AppHandle, generation: u32, directory: PathBuf) {
-    let Some(identity) = studio_stop_registry(app).active_identity(&directory, generation) else {
-        return;
-    };
-    let app = app.clone();
-    drop(tauri::async_runtime::spawn(async move {
-        if let Err(error) =
-            stop_clean_studio_recording(app, identity.handle, generation, directory).await
-        {
-            tracing::error!(%error, "Clean capture Stop did not complete");
-        }
-    }));
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-pub(crate) async fn stop_clean_studio_recording(
-    app: AppHandle,
-    handle: studio_recording::ActorHandle,
-    generation: u32,
-    directory: PathBuf,
-) -> Result<(), String> {
-    let state = app.state::>>().inner().clone();
-    let participant = {
-        let current = state.read().await;
-        let Some(InProgressRecording::Studio {
-            handle: current_handle,
-            common,
-            ..
-        }) = current.current_recording()
-        else {
-            return Ok(());
-        };
-        let identity = StudioStopIdentity {
-            handle,
-            directory,
-            generation: Some(generation),
-        };
-        if !identity.matches(
-            current_handle,
-            &common.recording_dir,
-            crate::clean_capture::owner(&app, &common.recording_dir),
-        ) || !crate::clean_capture::queue_owned_studio_stop(
-            &app,
-            generation,
-            &common.recording_dir,
-        ) {
-            return Ok(());
-        }
-        enroll_studio_stop(
-            &app,
-            &state,
-            current_handle,
-            &common.recording_dir,
-            Some(generation),
-            StudioStopOrigin::Explicit,
-        )
-    };
-    control_studio_recording(
-        &app,
-        &state,
-        None,
-        StudioTerminalAction::Stop,
-        None,
-        Some(participant),
-    )
-    .await
-    .map_or(Ok(()), StudioTerminalCompletion::into_result)
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows))]
-async fn queue_studio_stop(
-    app: &AppHandle,
-    state: &Arc>,
-) -> (bool, Option) {
-    let current = state.read().await;
-    let generation = match current.current_recording() {
-        Some(InProgressRecording::Studio { common, .. }) => {
-            crate::clean_capture::owner(app, &common.recording_dir)
-        }
-        _ => None,
-    };
-    let deferred = crate::clean_capture::queue_stop(app);
-    let retry = if deferred {
-        match current.current_recording() {
-            Some(InProgressRecording::Studio { handle, common, .. })
-                if studio_stop_retry_is_current(app, &common.recording_dir, generation) =>
-            {
-                Some(enroll_studio_stop(
-                    app,
-                    state,
-                    handle,
-                    &common.recording_dir,
-                    generation,
-                    StudioStopOrigin::Explicit,
-                ))
-            }
-            _ => None,
-        }
-    } else {
-        None
-    };
-    (deferred, retry)
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app, state))]
-pub async fn stop_recording(app: AppHandle, state: MutableState<'_, App>) -> Result<(), String> {
-    if cancel_recording_storage_prompt(&app, &state).await {
-        return Ok(());
-    }
-    {
-        let current = state.read().await;
-        if let Some(InProgressRecording::Studio { common, .. }) = current.current_recording() {
-            common.camera_snapshot.get_or_init(|| {
-                StudioCameraSnapshot::capture(&app, ¤t, &common.inputs.capture_target)
-            });
-        }
-    }
-    #[cfg(target_os = "linux")]
-    if let Some(attempt) = linux_instant::current(&app) {
-        return linux_instant::control(app, attempt, false).await;
-    }
-    #[cfg(any(target_os = "linux", target_os = "macos", windows))]
-    let (deferred, retry) = queue_studio_stop(&app, &state).await;
-    #[cfg(not(any(target_os = "linux", target_os = "macos", windows)))]
-    let deferred = crate::clean_capture::queue_stop(&app);
-    if deferred {
-        #[cfg(any(target_os = "linux", target_os = "macos", windows))]
-        if let Some(retry) = retry {
-            return control_studio_recording(
-                &app,
-                &state,
-                None,
-                StudioTerminalAction::Stop,
-                None,
-                Some(retry),
-            )
-            .await
-            .map_or(Ok(()), StudioTerminalCompletion::into_result);
-        }
-        return Ok(());
-    }
-    #[cfg(any(target_os = "linux", target_os = "macos", windows))]
-    if let Some(result) =
-        control_studio_recording(&app, &state, None, StudioTerminalAction::Stop, None, None).await
-    {
-        return result.into_result();
-    }
-    let mut state = state.write().await;
-    let recording_pending = matches!(&state.recording_state, RecordingState::Pending { .. });
-    let Some(current_recording) = state.clear_current_recording() else {
-        if recording_pending {
-            debug!("Stop recording requested before recording actor was ready");
-            return Err("Recording is still starting".to_string());
-        }
-        debug!("Stop recording requested without active recording");
-        return Ok(());
-    };
-
-    let recording_dir = current_recording.recording_dir().clone();
-    let recording_outcome = match current_recording.stop().await {
-        Ok(completed) => Ok(completed),
-        Err((e, ctx)) => {
-            error!("Recording stop failed: {e:#}");
-            if let Some(ctx) = ctx {
-                #[cfg(not(target_os = "linux"))]
-                {
-                    ctx.segment_upload.session.cancel();
-                    let _ = ctx.segment_upload.handle.await;
-                }
-                #[cfg(target_os = "linux")]
-                if let Some(attempt) = linux_instant::current(&app) {
-                    attempt.cancel();
-                }
-                crate::upload::emit_upload_complete(&app, &ctx.video_upload_info.id);
-            }
-            Err(e.to_string())
-        }
-    };
-
-    handle_recording_end(app, recording_outcome, &mut state, recording_dir).await?;
-
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app, state))]
-pub async fn restart_recording(
-    app: AppHandle,
-    state: MutableState<'_, App>,
-) -> Result {
-    #[cfg(target_os = "linux")]
-    if let Some(attempt) = linux_instant::current(&app) {
-        let inputs = state
-            .read()
-            .await
-            .current_recording()
-            .ok_or("No recording in progress")?
-            .inputs()
-            .clone();
-        let restore_generation =
-            crate::clean_capture::phase(&app).map(|_| crate::clean_capture::generation(&app));
-        linux_instant::control(app.clone(), attempt, true).await?;
-        if let Some(generation) = restore_generation {
-            crate::clean_capture::wait_restored(&app, generation).await?;
-        }
-        return Box::pin(start_recording(app, state, inputs)).await;
-    }
-    #[cfg(any(target_os = "linux", target_os = "macos", windows))]
-    {
-        let current = {
-            let state = state.read().await;
-            match state.current_recording() {
-                Some(InProgressRecording::Studio { common, .. }) => Some((
-                    common.inputs.clone(),
-                    common.recording_dir.clone(),
-                    crate::clean_capture::owner(&app, &common.recording_dir),
-                )),
-                _ => None,
-            }
-        };
-        if let Some((inputs, directory, generation)) = current {
-            return complete_studio_restart(async move {
-                let state = app.state::>();
-                let target = EditorRecordingTarget::get(&app);
-                restart_with_editor_target(
-                    &target,
-                    async {
-                        control_studio_recording(
-                            &app,
-                            &state,
-                            Some(&directory),
-                            StudioTerminalAction::Restart,
-                            None,
-                            None,
-                        )
-                        .await
-                        .ok_or("Studio recording changed before restart")?
-                        .into_result()?;
-                        Ok(())
-                    },
-                    async {
-                        #[cfg(target_os = "linux")]
-                        if let Some(generation) = generation {
-                            crate::clean_capture::wait_restored(&app, generation).await?;
-                        }
-                        #[cfg(any(target_os = "macos", windows))]
-                        let _ = generation;
-                        Ok(())
-                    },
-                    || Box::pin(start_recording(app.clone(), app.state(), inputs)),
-                    |expected, cleanup_completed| {
-                        let app = &app;
-                        let state = &state;
-                        let target = ⌖
-                        async move {
-                            let state = state.read().await;
-                            if let Some(editor_path) = take_failed_restart_editor_target(
-                                target,
-                                expected.as_deref(),
-                                cleanup_completed
-                                    && matches!(state.recording_state, RecordingState::None),
-                            ) {
-                                crate::editor_recording::finish(app);
-                                crate::editor_recording::reveal_editor(app, &editor_path);
-                            }
-                        }
-                    },
-                )
-                .await
-            })
-            .await;
-        }
-    }
-    if crate::clean_capture::phase(&app) == Some(crate::clean_capture::Phase::Recording) {
-        crate::clean_capture::control(&app, false).await?;
-    }
-
-    let (recording, clean_generation) = {
-        let mut state = state.write().await;
-        let recording = state
-            .current_recording()
-            .ok_or("No recording in progress")?;
-        let generation = crate::clean_capture::begin_restart(&app, recording.recording_dir())?;
-        (state.clear_current_recording().unwrap(), generation)
-    };
-
-    let _ = CurrentRecordingChanged.emit(&app);
-
-    let inputs = recording.inputs().clone();
-    let recording_dir = recording.recording_dir().clone();
-
-    let upload_session = match &recording {
-        InProgressRecording::Instant { segment_upload, .. } => {
-            #[cfg(not(target_os = "linux"))]
-            let session = segment_upload.session.clone();
-            #[cfg(target_os = "linux")]
-            let session = segment_upload.lock().await.session.clone();
-            Some(session)
-        }
-        _ => None,
-    };
-    let video_id = cancel_discarded_recording(&app, recording).await;
-    if let (Some(video_id), Some(session)) = (video_id, upload_session) {
-        let cleanup_app = app.clone();
-        let cleanup_directory = recording_dir.clone();
-        if let Err(error) = crate::upload::lifecycle::supervise(app.clone(), session, async move {
-            delete_remote_instant_video(&cleanup_app, &video_id)
-                .await
-                .map_err(AuthedApiError::from)?;
-            remove_recording_dir(&cleanup_directory)
-                .await
-                .map_err(AuthedApiError::from)
-        })
-        .await
-        {
-            warn!(%error, "Restart retained the cancelled recording");
-        }
-    } else if let Err(error) = remove_recording_dir(&recording_dir).await {
-        warn!(%error, "Failed to delete recording files while restarting");
-    }
-
-    if let Some(generation) = clean_generation {
-        let result = async {
-            crate::clean_capture::hide(&app, generation).await?;
-            let requested = app
-                .state::()
-                .ready_snapshot()?;
-            crate::clean_capture::prepare(&app, &inputs, Some(generation)).await?;
-            state
-                .write()
-                .await
-                .set_pending_recording(inputs.mode, inputs.capture_target.clone())?;
-            start_recording_prepared(
-                app.clone(),
-                state.clone(),
-                inputs,
-                requested,
-                Some(generation),
-            )
-            .await
-        }
-        .await;
-        if !matches!(&result, Ok(RecordingAction::Started)) {
-            let mut app_state = state.write().await;
-            if crate::clean_capture::is_current(&app, generation) {
-                app_state.clear_pending_recording();
-                drop(app_state);
-                crate::clean_capture::release(&app, generation, false);
-            }
-        }
-        return result;
-    }
-    start_recording(app.clone(), state, inputs).await
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows, test))]
-async fn complete_studio_restart(
-    restart: impl std::future::Future> + Send + 'static,
-) -> Result {
-    tokio::spawn(restart)
-        .await
-        .map_err(|error| format!("Recording restart task failed: {error}"))?
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows, test))]
-async fn restart_with_editor_target(
-    target: &EditorRecordingTarget,
-    cleanup: C,
-    restore: R,
-    start: impl FnOnce() -> S,
-    on_failure: impl FnOnce(Option, bool) -> F,
-) -> Result
-where
-    C: std::future::Future>,
-    R: std::future::Future>,
-    S: std::future::Future>,
-    F: std::future::Future,
-{
-    let expected = target.0.lock().unwrap().clone();
-    let cleanup_result = cleanup.await;
-    let cleanup_completed = cleanup_result.is_ok();
-    let result = match cleanup_result {
-        Ok(()) => match restore.await {
-            Ok(()) => {
-                let unchanged = *target.0.lock().unwrap() == expected;
-                if unchanged {
-                    start().await
-                } else {
-                    Err("Recording editor target changed before restart".into())
-                }
-            }
-            Err(error) => Err(error),
-        },
-        Err(error) => Err(error),
-    };
-    if !matches!(&result, Ok(RecordingAction::Started)) {
-        on_failure(expected, cleanup_completed).await;
-    }
-    result
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos", windows, test))]
-fn take_failed_restart_editor_target(
-    target: &EditorRecordingTarget,
-    expected: Option<&Path>,
-    recording_cleared: bool,
-) -> Option {
-    if !recording_cleared {
-        return None;
-    }
-    let mut current = target.0.lock().unwrap();
-    if current.as_deref() == expected {
-        current.take()
-    } else {
-        None
-    }
-}
-
-fn take_editor_target_after_recording(
-    target: &EditorRecordingTarget,
-    preserve: bool,
-) -> Option {
-    if preserve {
-        None
-    } else {
-        target.0.lock().unwrap().take()
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app, state))]
-pub async fn delete_recording(app: AppHandle, state: MutableState<'_, App>) -> Result<(), String> {
-    if cancel_recording_storage_prompt(&app, &state).await {
-        return Ok(());
-    }
-    #[cfg(target_os = "linux")]
-    if let Some(attempt) = linux_instant::current(&app) {
-        return linux_instant::control(app, attempt, true).await;
-    }
-    #[cfg(any(target_os = "linux", target_os = "macos", windows))]
-    if let Some(result) = control_studio_recording(
-        &app,
-        &state,
-        None,
-        StudioTerminalAction::Discard,
-        None,
-        None,
-    )
-    .await
-    {
-        return result.into_result();
-    }
-    if crate::clean_capture::phase(&app) == Some(crate::clean_capture::Phase::Recording) {
-        crate::clean_capture::control(&app, false).await?;
-    }
-
-    if matches!(
-        crate::clean_capture::phase(&app),
-        Some(
-            crate::clean_capture::Phase::Starting
-                | crate::clean_capture::Phase::AwaitingShortcut
-                | crate::clean_capture::Phase::Pausing
-                | crate::clean_capture::Phase::Resuming
-                | crate::clean_capture::Phase::ResumeFailed
-                | crate::clean_capture::Phase::Restarting
-        )
-    ) {
-        return Err("Recording is changing state. Use Ctrl+Shift+F9 to stop.".into());
-    }
-    let recording_data = {
-        let mut app_state = state.write().await;
-        app_state.clear_current_recording()
-    };
-
-    if let Some(recording) = recording_data {
-        CurrentRecordingChanged.emit(&app).ok();
-        RecordingStopped {}.emit(&app).ok();
-
-        if let Some(window) = CapWindowId::RecordingControls.get(&app) {
-            let _ = window.hide();
-        }
-
-        let clean_generation = crate::clean_capture::owner(&app, recording.recording_dir());
-        if let Some(generation) = clean_generation {
-            crate::clean_capture::set_phase(
-                &app,
-                generation,
-                crate::clean_capture::Phase::Stopping,
-            );
-        }
-        let delete_result = discard_recording(&app, recording).await;
-        if let Some(generation) = clean_generation {
-            crate::clean_capture::release(&app, generation, false);
-        }
-
-        let settings = GeneralSettingsStore::get(&app)
-            .ok()
-            .flatten()
-            .unwrap_or_default();
-
-        match settings.post_deletion_behaviour {
-            PostDeletionBehaviour::DoNothing => {}
-            PostDeletionBehaviour::ReopenRecordingWindow => {
-                let _ = ShowCapWindow::Main {
-                    init_target_mode: None,
-                }
-                .show(&app)
-                .await;
-            }
-        }
-
-        delete_result?;
-    }
-
-    Ok(())
-}
-
-#[tauri::command(async)]
-#[specta::specta]
-#[tracing::instrument(name = "take_screenshot", skip(app))]
-pub async fn take_screenshot(
-    app: AppHandle,
-    target: ScreenCaptureTarget,
-) -> Result {
-    use crate::NewScreenshotAdded;
-    use crate::notifications;
-    use crate::{PendingScreenshot, PendingScreenshots};
-    use cap_recording::screenshot::capture_screenshot;
-    use image::ImageEncoder;
-    use std::time::Instant;
-
-    let general_settings = GeneralSettingsStore::get(&app).ok().flatten();
-    let general_settings = general_settings.as_ref();
-
-    let project_name = format_project_name(
-        general_settings
-            .and_then(|s| s.default_project_name_template.clone())
-            .as_deref(),
-        target.title().as_deref().unwrap_or("Unknown"),
-        target.kind_str(),
-        RecordingMode::Screenshot,
-        None,
-    );
-
-    let mut hid_any = false;
-    for (label, window) in app.webview_windows() {
-        if let Ok(id) = CapWindowId::from_str(&label)
-            && matches!(
-                id,
-                CapWindowId::TargetSelectOverlay { .. }
-                    | CapWindowId::WindowCaptureOccluder { .. }
-                    | CapWindowId::CaptureArea
-                    | CapWindowId::ModeSelect
-                    | CapWindowId::RecordingsOverlay
-            )
-        {
-            hide_overlay(&window);
-            hid_any = true;
-        }
-    }
-
-    if hid_any {
-        tokio::time::sleep(std::time::Duration::from_millis(150)).await;
-    }
-
-    let automation_target = target.clone();
-
-    let image = capture_screenshot(target)
-        .await
-        .map_err(|e| format!("Failed to capture screenshot: {e}"))?;
-
-    AppSounds::Notification.play();
-
-    let image_width = image.width();
-    let image_height = image.height();
-    let channels: u32 = match &image {
-        image::DynamicImage::ImageRgba8(_) => 4,
-        _ => 3,
-    };
-    let color_type = if channels == 4 {
-        image::ColorType::Rgba8
-    } else {
-        image::ColorType::Rgb8
-    };
-    let image_data = image.into_bytes();
-
-    let filename = project_name.replace(":", ".");
-    let filename = format!("{}.cap", sanitize_filename::sanitize(&filename));
-
-    let screenshots_base_dir = app.path().app_data_dir().unwrap().join("screenshots");
-
-    let project_file_path = screenshots_base_dir.join(&cap_utils::ensure_unique_filename(
-        &filename,
-        &screenshots_base_dir,
-    )?);
-
-    ensure_dir(&project_file_path)
-        .map_err(|e| format!("Failed to create screenshots directory: {e}"))?;
-
-    let image_filename = "original.png";
-    let image_path = project_file_path.join(image_filename);
-    let cap_dir_key = project_file_path.to_string_lossy().to_string();
-
-    let pending_screenshots = app.state::();
-    pending_screenshots.insert(
-        cap_dir_key.clone(),
-        PendingScreenshot {
-            data: image_data.clone(),
-            width: image_width,
-            height: image_height,
-            channels,
-            created_at: Instant::now(),
-        },
-    );
-
-    let relative_path = relative_path::RelativePathBuf::from(image_filename);
-
-    let video_meta = cap_project::VideoMeta {
-        path: relative_path,
-        fps: 0,
-        start_time: Some(0.0),
-        device_id: None,
-    };
-
-    let segment = cap_project::SingleSegment {
-        display: video_meta,
-        camera: None,
-        audio: None,
-        cursor: None,
-    };
-
-    let meta = cap_project::RecordingMeta {
-        platform: Some(Platform::default()),
-        project_path: project_file_path.clone(),
-        pretty_name: project_name,
-        sharing: None,
-        inner: cap_project::RecordingMetaInner::Studio(Box::new(
-            cap_project::StudioRecordingMeta::SingleSegment { segment },
-        )),
-        upload: None,
-    };
-
-    meta.save_for_project()
-        .map_err(|e| format!("Failed to save recording meta: {e}"))?;
-
-    let mut screenshot_config = cap_project::ProjectConfiguration::default();
-    screenshot_config.background.source = cap_project::BackgroundSource::Color {
-        value: [255, 255, 255],
-        alpha: 0,
-    };
-    screenshot_config.background.shadow = 0.0;
-    screenshot_config
-        .write(&project_file_path)
-        .map_err(|e| format!("Failed to save project config: {e}"))?;
-
-    let is_large_capture = (image_width as u64).saturating_mul(image_height as u64) > 8_000_000;
-    let compression = if is_large_capture {
-        image::codecs::png::CompressionType::Fast
-    } else {
-        image::codecs::png::CompressionType::Default
-    };
-    let image_path_for_emit = image_path.clone();
-    let image_path_for_write = image_path.clone();
-    let app_handle = app.clone();
-    let pending_state = PendingScreenshots(pending_screenshots.0.clone());
-
-    tauri::async_runtime::spawn(async move {
-        let encode_result = tokio::task::spawn_blocking(move || -> Result<(), String> {
-            let file = std::fs::File::create(&image_path_for_write)
-                .map_err(|e| format!("Failed to create screenshot file: {e}"))?;
-            let encoder = image::codecs::png::PngEncoder::new_with_quality(
-                std::io::BufWriter::new(file),
-                compression,
-                image::codecs::png::FilterType::Adaptive,
-            );
-
-            ImageEncoder::write_image(
-                encoder,
-                &image_data,
-                image_width,
-                image_height,
-                color_type.into(),
-            )
-            .map_err(|e| format!("Failed to encode PNG: {e}"))
-        })
-        .await;
-
-        pending_state.remove(&cap_dir_key);
-
-        match encode_result {
-            Ok(Ok(())) => {
-                let _ = NewScreenshotAdded {
-                    path: image_path_for_emit.clone(),
-                }
-                .emit(&app_handle);
-
-                crate::automation::run_screenshot_automations(
-                    app_handle.clone(),
-                    image_path_for_emit.clone(),
-                    &automation_target,
-                );
-
-                notifications::send_notification(
-                    &app_handle,
-                    notifications::NotificationType::ScreenshotSaved,
-                );
-            }
-            Ok(Err(e)) => {
-                error!("Failed to encode PNG: {e}");
-                notifications::send_notification(
-                    &app_handle,
-                    notifications::NotificationType::ScreenshotSaveFailed,
-                );
-            }
-            Err(e) => {
-                error!("Failed to join screenshot encoding task: {e}");
-                notifications::send_notification(
-                    &app_handle,
-                    notifications::NotificationType::ScreenshotSaveFailed,
-                );
-            }
-        }
-    });
-
-    Ok(image_path)
-}
-
-async fn handle_recording_end(
-    handle: AppHandle,
-    recording: Result,
-    app: &mut App,
-    recording_dir: PathBuf,
-) -> Result<(), String> {
-    handle_recording_end_inner(handle, recording, app, recording_dir, false, None).await
-}
-
-async fn handle_recording_end_inner(
-    handle: AppHandle,
-    recording: Result,
-    app: &mut App,
-    recording_dir: PathBuf,
-    preserve_editor_target: bool,
-    finalization_project: Option, String>>,
-) -> Result<(), String> {
-    #[cfg(target_os = "linux")]
-    if let Some(InProgressRecording::Studio {
-        handle: studio,
-        common,
-        ..
-    }) = app.current_recording()
-        && common.recording_dir == recording_dir
-        && studio.lifecycle().quiescence() != studio_recording::StudioQuiescence::Joined
-    {
-        return Err("Studio capture cleanup is unconfirmed; active recording retained".into());
-    }
-    #[cfg(any(target_os = "macos", windows))]
-    if let Some(InProgressRecording::Studio {
-        handle: studio,
-        common,
-        ..
-    }) = app.current_recording()
-        && common.recording_dir == recording_dir
-        && !studio.stop_acknowledged()
-    {
-        return Err("Studio stop is unconfirmed; active recording retained".into());
-    }
-    #[cfg(target_os = "linux")]
-    if linux_instant::current(&handle)
-        .is_some_and(|attempt| attempt.owns_directory(&recording_dir) && !attempt.capture_joined())
-    {
-        return Err("Instant capture cleanup is unconfirmed; recording state retained".into());
-    }
-    #[cfg(target_os = "linux")]
-    let strict_attempt =
-        linux_instant::current(&handle).filter(|attempt| attempt.owns_directory(&recording_dir));
-    #[cfg(target_os = "linux")]
-    let mut recording = match &strict_attempt {
-        Some(attempt) => attempt.checked(recording),
-        None => recording,
-    };
-    let clean_generation = crate::clean_capture::owner(&handle, &recording_dir);
-    if crate::clean_capture::phase(&handle).is_some() && clean_generation.is_none() {
-        return Ok(());
-    }
-    let camera_snapshot = match &recording {
-        Ok(CompletedRecording::Studio {
-            recording,
-            capture_target,
-            ..
-        }) => {
-            let mut snapshot = app
-                .current_recording()
-                .and_then(|current| current.common().camera_snapshot.get())
-                .cloned()
-                .unwrap_or_else(|| StudioCameraSnapshot::capture(&handle, app, capture_target));
-            if recording.meta.camera_path().is_none() {
-                snapshot.placement = None;
-            }
-            Some(snapshot)
-        }
-        _ => None,
-    };
-    let cleared = app.clear_recording_state();
-    #[cfg(any(target_os = "linux", target_os = "macos", windows))]
-    if let Some(InProgressRecording::Studio {
-        handle: studio,
-        common,
-        ..
-    }) = &cleared
-        && let Some(owner) = studio_stop_registry(&handle).retire_identity(
-            studio,
-            &common.recording_dir,
-            clean_generation,
-        )
-    {
-        crate::clean_capture::confirm_stop_notice(&handle, &owner);
-    }
-
-    #[cfg(not(target_os = "linux"))]
-    let mut cleared = cleared;
-
-    if let Some(in_progress) = cleared.as_ref() {
-        let mode = in_progress.inputs().mode;
-        let (snapshot, duration_secs, mic_feed) = {
-            match in_progress {
-                InProgressRecording::Instant {
-                    common, mic_feed, ..
-                }
-                | InProgressRecording::Studio {
-                    common, mic_feed, ..
-                } => (
-                    common.health.snapshot(),
-                    common.health.seconds_since_start() as u64,
-                    mic_feed.clone(),
-                ),
-            }
-        };
-        let drop_rate_pct = 0.0_f64;
-        let dropped_mic_messages = match mic_feed {
-            Some(feed) => feed.dropped_message_count().await,
-            None => 0,
-        };
-        #[cfg(target_os = "linux")]
-        if let Some(attempt) = &strict_attempt {
-            recording = attempt.checked(recording);
-        }
-        let (status, error_class) = match &recording {
-            Ok(_) => ("stopped", None),
-            Err(e) => ("failed", Some(classify_error_message(e.as_str()))),
-        };
-        crate::telemetry::async_capture_event(
-            &handle,
-            crate::telemetry::AnalyticsEvent::RecordingCompleted {
-                mode: crate::recording_telemetry::mode_label(mode),
-                status,
-                duration_secs,
-                segment_count: 1,
-                track_failure_count: 0,
-                error_class,
-                video_frames_captured: 0,
-                video_frames_dropped: 0,
-                drop_rate_pct,
-                capture_stalls_count: snapshot.capture_stalls_count,
-                capture_stalls_max_ms: snapshot.capture_stalls_max_ms,
-                mixer_stalls_count: snapshot.mixer_stalls_count,
-                mixer_stalls_max_ms: snapshot.mixer_stalls_max_ms,
-                audio_gaps_count: snapshot.audio_gaps_count,
-                audio_gaps_total_ms: snapshot.audio_gaps_total_ms,
-                frame_drop_rate_high_count: snapshot.frame_drop_rate_high_count,
-                source_restarts_count: snapshot.source_restarts_count,
-                muxer_crash_count: snapshot.muxer_crash_count,
-                audio_degraded_count: snapshot.audio_degraded_count,
-                dropped_mic_messages,
-            },
-        );
-    }
-
-    app.disconnected_inputs.clear();
-    app.camera_in_use = false;
-
-    if recording.is_err()
-        && let Some(InProgressRecording::Instant {
-            segment_upload,
-            video_upload_info,
-            ..
-        }) = cleared.as_ref()
-    {
-        info!("Ending upload after recording failure");
-        #[cfg(not(target_os = "linux"))]
-        segment_upload.session.cancel();
-        #[cfg(target_os = "linux")]
-        {
-            let _ = segment_upload;
-            if let Some(attempt) = linux_instant::current(&handle) {
-                attempt.upload().deny();
-            }
-        }
-        crate::upload::emit_upload_complete(&handle, &video_upload_info.id);
-    }
-
-    #[cfg(not(target_os = "linux"))]
-    if recording.is_err()
-        && let Some(InProgressRecording::Instant { segment_upload, .. }) = cleared.take()
-    {
-        let session = segment_upload.session.clone();
-        let _ = crate::upload::lifecycle::supervise(handle.clone(), session, async move {
-            segment_upload
-                .handle
-                .await
-                .map_err(|error| error.to_string())?
-        })
-        .await;
-    }
-    drop(cleared);
-
-    if app.was_camera_only_recording {
-        app.was_camera_only_recording = false;
-    }
-
-    #[cfg(target_os = "linux")]
-    if let Some(attempt) = &strict_attempt {
-        recording = attempt.checked(recording);
-    }
-    let res = match recording {
-        // we delay reporting errors here so that everything else happens first
-        Ok(recording) => Some(
-            handle_recording_finish(&handle, recording, finalization_project, camera_snapshot)
-                .await,
-        ),
-        Err(error) => {
-            if let Ok(mut project_meta) =
-                RecordingMeta::load_for_project(&recording_dir).map_err(|err| {
-                    error!("Error loading recording meta while finishing recording: {err}")
-                })
-            {
-                match &mut project_meta.inner {
-                    RecordingMetaInner::Studio(meta) => {
-                        if let StudioRecordingMeta::MultipleSegments { inner } = &mut **meta {
-                            inner.status = Some(StudioRecordingStatus::Failed { error });
-                        }
-                    }
-                    RecordingMetaInner::Instant(meta) => {
-                        *meta = InstantRecordingMeta::Failed { error };
-                    }
-                }
-                project_meta
-                    .save_for_project()
-                    .map_err(|err| {
-                        error!("Error saving recording meta while finishing recording: {err}")
-                    })
-                    .ok();
-            }
-
-            None
-        }
-    };
-
-    let _ = RecordingStopped.emit(&handle);
-
-    let _ = app.recording_logging_handle.reload(None);
-
-    if let Some(window) = CapWindowId::RecordingControls.get(&handle) {
-        let _ = window.hide();
-    }
-
-    crate::target_select_overlay::close_target_select_overlay_windows(&handle);
-
-    if let Some(camera) = CapWindowId::Camera.get(&handle) {
-        let _ = camera.hide();
-    }
-
-    app.camera_preview.pause();
-    app.applied_mic_input.invalidate();
-    let _ = app.mic_feed.ask(microphone::RemoveInput).await;
-    let _ = app.camera_feed.ask(camera::RemoveInput).await;
-
-    let main_window = CapWindowId::Main.get(&handle);
-
-    // When the finish path handed the foreground to an editor window, leave
-    // the main window alone: un-minimizing it here (Windows `Close` behaviour
-    // minimizes; macOS `Minimise` miniaturizes) would restore it on top of the
-    // editor that just opened.
-    let mut editor_took_foreground = matches!(&res, Some(Ok(true)));
-
-    if let Some(window) = main_window {
-        if !editor_took_foreground && clean_generation.is_none() {
-            window.unminimize().ok();
-        }
-        let requested = handle.state::().snapshot();
-        if clean_generation.is_none()
-            && !requested.microphone.pending
-            && requested.microphone.error.is_none()
-            && requested.microphone.value == app.selected_mic_label
-            && let Err(err) = app.ensure_selected_mic_ready().await
-        {
-            warn!("Failed to restore microphone preview after recording: {err}");
-        }
-    } else {
-        app.selected_mic_label = None;
-        app.selected_camera_id = None;
-    }
-
-    // Fallback for in-editor recordings that did NOT reach
-    // `apply_post_studio_editor_behaviour` (failed/cancelled recordings, or
-    // non-studio modes). On the studio success path `handle_recording_finish`
-    // — awaited above into `res` — already consumed the target and emitted
-    // `EditorRecordingAdded`, so this `take()` returns `None` and is a no-op.
-    // Using `take()` (not `current()`) here is deliberate: it restores the
-    // editor window AND clears any stale target so it can't leak into the next
-    // recording session.
-    if let Some(editor_path) = take_editor_target_after_recording(
-        &EditorRecordingTarget::get(&handle),
-        preserve_editor_target,
-    ) {
-        crate::editor_recording::finish(&handle);
-        if crate::editor_recording::reveal_editor(&handle, &editor_path) {
-            editor_took_foreground = true;
-        }
-    }
-
-    CurrentRecordingChanged.emit(&handle).ok();
-    if let Some(generation) = clean_generation {
-        crate::clean_capture::release_after_recording(&handle, generation, editor_took_foreground);
-    }
-
-    if let Some(res) = res {
-        let _editor_took_foreground: bool = res?;
-    }
-
-    Ok(())
-}
-
-fn compute_studio_duration_secs(recording_dir: &std::path::Path) -> f64 {
-    let Ok(meta) = RecordingMeta::load_for_project(recording_dir) else {
-        return 0.0;
-    };
-    let Some(studio_meta) = meta.studio_meta() else {
-        return 0.0;
-    };
-    ProjectRecordingsMeta::new(&recording_dir.to_path_buf(), studio_meta)
-        .map(|r| r.duration())
-        .unwrap_or(0.0)
-}
-
-/// Returns `true` when an editor window took the foreground (in-editor
-/// re-record, or the post-recording behaviour opened the editor). Callers use
-/// this to keep the main window suppressed so it can't cover the editor.
-async fn apply_post_studio_editor_behaviour(
-    app: &AppHandle,
-    recording_dir: PathBuf,
-    duration_secs: f64,
-) -> bool {
-    if let Some(editor_path) = EditorRecordingTarget::take(app) {
-        crate::editor_recording::finish(app);
-        crate::editor_recording::reveal_editor(app, &editor_path);
-
-        let _ = EditorRecordingAdded {
-            editor_path,
-            recording_path: recording_dir,
-        }
-        .emit(app);
-
-        return true;
-    }
-
-    let default = GeneralSettingsStore::get(app)
-        .ok()
-        .flatten()
-        .map(|v| v.post_studio_recording_behaviour)
-        .unwrap_or(PostStudioRecordingBehaviour::OpenEditor);
-
-    match crate::automation::studio_recording_editor_behaviour(
-        app,
-        &recording_dir,
-        duration_secs,
-        default,
-    ) {
-        Some(PostStudioRecordingBehaviour::OpenEditor) => {
-            let _ = ShowCapWindow::Editor {
-                project_path: recording_dir,
-            }
-            .show(app)
-            .await;
-
-            true
-        }
-        Some(PostStudioRecordingBehaviour::ShowOverlay) => {
-            let _ = ShowCapWindow::RecordingsOverlay.show(app).await;
-
-            let app = AppHandle::clone(app);
-            tokio::spawn(async move {
-                tokio::time::sleep(Duration::from_millis(1000)).await;
-                let _ = NewStudioRecordingAdded {
-                    path: recording_dir,
-                }
-                .emit(&app);
-            });
-
-            false
-        }
-        None => {
-            let _ = NewStudioRecordingAdded {
-                path: recording_dir,
-            }
-            .emit(app);
-
-            false
-        }
-    }
-}
-
-// runs when a recording successfully finishes; Ok(true) means an editor
-// window took the foreground and the main window must stay suppressed
-async fn handle_recording_finish(
-    app: &AppHandle,
-    completed_recording: CompletedRecording,
-    finalization_project: Option, String>>,
-    camera_snapshot: Option,
-) -> Result {
-    let recording_dir = completed_recording.project_path().clone();
-
-    let screenshots_dir = recording_dir.join("screenshots");
-    std::fs::create_dir_all(&screenshots_dir).ok();
-
-    let (meta_inner, sharing) = match completed_recording {
-        CompletedRecording::Studio {
-            recording,
-            capture_target,
-            ..
-        } => {
-            let meta_inner = RecordingMetaInner::Studio(Box::new(recording.meta.clone()));
-
-            if let Ok(mut meta) = RecordingMeta::load_for_project(&recording_dir).map_err(|err| {
-                error!("Failed to load recording meta while saving finished recording: {err}")
-            }) {
-                meta.inner = meta_inner.clone();
-                meta.sharing = None;
-                meta.save_for_project()
-                    .map_err(|e| format!("Failed to save recording meta: {e}"))?;
-            }
-
-            let needs_remux = needs_fragment_remux(&recording_dir, &recording.meta);
-
-            if needs_remux {
-                info!(
-                    "Recording has fragments queued for finalization - opening editor immediately"
-                );
-
-                let project = finalization_project.ok_or_else(|| {
-                    crate::recoverable_finalization_error(
-                        &recording_dir,
-                        "Recording directory was not admitted for finalization.".into(),
-                    )
-                })??;
-                let finalizing_state = app.state::();
-                let finalization = finalizing_state.start_finalizing(project.clone())?;
-
-                let duration = compute_studio_duration_secs(&recording_dir);
-                let editor_took_foreground =
-                    apply_post_studio_editor_behaviour(app, recording_dir.clone(), duration).await;
-
-                AppSounds::StopRecording.play();
-
-                let app = app.clone();
-                let recording_dir_for_finalize = recording_dir.clone();
-                let default_preset = PresetsStore::get_default_preset(&app)
-                    .ok()
-                    .flatten()
-                    .map(|p| p.config);
-
-                tokio::spawn(async move {
-                    let result = finalize_studio_recording(
-                        &app,
-                        project,
-                        recording,
-                        default_preset,
-                        Some(capture_target),
-                        finalization.preparing(),
-                        camera_snapshot,
-                    )
-                    .await;
-
-                    match &result {
-                        Ok(()) => {
-                            let duration =
-                                compute_studio_duration_secs(&recording_dir_for_finalize);
-                            crate::automation::run_studio_recording_automations(
-                                app.clone(),
-                                recording_dir_for_finalize.clone(),
-                                duration,
-                            );
-                        }
-                        Err(e) => error!("Failed to finalize recording: {e}"),
-                    }
-
-                    finalization.finish(result);
-                });
-
-                return Ok(editor_took_foreground);
-            }
-
-            let updated_studio_meta = recording.meta.clone();
-
-            let display_output_path = match &updated_studio_meta {
-                StudioRecordingMeta::SingleSegment { segment } => {
-                    segment.display.path.to_path(&recording_dir)
-                }
-                StudioRecordingMeta::MultipleSegments { inner, .. } => {
-                    inner.segments[0].display.path.to_path(&recording_dir)
-                }
-            };
-
-            let display_screenshot = screenshots_dir.join("display.jpg");
-            tokio::spawn(create_screenshot(
-                display_output_path,
-                display_screenshot.clone(),
-                None,
-            ));
-
-            let recordings = ProjectRecordingsMeta::new(&recording_dir, &updated_studio_meta)?;
-
-            let config = project_config_from_recording(
-                app,
-                &cap_recording::studio_recording::CompletedRecording {
-                    project_path: recording.project_path,
-                    meta: updated_studio_meta.clone(),
-                    cursor_data: recording.cursor_data,
-                    clean_stopped: None,
-                },
-                &recordings,
-                PresetsStore::get_default_preset(app)?.map(|p| p.config),
-                Some(&capture_target),
-                stored_current_desktop_background_path(&recording_dir),
-                camera_snapshot.as_ref(),
-            );
-
-            config.write(&recording_dir).map_err(|e| e.to_string())?;
-
-            (
-                RecordingMetaInner::Studio(Box::new(updated_studio_meta)),
-                None,
-            )
-        }
-        CompletedRecording::Instant {
-            #[cfg(target_os = "linux")]
-            finalized,
-            recording,
-            segment_upload,
-            video_upload_info,
-            ..
-        } => {
-            #[cfg(target_os = "linux")]
-            if finalized {
-                if let Some(attempt) = linux_instant::current(app) {
-                    attempt.checked(Ok(()))?;
-                }
-                return Ok(false);
-            }
-            if !recording.health.is_uploadable()
-                && let cap_recording::RecordingHealth::Damaged { ref reason } = recording.health
-            {
-                error!(
-                    reason,
-                    "Instant recording is damaged and cannot be uploaded"
-                );
-                RecordingEvent::Failed {
-                    error: format!("Recording output is damaged: {reason}"),
-                }
-                .emit(app)
-                .ok();
-                return Ok(false);
-            }
-
-            AppSounds::StopRecording.play();
-            use tauri_plugin_clipboard_manager::ClipboardExt;
-            let _ = app.clipboard().write_text(video_upload_info.link.clone());
-            let _ = open_external_link(
-                app.clone(),
-                recording_stopped_share_url(&video_upload_info.link),
-            );
-
-            let app = app.clone();
-            let is_camera_only =
-                matches!(recording.display_source, ScreenCaptureTarget::CameraOnly);
-
-            let display_screenshot = screenshots_dir.join("display.jpg");
-            let screenshot_task = if is_camera_only {
-                let output_mp4 = recording_dir.join("content/output.mp4");
-                tokio::spawn({
-                    let display_screenshot = display_screenshot.clone();
-                    async move { create_screenshot(output_mp4, display_screenshot, None).await }
-                })
-            } else {
-                let segments_dir = recording_dir.join("content/display");
-                tokio::spawn({
-                    let display_screenshot = display_screenshot.clone();
-                    async move {
-                        let screenshot_source: Result =
-                            create_screenshot_source_from_segments(&segments_dir).await;
-                        match screenshot_source {
-                            Ok(temp_path) => {
-                                let result =
-                                    create_screenshot(temp_path.clone(), display_screenshot, None)
-                                        .await;
-                                let _ = tokio::fs::remove_file(&temp_path).await;
-                                result
-                            }
-                            Err(e) => Err(format!("Failed to create screenshot source: {e}")),
-                        }
-                    }
-                })
-            };
-
-            #[cfg(not(target_os = "linux"))]
-            let session = segment_upload.session.clone();
-            #[cfg(target_os = "linux")]
-            let session = segment_upload.lock().await.session.clone();
-            session
-                .persist_local_complete(
-                    recording.meta.clone(),
-                    SharingMeta {
-                        id: video_upload_info.id.clone(),
-                        link: video_upload_info.link.clone(),
-                        content_hash: None,
-                    },
-                )
-                .map_err(|error| error.to_string())?;
-            session
-                .mark_ready(false)
-                .map_err(|error| error.to_string())?;
-            let job_session = session.clone();
-            crate::upload::lifecycle::supervise(app.clone(), session, {
-                let video = video_upload_info.clone();
-                let recording_dir = recording_dir.clone();
-                async move {
-                    let uploaded = await_instant_upload(segment_upload).await;
-                    let screenshot = screenshot_task.await;
-                    uploaded.map_err(AuthedApiError::from)??;
-                    screenshot
-                        .map_err(|error| error.to_string())?
-                        .map_err(AuthedApiError::from)?;
-                    job_session.check()?;
-                    let bytes = compress_image(display_screenshot).await?;
-                    crate::upload::singlepart_uploader(
-                        app.clone(),
-                        crate::api::PresignedS3PutRequest {
-                            video_id: video.id.clone(),
-                            subpath: "screenshot/screen-capture.jpg".into(),
-                            method: PresignedS3PutRequestMethod::Put,
-                            meta: None,
-                        },
-                        bytes.len() as u64,
-                        stream::once(
-                            async move { Ok::<_, std::io::Error>(bytes::Bytes::from(bytes)) },
-                        ),
-                    )
-                    .await?;
-                    job_session.complete_locally(&app).await?;
-                    crate::automation::run_upload_completed_automations(
-                        app,
-                        recording_dir,
-                        Some(video.link),
-                        Some(video.id),
-                    );
-                    Ok(())
-                }
-            })
-            .await
-            .map_err(|error| error.to_string())?;
-
-            (
-                RecordingMetaInner::Instant(recording.meta),
-                Some(SharingMeta {
-                    link: video_upload_info.link,
-                    id: video_upload_info.id,
-                    content_hash: None,
-                }),
-            )
-        }
-    };
-
-    let instant_share = sharing.as_ref().map(|s| (s.link.clone(), s.id.clone()));
-
-    if let RecordingMetaInner::Instant(_) = &meta_inner {
-        let (link, id) = match instant_share {
-            Some((link, id)) => (Some(link), Some(id)),
-            None => (None, None),
-        };
-        crate::automation::run_instant_recording_automations(
-            app.clone(),
-            recording_dir.clone(),
-            link,
-            id,
-        );
-    }
-
-    let mut editor_took_foreground = false;
-    if let RecordingMetaInner::Studio(_) = meta_inner {
-        let duration = compute_studio_duration_secs(&recording_dir);
-        crate::automation::run_studio_recording_automations(
-            app.clone(),
-            recording_dir.clone(),
-            duration,
-        );
-        editor_took_foreground =
-            apply_post_studio_editor_behaviour(app, recording_dir, duration).await;
-        AppSounds::StopRecording.play();
-    }
-
-    Ok(editor_took_foreground)
-}
-
-async fn finalize_studio_recording(
-    app: &AppHandle,
-    project: Arc,
-    recording: cap_recording::studio_recording::CompletedRecording,
-    default_preset: Option,
-    capture_target: Option,
-    preparing: crate::preparing_finalization::FinalizationPreparing,
-    camera_snapshot: Option,
-) -> Result<(), String> {
-    info!("Starting background finalization for recording");
-    project.validate_async().await?;
-    preparing.set_presentation(
-        preparing_presentation_snapshot(default_preset.as_ref(), capture_target.as_ref()).map(
-            |mut config| {
-                apply_studio_sound_default(app, &mut config);
-                if let Some(snapshot) = &camera_snapshot {
-                    snapshot.apply(&mut config);
-                }
-                config
-            },
-        ),
-    );
-    let recording_dir = project.work_path().to_path_buf();
-    let screenshots_dir = recording_dir.join("screenshots");
-    let display_path = project.display_path().to_path_buf();
-    let recording_dir_for_remux = recording_dir.clone();
-    let app_for_remux = app.clone();
-    let (remux_result, recording) = tokio::task::spawn_blocking(move || {
-        let result = remux_fragmented_recording_with_preparing(
-            &recording_dir_for_remux,
-            &display_path,
-            "recording_stop",
-            Some(&app_for_remux),
-            Some((&preparing, &recording)),
-        );
-        (result, recording)
-    })
-    .await
-    .map_err(|e| format!("Recording finalization task panicked: {e}"))?;
-
-    if let Err(e) = remux_result {
-        error!("Failed to finalize fragmented recording: {e}");
-        return Err(e);
-    }
-
-    let updated_meta = RecordingMeta::load_for_project(&recording_dir)
-        .map_err(|e| format!("Failed to reload recording meta: {e}"))?;
-    let updated_studio_meta = updated_meta
-        .studio_meta()
-        .ok_or_else(|| "Expected studio meta after remux".to_string())?
-        .clone();
-
-    let display_output_path = match &updated_studio_meta {
-        StudioRecordingMeta::SingleSegment { segment } => {
-            segment.display.path.to_path(&recording_dir)
-        }
-        StudioRecordingMeta::MultipleSegments { inner, .. } => {
-            inner.segments[0].display.path.to_path(&recording_dir)
-        }
-    };
-
-    let display_screenshot = screenshots_dir.join("display.jpg");
-    tokio::spawn(create_screenshot(
-        display_output_path,
-        display_screenshot,
-        None,
-    ));
-
-    let recordings = ProjectRecordingsMeta::new(&recording_dir, &updated_studio_meta)
-        .map_err(|e| format!("Failed to create project recordings meta: {e}"))?;
-
-    let config = project_config_from_recording(
-        app,
-        &cap_recording::studio_recording::CompletedRecording {
-            project_path: recording.project_path,
-            meta: updated_studio_meta,
-            cursor_data: recording.cursor_data,
-            clean_stopped: None,
-        },
-        &recordings,
-        default_preset,
-        capture_target.as_ref(),
-        stored_current_desktop_background_path(&recording_dir),
-        camera_snapshot.as_ref(),
-    );
-
-    config
-        .write(&recording_dir)
-        .map_err(|e| format!("Failed to write project config: {e}"))?;
-
-    project.validate_async().await?;
-    info!("Background finalization completed for recording");
-
-    Ok(())
-}
-
-pub const DEFAULT_AUTO_ZOOM_AMOUNT: f64 = 2.0;
-
-fn generate_zoom_segments_from_clicks_impl(
-    mut clicks: Vec,
-    _moves: Vec,
-    max_duration: f64,
-    zoom_amount: f64,
-) -> Vec {
-    const MS_PER_SECOND: f64 = 1000.0;
-    const START_MIN_MS: f64 = 1.0;
-    const CLICK_PRE_PADDING_MS: f64 = 300.0;
-    const CLICK_POST_PADDING_MS: f64 = 2500.0;
-    const CLICK_END_CLAMP_PADDING_MS: f64 = 800.0;
-    const TRAILING_CLICK_IGNORE_MS: f64 = 1000.0;
-    const MERGE_GAP_MS: f64 = 2500.0;
-
-    if max_duration <= 0.0 {
-        return Vec::new();
-    }
-
-    let duration_ms = max_duration * MS_PER_SECOND;
-    let click_cutoff_ms = duration_ms - TRAILING_CLICK_IGNORE_MS;
-    let end_limit_ms = duration_ms - CLICK_END_CLAMP_PADDING_MS;
-    if click_cutoff_ms <= 0.0 || end_limit_ms <= START_MIN_MS {
-        return Vec::new();
-    }
-
-    clicks.sort_by(|a, b| {
-        a.time_ms
-            .partial_cmp(&b.time_ms)
-            .unwrap_or(std::cmp::Ordering::Equal)
-    });
-
-    let mut intervals: Vec<(f64, f64)> = Vec::new();
-    for click in clicks {
-        let time_ms = click.time_ms.floor();
-        if time_ms >= click_cutoff_ms {
-            continue;
-        }
-
-        let start = (time_ms - CLICK_PRE_PADDING_MS).max(START_MIN_MS);
-        let end = (time_ms + CLICK_POST_PADDING_MS).min(end_limit_ms);
-
-        if end > start {
-            intervals.push((start, end));
-        }
-    }
-
-    if intervals.is_empty() {
-        return Vec::new();
-    }
-
-    intervals.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(std::cmp::Ordering::Equal));
-
-    let mut merged: Vec<(f64, f64)> = Vec::new();
-    for interval in intervals {
-        if let Some(last) = merged.last_mut()
-            && interval.0 <= last.1 + MERGE_GAP_MS
-        {
-            last.1 = last.1.max(interval.1);
-            continue;
-        }
-        merged.push(interval);
-    }
-
-    merged
-        .into_iter()
-        .map(|(start, end)| ZoomSegment {
-            start: start.round() / MS_PER_SECOND,
-            end: end.round() / MS_PER_SECOND,
-            amount: zoom_amount,
-            mode: ZoomMode::Auto,
-            glide_direction: GlideDirection::None,
-            glide_speed: 0.5,
-            instant_animation: false,
-            edge_snap_ratio: 0.25,
-        })
-        .collect()
-}
-
-/// Generates zoom segments based on mouse click events during recording.
-/// Used during the recording completion process.
-pub fn generate_zoom_segments_from_clicks(
-    recording: &studio_recording::CompletedRecording,
-    recordings: &ProjectRecordingsMeta,
-    zoom_amount: f64,
-) -> Vec {
-    // Build a temporary RecordingMeta so we can use the common implementation
-    let recording_meta = RecordingMeta {
-        platform: None,
-        project_path: recording.project_path.clone(),
-        pretty_name: String::new(),
-        sharing: None,
-        inner: RecordingMetaInner::Studio(Box::new(recording.meta.clone())),
-        upload: None,
-    };
-
-    generate_zoom_segments_for_project(&recording_meta, recordings, zoom_amount)
-}
-
-/// Generates zoom segments from clicks for an existing project.
-/// Used in the editor context where we have RecordingMeta.
-pub fn generate_zoom_segments_for_project(
-    recording_meta: &RecordingMeta,
-    recordings: &ProjectRecordingsMeta,
-    zoom_amount: f64,
-) -> Vec {
-    let RecordingMetaInner::Studio(studio_meta) = &recording_meta.inner else {
-        return Vec::new();
-    };
-
-    let mut all_clicks = Vec::new();
-    let mut all_moves = Vec::new();
-
-    match &**studio_meta {
-        StudioRecordingMeta::SingleSegment { segment } => {
-            if let Some(cursor_path) = &segment.cursor {
-                let mut events = CursorEvents::load_from_file(&recording_meta.path(cursor_path))
-                    .unwrap_or_default();
-                let pointer_ids = studio_meta.pointer_cursor_ids();
-                let pointer_ids_ref = (!pointer_ids.is_empty()).then_some(&pointer_ids);
-                events.stabilize_short_lived_cursor_shapes(
-                    pointer_ids_ref,
-                    SHORT_CURSOR_SHAPE_DEBOUNCE_MS,
-                );
-                all_clicks = events.clicks;
-                all_moves = events.moves;
-            }
-        }
-        StudioRecordingMeta::MultipleSegments { inner, .. } => {
-            for segment in inner.segments.iter() {
-                let events = segment.cursor_events(recording_meta);
-                all_clicks.extend(events.clicks);
-                all_moves.extend(events.moves);
-            }
-        }
-    }
-
-    generate_zoom_segments_from_clicks_impl(
-        all_clicks,
-        all_moves,
-        recordings.duration(),
-        zoom_amount,
-    )
-}
-
-fn apply_studio_sound_default(app: &AppHandle, config: &mut ProjectConfiguration) {
-    let audio_enhancement = app
-        .store("store")
-        .ok()
-        .and_then(|store| store.get("audio_enhancement"));
-    if audio_enhancement
-        .as_ref()
-        .and_then(|value| {
-            value
-                .get("enabledByDefault")
-                .and_then(serde_json::Value::as_bool)
-        })
-        .unwrap_or(true)
-    {
-        config.audio.improve = true;
-        config.audio.isolation = audio_enhancement
-            .and_then(|value| value.get("isolation").cloned())
-            .and_then(|value| serde_json::from_value(value).ok())
-            .unwrap_or_default();
-    }
-}
-
-fn project_config_from_recording(
-    app: &AppHandle,
-    completed_recording: &studio_recording::CompletedRecording,
-    recordings: &ProjectRecordingsMeta,
-    default_config: Option,
-    capture_target: Option<&ScreenCaptureTarget>,
-    stored_desktop_background_path: Option,
-    camera_snapshot: Option<&StudioCameraSnapshot>,
-) -> ProjectConfiguration {
-    let settings = GeneralSettingsStore::get(app)
-        .unwrap_or(None)
-        .unwrap_or_default();
-
-    let using_default_config = default_config.is_none();
-    let mut config = default_config.unwrap_or_default();
-    apply_studio_sound_default(app, &mut config);
-    if using_default_config {
-        let library = app
-            .store("store")
-            .ok()
-            .and_then(|store| store.get("animated_gradients"))
-            .and_then(|value| serde_json::from_value(value).ok());
-        apply_animated_gradient_default(
-            &mut config,
-            library.as_ref(),
-            using_default_config,
-            capture_target,
-        );
-    }
-    config.cursor.size = cap_project::CursorConfiguration::default().size;
-    apply_recording_presentation_defaults(
-        app,
-        &mut config,
-        capture_target,
-        using_default_config,
-        stored_desktop_background_path,
-    );
-
-    if let Some(snapshot) = camera_snapshot {
-        snapshot.apply(&mut config);
-    }
-
-    let timeline_segments = recordings
-        .segments
-        .iter()
-        .enumerate()
-        .map(|(i, segment)| TimelineSegment {
-            recording_clip: i as u32,
-            start: 0.0,
-            end: segment.duration(),
-            timescale: 1.0,
-            name: None,
-            speed_audio_mode: None,
-            hide_cursor: None,
-            volume: None,
-        })
-        .collect::>();
-
-    let zoom_segments = if settings.auto_zoom_on_clicks {
-        generate_zoom_segments_from_clicks(
-            completed_recording,
-            recordings,
-            settings
-                .default_zoom_amount
-                .unwrap_or(DEFAULT_AUTO_ZOOM_AMOUNT),
-        )
-    } else {
-        Vec::new()
-    };
-
-    if should_enable_notch_overlay(
-        capture_target,
-        settings.macbook_notch_overlay.unwrap_or(false),
-        completed_recording.meta.display_notch().is_some(),
-    ) {
-        config.background.notch = Some(cap_project::NotchConfiguration {
-            enabled: true,
-            ..Default::default()
-        });
-    }
-
-    config.timeline = Some(recording_timeline(timeline_segments, zoom_segments));
-
-    config
-}
-
-pub(crate) fn recording_timeline(
-    segments: Vec,
-    zoom_segments: Vec,
-) -> TimelineConfiguration {
-    TimelineConfiguration {
-        segments,
-        transitions: Vec::new(),
-        zoom_segments,
-        scene_segments: Vec::new(),
-        style_segments: Vec::new(),
-        image_segments: Vec::new(),
-        mask_segments: Vec::new(),
-        text_segments: Vec::new(),
-        caption_segments: Vec::new(),
-        keyboard_segments: Vec::new(),
-        audio_segments: Vec::new(),
-        camera3d_segments: Vec::new(),
-    }
-}
-
-#[derive(Clone)]
-struct StudioCameraSnapshot {
-    state: crate::camera::CameraPreviewState,
-    placement: Option,
-}
-
-impl StudioCameraSnapshot {
-    fn capture(app: &AppHandle, state: &App, target: &ScreenCaptureTarget) -> Self {
-        Self {
-            state: state.camera_preview.get_state().unwrap_or_default(),
-            placement: state
-                .camera_in_use
-                .then(|| studio_camera_placement(app, target))
-                .flatten(),
-        }
-    }
-
-    fn apply(&self, config: &mut ProjectConfiguration) {
-        apply_recording_camera_preview_state(config, &self.state);
-        if let Some(placement) = self.placement {
-            placement.apply(&mut config.camera);
-        }
-    }
-}
-
-fn studio_camera_placement(
-    app: &AppHandle,
-    target: &ScreenCaptureTarget,
-) -> Option {
-    if matches!(target, ScreenCaptureTarget::CameraOnly) {
-        return None;
-    }
-    let window = CapWindowId::Camera.get(app)?;
-    let scale = window.scale_factor().ok()?;
-    if !scale.is_finite() || scale <= 0.0 {
-        return None;
-    }
-    let position = window.inner_position().ok()?;
-    let size = window.inner_size().ok()?;
-    let toolbar = 56.0 * scale;
-    #[cfg(target_os = "macos")]
-    let units = scale;
-    #[cfg(not(target_os = "macos"))]
-    let units = 1.0;
-    cap_recording::camera_placement::recording_camera_placement(
-        target,
-        [
-            f64::from(position.x) / units,
-            (f64::from(position.y) + toolbar) / units,
-            f64::from(size.width) / units,
-            (f64::from(size.height) - toolbar) / units,
-        ],
-    )
-}
-
-fn apply_recording_camera_preview_state(
-    config: &mut ProjectConfiguration,
-    camera_preview_state: &crate::camera::CameraPreviewState,
-) {
-    match camera_preview_state.shape {
-        CameraPreviewShape::Round => {
-            config.camera.shape = CameraShape::Square;
-            config.camera.rounding = 100.0;
-            config.camera.rounding_type = CornerStyle::Rounded;
-        }
-        CameraPreviewShape::Square => {
-            config.camera.shape = CameraShape::Square;
-            config.camera.rounding = 25.0;
-        }
-        CameraPreviewShape::Full => {
-            config.camera.shape = CameraShape::Source;
-            config.camera.rounding = 25.0;
-        }
-    }
-
-    config.camera.background_blur = cap_project::BackgroundBlurConfig {
-        mode: camera_preview_state.background_blur,
-    };
-}
-
-fn should_enable_notch_overlay(
-    capture_target: Option<&ScreenCaptureTarget>,
-    setting_enabled: bool,
-    has_recorded_notch: bool,
-) -> bool {
-    setting_enabled
-        && has_recorded_notch
-        && matches!(
-            capture_target,
-            Some(ScreenCaptureTarget::Display { .. } | ScreenCaptureTarget::Area { .. })
-        )
-}
-
-fn apply_recording_presentation_defaults(
-    app: &AppHandle,
-    config: &mut ProjectConfiguration,
-    capture_target: Option<&ScreenCaptureTarget>,
-    using_default_config: bool,
-    stored_desktop_background_path: Option,
-) {
-    let default_wallpaper_path = if using_default_config {
-        stored_desktop_background_path.or_else(|| {
-            app.path()
-                .resolve("assets/backgrounds/cities/sf.jpg", BaseDirectory::Resource)
-                .ok()
-                .map(|path| path.to_string_lossy().into_owned())
-        })
-    } else {
-        None
-    };
-
-    apply_screen_recording_presentation_defaults(
-        config,
-        capture_target,
-        using_default_config,
-        default_wallpaper_path,
-    );
-}
-
-fn apply_animated_gradient_default(
-    config: &mut ProjectConfiguration,
-    library: Option<&cap_project::AnimatedGradientLibrary>,
-    using_default_config: bool,
-    capture_target: Option<&ScreenCaptureTarget>,
-) {
-    if using_default_config
-        && !matches!(capture_target, Some(ScreenCaptureTarget::CameraOnly))
-        && let Some(library) = library
-        && library.selected
-        && let Some(gradient) = &library.last_used
-    {
-        config.background.source = cap_project::BackgroundSource::AnimatedGradient {
-            config: gradient.normalized(),
-        };
-    }
-}
-
-const DEFAULT_SCREEN_RECORDING_BACKGROUND_ROUNDING_PERCENT: f64 = 7.5;
-
-fn apply_screen_recording_presentation_defaults(
-    config: &mut ProjectConfiguration,
-    capture_target: Option<&ScreenCaptureTarget>,
-    using_default_config: bool,
-    default_wallpaper_path: Option,
-) {
-    use cap_project::{BackgroundSource, ScreenMovementSpring};
-
-    if matches!(capture_target, Some(ScreenCaptureTarget::CameraOnly)) {
-        return;
-    }
-
-    let has_default_background = matches!(
-        &config.background.source,
-        BackgroundSource::Color { value, alpha } if *value == [255, 255, 255] && *alpha == 255
-    );
-
-    if using_default_config && has_default_background {
-        if let Some(path) = default_wallpaper_path {
-            config.background.source = BackgroundSource::Wallpaper { path: Some(path) };
-        }
-    }
-
-    if config.background.padding <= f64::EPSILON {
-        config.background.padding = 10.0;
-    }
-
-    if matches!(
-        capture_target,
-        Some(ScreenCaptureTarget::Window { .. } | ScreenCaptureTarget::Display { .. })
-    ) && config.background.rounding <= f64::EPSILON
-    {
-        config.background.rounding = DEFAULT_SCREEN_RECORDING_BACKGROUND_ROUNDING_PERCENT;
-    }
-
-    if (config.screen_movement_spring.stiffness - 120.0).abs() < f32::EPSILON
-        && (config.screen_movement_spring.damping - 14.0).abs() < f32::EPSILON
-        && (config.screen_movement_spring.mass - 1.0).abs() < f32::EPSILON
-    {
-        config.screen_movement_spring = ScreenMovementSpring::default();
-    }
-}
-
-pub fn default_project_config() -> ProjectConfiguration {
-    let mut config = ProjectConfiguration::default();
-
-    apply_screen_recording_presentation_defaults(&mut config, None, false, None);
-
-    if config.background.rounding <= f64::EPSILON {
-        config.background.rounding = DEFAULT_SCREEN_RECORDING_BACKGROUND_ROUNDING_PERCENT;
-    }
-
-    config
-}
-
-#[tauri::command]
-#[specta::specta]
-pub fn get_default_project_config() -> ProjectConfiguration {
-    default_project_config()
-}
-
-pub fn needs_fragment_remux(recording_dir: &Path, meta: &StudioRecordingMeta) -> bool {
-    let StudioRecordingMeta::MultipleSegments { inner, .. } = meta else {
-        return false;
-    };
-
-    for segment in &inner.segments {
-        let display_path = segment.display.path.to_path(recording_dir);
-        if display_path.is_dir() {
-            return true;
-        }
-    }
-
-    false
-}
-
-pub const FRAGMENTED_EXPORT_FFMPEG_MARKER: &str = ".force-ffmpeg-export";
-
-fn fragmented_export_ffmpeg_marker_path(recording_dir: &Path) -> PathBuf {
-    recording_dir.join(FRAGMENTED_EXPORT_FFMPEG_MARKER)
-}
-
-fn mark_fragmented_recording_for_ffmpeg_export(recording_dir: &Path) -> Result<(), String> {
-    std::fs::write(
-        fragmented_export_ffmpeg_marker_path(recording_dir),
-        b"fragmented-remux",
-    )
-    .map_err(|e| format!("Failed to mark recording for FFmpeg export: {e}"))
-}
-
-pub(crate) fn remux_fragmented_recording(
-    project: &crate::FinalizationProject,
-) -> Result<(), String> {
-    remux_fragmented_recording_with_trigger(
-        project.work_path(),
-        project.display_path(),
-        "manual_remux",
-        None,
-    )
-}
-
-pub fn remux_fragmented_recording_with_trigger(
-    recording_dir: &Path,
-    display_path: &Path,
-    trigger: &'static str,
-    app: Option<&AppHandle>,
-) -> Result<(), String> {
-    remux_fragmented_recording_with_preparing(recording_dir, display_path, trigger, app, None)
-}
-
-pub(crate) fn remux_fragmented_recording_with_preparing(
-    recording_dir: &Path,
-    display_path: &Path,
-    trigger: &'static str,
-    app: Option<&AppHandle>,
-    preparing: Option<(
-        &crate::preparing_finalization::FinalizationPreparing,
-        &studio_recording::CompletedRecording,
-    )>,
-) -> Result<(), String> {
-    crate::recovery::ensure_finalization_storage(recording_dir, display_path)?;
-    let incomplete_recording = RecoveryManager::inspect_recording(recording_dir);
-
-    if let Some(recording) = incomplete_recording {
-        let normal_stop = trigger == "recording_stop";
-        let validation_start = std::time::Instant::now();
-        let outcome = if normal_stop {
-            match preparing.and_then(|(publisher, completed)| publisher.claim(completed)) {
-                Some(job) => RecoveryManager::finalize_with_preparing(&recording, job),
-                None => RecoveryManager::finalize(&recording),
-            }
-        } else {
-            RecoveryManager::recover(&recording)
-        };
-        let validation_took_ms = validation_start.elapsed().as_millis() as u64;
-
-        match outcome {
-            Ok(_) => {
-                if let Err(error) = mark_fragmented_recording_for_ffmpeg_export(recording_dir) {
-                    warn!(project_path = %recording_dir.display(), error = %error, "Failed to write fragmented recording export marker");
-                }
-                if normal_stop {
-                    info!("Successfully finalized fragmented recording");
-                } else {
-                    info!("Successfully recovered fragmented recording");
-                }
-
-                if let Some(app_handle) = app
-                    && !normal_stop
-                {
-                    let recovered_duration_secs = RecordingMeta::load_for_project(recording_dir)
-                        .ok()
-                        .and_then(|meta| match meta.inner {
-                            RecordingMetaInner::Studio(studio) => match *studio {
-                                StudioRecordingMeta::MultipleSegments { inner } => Some(
-                                    inner
-                                        .segments
-                                        .iter()
-                                        .filter_map(|seg| seg.display.start_time)
-                                        .fold(0.0_f64, |acc, v| acc.max(v)),
-                                ),
-                                StudioRecordingMeta::SingleSegment { .. } => None,
-                            },
-                            _ => None,
-                        })
-                        .map(|s| s as u64)
-                        .unwrap_or_default();
-
-                    let segments_recovered = RecordingMeta::load_for_project(recording_dir)
-                        .ok()
-                        .and_then(|meta| match meta.inner {
-                            RecordingMetaInner::Studio(studio) => match *studio {
-                                StudioRecordingMeta::MultipleSegments { inner } => {
-                                    Some(inner.segments.len() as u32)
-                                }
-                                StudioRecordingMeta::SingleSegment { .. } => Some(1),
-                            },
-                            _ => None,
-                        })
-                        .unwrap_or(0);
-
-                    crate::telemetry::async_capture_event(
-                        app_handle,
-                        crate::telemetry::AnalyticsEvent::RecordingRecovered {
-                            trigger,
-                            recovered_duration_secs,
-                            segments_recovered,
-                            validation_took_ms,
-                        },
-                    );
-                }
-                Ok(())
-            }
-            Err(e) => {
-                let storage_full = crate::recovery::is_storage_full_recovery_error(&e);
-                let reason = format!("{e}");
-                if let Some(app_handle) = app {
-                    crate::telemetry::async_capture_event(
-                        app_handle,
-                        crate::telemetry::AnalyticsEvent::RecordingRecoveryFailed {
-                            trigger,
-                            reason: reason.clone(),
-                        },
-                    );
-                }
-                if storage_full {
-                    return Err(crate::recovery::finalization_storage_error(display_path));
-                }
-                let action = if normal_stop { "finalize" } else { "recover" };
-                Err(format!("Failed to {action} recording: {reason}"))
-            }
-        }
-    } else {
-        Err("Could not find fragments to remux".to_string())
-    }
-}
-
-fn classify_error_message(error: &str) -> String {
-    let lowered = error.to_ascii_lowercase();
-    let class = if lowered.contains("permission") {
-        "permission"
-    } else if lowered.contains("disk") || lowered.contains("no space") {
-        "disk"
-    } else if lowered.contains("camera") {
-        "camera"
-    } else if lowered.contains("microphone") || lowered.contains("mic") {
-        "microphone"
-    } else if lowered.contains("display") || lowered.contains("screen") {
-        "display"
-    } else if lowered.contains("muxer") {
-        "muxer"
-    } else if lowered.contains("timeout") {
-        "timeout"
-    } else if lowered.contains("cancel") {
-        "cancelled"
-    } else {
-        "other"
-    };
-    class.to_string()
-}
-
-async fn emit_recording_started_telemetry(app: &AppHandle, state_mtx: &MutableState<'_, App>) {
-    use crate::recording_telemetry::{mode_label, target_kind_label};
-    use crate::telemetry::{AnalyticsEvent, async_capture_event};
-
-    let (mode, recording_mode, target_kind, has_camera, has_mic, has_system_audio) = {
-        let state = state_mtx.read().await;
-        let Some(recording) = state.current_recording() else {
-            return;
-        };
-        let inputs = recording.inputs();
-        let target_kind = target_kind_label(recording.capture_target());
-        let has_camera = match recording {
-            InProgressRecording::Instant { camera_feed, .. }
-            | InProgressRecording::Studio { camera_feed, .. } => camera_feed.is_some(),
-        };
-        (
-            mode_label(inputs.mode),
-            inputs.mode,
-            target_kind,
-            has_camera,
-            state.selected_mic_label.is_some(),
-            inputs.capture_system_audio,
-        )
-    };
-
-    let general = GeneralSettingsStore::get(app).ok().flatten();
-    let defaults = desktop_recording_defaults(general.as_ref());
-    let fragmented = defaults.crash_recovery_recording;
-    let custom_cursor_capture = defaults.custom_cursor_capture;
-    // Studio applies the camera fps clamp via `apply_to_studio_builder`; Instant records screen at a
-    // fixed fps, so report the value each mode actually uses rather than the raw studio cap.
-    let target_fps = match recording_mode {
-        RecordingMode::Studio => defaults.studio_max_fps(has_camera, None),
-        RecordingMode::Instant | RecordingMode::Screenshot => {
-            cap_recording::DEFAULT_INSTANT_MODE_FPS
-        }
-    };
-
-    async_capture_event(
-        app,
-        AnalyticsEvent::RecordingStarted {
-            mode,
-            target_kind,
-            has_camera,
-            has_mic,
-            has_system_audio,
-            target_fps,
-            target_width: 0,
-            target_height: 0,
-            fragmented,
-            custom_cursor_capture,
-        },
-    );
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use chrono::TimeZone as _;
-    use tempfile::tempdir;
-
-    #[test]
-    fn project_name_random_placeholder_is_filename_safe_and_sized() {
-        let name = format_project_name(
-            Some("{random}-{random:16}-{random:0}"),
-            "Example Window",
-            "Window",
-            RecordingMode::Studio,
-            None,
-        );
-        let parts = name.split('-').collect::>();
-
-        assert_eq!(parts[0].len(), 10);
-        assert_eq!(parts[1].len(), 16);
-        assert!(
-            parts[..2]
-                .iter()
-                .all(|part| part.chars().all(|character| character.is_ascii_hexdigit()))
-        );
-        assert_eq!(parts[2], "{random:0}");
-    }
-
-    #[test]
-    fn project_name_preserves_random_placeholder_in_window_title() {
-        let timestamp = chrono::Local
-            .with_ymd_and_hms(2026, 8, 25, 9, 15, 0)
-            .single()
-            .unwrap();
-
-        let name = format_project_name(
-            None,
-            "Implement {random} placeholder",
-            "Window",
-            RecordingMode::Studio,
-            Some(timestamp),
-        );
-
-        assert!(name.contains("Implement {random} placeholder"));
-    }
-
-    #[test]
-    fn requested_microphone_absence_is_an_error_not_an_empty_track() {
-        let error = selected_microphone_for_start(Some("Requested mic".into()), &[])
-            .unwrap_err()
-            .to_string();
-        assert!(error.contains("Requested mic"));
-        assert!(error.contains("no longer available"));
-        assert!(error.contains("Reconnect"));
-    }
-
-    #[test]
-    fn requested_microphone_requires_exact_name_without_substring_fallback() {
-        for names in [
-            vec!["Requested mic alternate".into()],
-            vec!["mic".into()],
-            vec!["requested mic".into()],
-        ] {
-            assert!(selected_microphone_for_start(Some("Requested mic".into()), &names).is_err());
-        }
-        assert_eq!(
-            selected_microphone_for_start(
-                Some("Requested mic".into()),
-                &["Requested mic alternate".into(), "Requested mic".into()],
-            )
-            .unwrap(),
-            Some("Requested mic".into())
-        );
-    }
-
-    #[test]
-    fn intentional_no_microphone_is_preserved() {
-        assert_eq!(selected_microphone_for_start(None, &[]).unwrap(), None);
-        assert_eq!(
-            selected_microphone_for_start(None, &["Another mic".into()]).unwrap(),
-            None
-        );
-    }
-
-    #[test]
-    fn requested_camera_absence_is_an_error_for_screen_capture_too() {
-        let id = camera::DeviceOrModelID::DeviceID("requested-camera".into());
-        let error = validate_selected_camera_for_start(Some(&id), |_| false)
-            .unwrap_err()
-            .to_string();
-        assert!(error.contains("requested-camera"));
-        assert!(error.contains("no longer available"));
-        assert!(error.contains("Reconnect"));
-        assert!(validate_selected_camera_for_start(Some(&id), |_| true).is_ok());
-    }
-
-    #[test]
-    fn intentional_no_camera_does_not_probe_or_choose_another_device() {
-        assert!(
-            validate_selected_camera_for_start(None, |_| { panic!("No camera was requested") })
-                .is_ok()
-        );
-    }
-
-    #[test]
-    fn animated_gradient_default_is_remembered_without_overwriting_explicit_presets() {
-        let library = cap_project::AnimatedGradientLibrary {
-            selected: true,
-            last_used: Some(cap_project::AnimatedGradientConfig::from_seed(42)),
-            ..Default::default()
-        };
-        let mut project = ProjectConfiguration::default();
-        apply_animated_gradient_default(&mut project, Some(&library), false, None);
-        assert!(matches!(
-            project.background.source,
-            cap_project::BackgroundSource::Color { .. }
-        ));
-        apply_animated_gradient_default(&mut project, Some(&library), true, None);
-        apply_screen_recording_presentation_defaults(
-            &mut project,
-            None,
-            true,
-            Some("wallpaper.jpg".into()),
-        );
-        let cap_project::BackgroundSource::AnimatedGradient { config } = project.background.source
-        else {
-            panic!("Expected remembered gradient");
-        };
-        assert_eq!(Some(config), library.last_used);
-        assert_eq!(project.background.padding, 10.0);
-    }
-
-    #[test]
-    fn deselected_or_missing_animated_gradient_keeps_recording_defaults() {
-        let mut project = ProjectConfiguration::default();
-        let library = cap_project::AnimatedGradientLibrary {
-            last_used: Some(cap_project::AnimatedGradientConfig::default()),
-            ..Default::default()
-        };
-        apply_animated_gradient_default(&mut project, Some(&library), true, None);
-        apply_animated_gradient_default(&mut project, None, true, None);
-        assert!(matches!(
-            project.background.source,
-            cap_project::BackgroundSource::Color { .. }
-        ));
-    }
-
-    #[test]
-    fn animated_gradient_default_preserves_camera_only_presentation() {
-        let library = cap_project::AnimatedGradientLibrary {
-            selected: true,
-            last_used: Some(cap_project::AnimatedGradientConfig::default()),
-            ..Default::default()
-        };
-        let mut project = ProjectConfiguration::default();
-        let original = serde_json::to_value(&project.background).unwrap();
-        apply_animated_gradient_default(
-            &mut project,
-            Some(&library),
-            true,
-            Some(&ScreenCaptureTarget::CameraOnly),
-        );
-        assert_eq!(serde_json::to_value(project.background).unwrap(), original);
-    }
-
-    #[test]
-    fn recording_start_preflight_requires_authentication_for_instant_recordings() {
-        assert_eq!(
-            recording_start_mode_error(RecordingMode::Instant, false),
-            Some("Please sign in to use instant recording")
-        );
-        assert_eq!(
-            recording_start_mode_error(RecordingMode::Instant, true),
-            None
-        );
-    }
-
-    #[test]
-    fn recording_start_preflight_preserves_studio_and_rejects_screenshot_modes() {
-        assert_eq!(
-            recording_start_mode_error(RecordingMode::Studio, false),
-            None
-        );
-        assert_eq!(
-            recording_start_mode_error(RecordingMode::Screenshot, true),
-            Some("Use take_screenshot for screenshots")
-        );
-    }
-
-    fn click_event_with_state(time_ms: f64, down: bool) -> CursorClickEvent {
-        CursorClickEvent {
-            active_modifiers: vec![],
-            cursor_num: 0,
-            cursor_id: "default".to_string(),
-            time_ms,
-            down,
-        }
-    }
-
-    fn click_event(time_ms: f64) -> CursorClickEvent {
-        click_event_with_state(time_ms, true)
-    }
-
-    fn click_up_event(time_ms: f64) -> CursorClickEvent {
-        click_event_with_state(time_ms, false)
-    }
-
-    fn move_event(time_ms: f64, x: f64, y: f64) -> CursorMoveEvent {
-        CursorMoveEvent {
-            active_modifiers: vec![],
-            cursor_id: "default".to_string(),
-            time_ms,
-            x,
-            y,
-        }
-    }
-
-    #[test]
-    fn mic_feed_locked_detects_feed_lock_errors() {
-        assert!(mic_feed_locked(&anyhow::Error::new(
-            microphone::FeedLockedError
-        )));
-        assert!(mic_feed_locked(&anyhow::Error::new(
-            microphone::LockFeedError::Locked(microphone::FeedLockedError)
-        )));
-        assert!(mic_feed_locked(&anyhow::Error::new(
-            microphone::SetInputError::Locked(microphone::FeedLockedError)
-        )));
-    }
-
-    #[test]
-    fn mic_feed_locked_ignores_unrelated_errors() {
-        assert!(!mic_feed_locked(&anyhow!("different failure")));
-    }
-
-    #[test]
-    fn skips_trailing_stop_click() {
-        let segments = generate_zoom_segments_from_clicks_impl(
-            vec![click_event(11_900.0)],
-            vec![],
-            12.0,
-            DEFAULT_AUTO_ZOOM_AMOUNT,
-        );
-
-        assert!(
-            segments.is_empty(),
-            "expected trailing stop click to be ignored"
-        );
-    }
-
-    #[test]
-    fn merges_clicks_with_three_second_gap() {
-        let clicks = vec![click_event(1_200.0), click_event(4_200.0)];
-        let moves = vec![
-            move_event(1_500.0, 0.10, 0.12),
-            move_event(1_720.0, 0.42, 0.45),
-            move_event(1_940.0, 0.74, 0.78),
-        ];
-
-        let segments =
-            generate_zoom_segments_from_clicks_impl(clicks, moves, 20.0, DEFAULT_AUTO_ZOOM_AMOUNT);
-
-        assert!(
-            !segments.is_empty(),
-            "expected activity to produce zoom segments"
-        );
-        let first = &segments[0];
-        assert_eq!(segments.len(), 1);
-        assert_eq!(first.start, 0.9);
-        assert_eq!(first.end, 6.7);
-    }
-
-    #[test]
-    fn separates_click_groups_across_long_idle_gap() {
-        let clicks = vec![
-            click_event(2_271.0),
-            click_event(9_137.0),
-            click_event(9_915.0),
-            click_event(19_404.0),
-        ];
-        let moves = vec![
-            move_event(562.0, 0.48, 0.50),
-            move_event(2_271.0, 0.05, 0.08),
-            move_event(9_137.0, 0.94, 0.06),
-            move_event(9_915.0, 0.94, 0.07),
-            move_event(19_364.0, 0.44, 0.95),
-        ];
-
-        let segments = generate_zoom_segments_from_clicks_impl(
-            clicks,
-            moves,
-            19.436_667,
-            DEFAULT_AUTO_ZOOM_AMOUNT,
-        );
-
-        assert_eq!(segments.len(), 2);
-        assert_eq!(segments[0].start, 1.971);
-        assert_eq!(segments[0].end, 4.771);
-        assert_eq!(segments[1].start, 8.837);
-        assert_eq!(segments[1].end, 12.415);
-    }
-
-    #[test]
-    fn extends_segment_until_after_mouse_up() {
-        let clicks = vec![click_event(1_000.0), click_up_event(2_500.0)];
-
-        let segments =
-            generate_zoom_segments_from_clicks_impl(clicks, vec![], 10.0, DEFAULT_AUTO_ZOOM_AMOUNT);
-
-        assert_eq!(segments.len(), 1);
-        assert_eq!(segments[0].start, 0.7);
-        assert_eq!(segments[0].end, 5.0);
-    }
-
-    #[test]
-    fn clamps_zoom_end_before_recording_end() {
-        let clicks = vec![click_event(8_999.0), click_event(9_000.0)];
-
-        let segments =
-            generate_zoom_segments_from_clicks_impl(clicks, vec![], 10.0, DEFAULT_AUTO_ZOOM_AMOUNT);
-
-        assert_eq!(segments.len(), 1);
-        assert_eq!(segments[0].start, 8.699);
-        assert_eq!(segments[0].end, 9.2);
-    }
-
-    #[test]
-    fn does_not_zoom_without_clicks() {
-        let jitter_moves = (0..30)
-            .map(|i| {
-                let t = 1_000.0 + (i as f64) * 30.0;
-                let delta = (i as f64) * 0.0004;
-                move_event(t, 0.5 + delta, 0.5)
-            })
-            .collect::>();
-
-        let segments = generate_zoom_segments_from_clicks_impl(
-            Vec::new(),
-            jitter_moves,
-            15.0,
-            DEFAULT_AUTO_ZOOM_AMOUNT,
-        );
-
-        assert!(
-            segments.is_empty(),
-            "small jitter should not generate segments"
-        );
-    }
-
-    #[test]
-    fn marks_fragmented_recordings_for_ffmpeg_export() {
-        let dir = tempdir().unwrap();
-
-        assert!(!fragmented_export_ffmpeg_marker_path(dir.path()).exists());
-
-        mark_fragmented_recording_for_ffmpeg_export(dir.path()).unwrap();
-
-        assert!(fragmented_export_ffmpeg_marker_path(dir.path()).exists());
-    }
-
-    #[test]
-    fn skips_desktop_background_paths_that_can_trigger_macos_prompts() {
-        let home = Path::new("/Users/test");
-
-        assert!(desktop_background_source_requires_user_prompt_for_home(
-            Path::new("/Users/test/Downloads/wallpaper.jpg"),
-            home
-        ));
-        assert!(desktop_background_source_requires_user_prompt_for_home(
-            Path::new("/Users/test/Library/CloudStorage/iCloud Drive/wallpaper.jpg"),
-            home
-        ));
-        assert!(!desktop_background_source_requires_user_prompt_for_home(
-            Path::new("/Users/test/Pictures/wallpaper.jpg"),
-            home
-        ));
-        assert!(!desktop_background_source_requires_user_prompt_for_home(
-            Path::new("/System/Library/Desktop Pictures/wallpaper.jpg"),
-            home
-        ));
-    }
-
-    #[test]
-    fn importing_a_desktop_background_preserves_referenced_snapshots() {
-        let dir = tempdir().unwrap();
-        let project = dir.path().join("project.cap");
-        let source = dir.path().join("wallpaper.jpg");
-        image::RgbImage::from_pixel(32, 16, image::Rgb([40, 120, 200]))
-            .save(&source)
-            .unwrap();
-        let previous = project.join("assets/current-desktop-background-1.jpg");
-        let previous_pending = project.join("assets/current-desktop-background-1.pending.jpg");
-        assert!(matches!(
-            write_desktop_background_source_to(&source, &previous, &previous_pending).unwrap(),
-            CurrentDesktopBackgroundWrite::Stored
-        ));
-        let saved_style_path = previous.clone();
-        let history_path = previous.clone();
-        let previous_bytes = std::fs::read(&previous).unwrap();
-        let sibling_pending = project.join("assets/current-desktop-background-2.pending.jpg");
-        std::fs::write(&sibling_pending, b"another import in progress").unwrap();
-
-        image::RgbImage::from_pixel(48, 24, image::Rgb([180, 60, 30]))
-            .save(&source)
-            .unwrap();
-        let imported = import_current_desktop_background_from_source(&project, &source).unwrap();
-
-        assert_ne!(Path::new(&imported), previous);
-        assert_eq!(image::image_dimensions(&imported).unwrap(), (48, 24));
-        assert_eq!(std::fs::read(saved_style_path).unwrap(), previous_bytes);
-        assert_eq!(image::image_dimensions(history_path).unwrap(), (32, 16));
-        assert_eq!(
-            std::fs::read(sibling_pending).unwrap(),
-            b"another import in progress"
-        );
-    }
-
-    #[test]
-    fn notch_overlay_requires_recorded_geometry_on_screen_target() {
-        let display = ScreenCaptureTarget::Display {
-            id: "1".parse().unwrap(),
-        };
-        let area = ScreenCaptureTarget::Area {
-            screen: "1".parse().unwrap(),
-            bounds: scap_targets::bounds::LogicalBounds::new(
-                scap_targets::bounds::LogicalPosition::new(0.0, 0.0),
-                scap_targets::bounds::LogicalSize::new(100.0, 100.0),
-            ),
-        };
-
-        assert!(should_enable_notch_overlay(Some(&display), true, true));
-        assert!(should_enable_notch_overlay(Some(&area), true, true));
-        assert!(!should_enable_notch_overlay(Some(&display), true, false));
-        assert!(!should_enable_notch_overlay(Some(&area), true, false));
-        assert!(!should_enable_notch_overlay(Some(&display), false, true));
-        assert!(!should_enable_notch_overlay(
-            Some(&ScreenCaptureTarget::CameraOnly),
-            true,
-            true
-        ));
-    }
-
-    #[test]
-    fn skips_screen_presentation_defaults_for_camera_only_recordings() {
-        let mut config = ProjectConfiguration::default();
-
-        apply_screen_recording_presentation_defaults(
-            &mut config,
-            Some(&ScreenCaptureTarget::CameraOnly),
-            true,
-            Some("wallpaper.jpg".to_string()),
-        );
-
-        assert_eq!(config.background.padding, 0.0);
-        assert!(matches!(
-            config.background.source,
-            cap_project::BackgroundSource::Color {
-                value: [255, 255, 255],
-                alpha: 255,
-            }
-        ));
-    }
-
-    #[test]
-    fn applies_screen_presentation_defaults_for_screen_recordings() {
-        let mut config = ProjectConfiguration::default();
-        let capture_target = ScreenCaptureTarget::Display {
-            id: "1".parse().unwrap(),
-        };
-
-        apply_screen_recording_presentation_defaults(
-            &mut config,
-            Some(&capture_target),
-            true,
-            Some("wallpaper.jpg".to_string()),
-        );
-
-        assert_eq!(config.background.padding, 10.0);
-        assert_eq!(config.background.rounding, 7.5);
-        assert!(matches!(
-            config.background.source,
-            cap_project::BackgroundSource::Wallpaper { path: Some(path) } if path == "wallpaper.jpg"
-        ));
-    }
-
-    #[test]
-    fn screen_presentation_defaults_apply_window_rounding_without_default_border() {
-        let mut config = ProjectConfiguration::default();
-        let capture_target = ScreenCaptureTarget::Window {
-            id: "1".parse().unwrap(),
-        };
-
-        apply_screen_recording_presentation_defaults(
-            &mut config,
-            Some(&capture_target),
-            true,
-            Some("wallpaper.jpg".to_string()),
-        );
-
-        assert_eq!(config.background.rounding, 7.5);
-        assert!(config.background.border.is_none());
-    }
-
-    #[test]
-    fn default_project_config_matches_screen_recording_presentation() {
-        let config = default_project_config();
-        let spring = cap_project::ScreenMovementSpring::default();
-
-        assert_eq!(config.background.padding, 10.0);
-        assert_eq!(
-            config.background.rounding,
-            DEFAULT_SCREEN_RECORDING_BACKGROUND_ROUNDING_PERCENT
-        );
-        assert_eq!(config.screen_movement_spring.stiffness, spring.stiffness);
-        assert_eq!(config.screen_movement_spring.damping, spring.damping);
-        assert_eq!(config.screen_movement_spring.mass, spring.mass);
-    }
-
-    #[test]
-    fn classifies_unsolicited_pipeline_completion_as_unexpected_stop() {
-        let disposition = classify_actor_done_result(Ok::<(), anyhow::Error>(()), true);
-
-        assert_eq!(
-            disposition,
-            ActorDoneDisposition::UnexpectedStop {
-                error: "Recording stopped unexpectedly before it was ended.".to_string()
-            }
-        );
-    }
-
-    #[test]
-    fn classifies_pipeline_completion_after_user_stop_as_expected() {
-        let disposition = classify_actor_done_result(Ok::<(), anyhow::Error>(()), false);
-
-        assert_eq!(disposition, ActorDoneDisposition::UserInitiatedStop);
-    }
-
-    #[test]
-    fn classifies_pipeline_failure_as_failure() {
-        let disposition = classify_actor_done_result(Err(anyhow!("feed lost")), true);
-
-        assert_eq!(
-            disposition,
-            ActorDoneDisposition::Failed {
-                error: "feed lost".to_string()
-            }
-        );
-    }
-}
-
-#[cfg(target_os = "linux")]
-pub(crate) mod linux_instant {
-    use super::*;
-    use crate::upload::strict_instant::{Control, Permission};
-    use std::sync::{
-        Mutex,
-        atomic::{AtomicBool, Ordering},
-    };
-
-    #[derive(Clone)]
-    pub struct Attempt(Arc);
-
-    struct AttemptInner {
-        lifecycle: Mutex>,
-        directory: Mutex>,
-        cancelled: AtomicBool,
-        cancel_changed: tokio::sync::watch::Sender,
-        started: tokio::sync::watch::Sender,
-        operation: tokio::sync::Mutex<()>,
-        upload: Control,
-        permission: Mutex>,
-        uploading: AtomicBool,
-        ui_ready: AtomicBool,
-        cleanup_uncertain: AtomicBool,
-        upload_result: Mutex>>,
-        terminal: Mutex>,
-    }
-
-    #[derive(Clone, Copy)]
-    enum ControlSuccess {
-        Stopped,
-        Discarded,
-    }
-
-    #[derive(Clone)]
-    struct TerminalControl {
-        kind: ControlSuccess,
-        result: Result<(), String>,
-    }
-
-    impl Attempt {
-        fn new() -> Self {
-            let (upload, permission) = Control::new();
-            let (started, _) = tokio::sync::watch::channel(false);
-            Self(Arc::new(AttemptInner {
-                lifecycle: Mutex::new(None),
-                directory: Mutex::new(None),
-                cancelled: AtomicBool::new(false),
-                cancel_changed: tokio::sync::watch::channel(false).0,
-                started,
-                operation: tokio::sync::Mutex::new(()),
-                upload,
-                ui_ready: AtomicBool::new(false),
-                cleanup_uncertain: AtomicBool::new(false),
-                upload_result: Mutex::new(None),
-                terminal: Mutex::new(None),
-                permission: Mutex::new(Some(permission)),
-                uploading: AtomicBool::new(false),
-            }))
-        }
-
-        pub(crate) fn checked(&self, result: Result) -> Result {
-            result.and_then(|value| {
-                if self.cancelled() {
-                    Err("Instant attempt cancelled; local recording retained".into())
-                } else {
-                    Ok(value)
-                }
-            })
-        }
-
-        fn terminal_result(&self, discard: bool) -> Option> {
-            let mut terminal = self.0.terminal.lock().unwrap();
-            let terminal = terminal.as_mut()?;
-            terminal.result = self.checked(terminal.result.clone());
-            Some(
-                terminal
-                    .result
-                    .clone()
-                    .and_then(|()| match (terminal.kind, discard) {
-                        (ControlSuccess::Stopped, true) => {
-                            Err("Instant recording was stopped, not discarded".into())
-                        }
-                        _ => Ok(()),
-                    }),
-            )
-        }
-
-        fn record_terminal(&self, discard: bool, result: Result<(), String>) -> Result<(), String> {
-            let result = self.checked(result);
-            let kind = if discard {
-                ControlSuccess::Discarded
-            } else {
-                ControlSuccess::Stopped
-            };
-            let mut terminal = self.0.terminal.lock().unwrap();
-            if terminal.is_none() {
-                *terminal = Some(TerminalControl { kind, result });
-            }
-            drop(terminal);
-            self.terminal_result(discard).unwrap()
-        }
-
-        pub fn control_in_progress(&self) -> bool {
-            self.0.operation.try_lock().is_err()
-        }
-        pub fn terminal_needs_cleanup(&self) -> bool {
-            if self.control_in_progress() {
-                false
-            } else {
-                self.cancel();
-                true
-            }
-        }
-
-        fn prepare_control(&self) {
-            if self.0.operation.try_lock().is_err() || !*self.0.started.borrow() {
-                self.cancel();
-            }
-        }
-
-        pub fn cancel(&self) {
-            self.0.cancelled.store(true, Ordering::Release);
-            self.0.cancel_changed.send_replace(true);
-            self.0.upload.deny();
-            if let Some(lifecycle) = self.lifecycle() {
-                lifecycle.cancel();
-            }
-        }
-
-        pub fn cancelled(&self) -> bool {
-            self.0.cancelled.load(Ordering::Acquire)
-        }
-        pub(crate) async fn while_active(
-            &self,
-            operation: impl std::future::Future>,
-        ) -> Result {
-            self.checked(Ok(()))?;
-            let mut changed = self.0.cancel_changed.subscribe();
-            tokio::select! {
-                biased;
-                _ = async {
-                    while !*changed.borrow_and_update() {
-                        if changed.changed().await.is_err() { break; }
-                    }
-                } => Err("Instant preparation cancelled".into()),
-                result = operation => self.checked(result),
-            }
-        }
-
-        pub fn upload(&self) -> Control {
-            self.0.upload.clone()
-        }
-        pub fn upload_started(&self) {
-            self.0.uploading.store(true, Ordering::Release);
-        }
-        fn lifecycle(&self) -> Option {
-            self.0.lifecycle.lock().unwrap().clone()
-        }
-        pub fn owns_directory(&self, directory: &Path) -> bool {
-            self.0.directory.lock().unwrap().as_deref() == Some(directory)
-        }
-        pub fn capture_joined(&self) -> bool {
-            self.lifecycle().is_none_or(|lifecycle| {
-                lifecycle.quiescence() == instant_recording::InstantQuiescence::Joined
-            })
-        }
-        pub fn has_capture(&self) -> bool {
-            self.lifecycle().is_some()
-        }
-        pub fn ui_ready(&self) -> bool {
-            self.0.ui_ready.load(Ordering::Acquire)
-        }
-        pub fn set_directory(&self, directory: PathBuf) {
-            *self.0.directory.lock().unwrap() = Some(directory);
-        }
-        pub(crate) fn same(&self, other: &Self) -> bool {
-            Arc::ptr_eq(&self.0, &other.0)
-        }
-
-        pub async fn attach(
-            &self,
-            directory: PathBuf,
-            lifecycle: instant_recording::InstantLifecycle,
-        ) -> Result<(), String> {
-            if let Some(previous) = self.lifecycle()
-                && previous.wait_for_quiescence().await
-                    != instant_recording::InstantQuiescence::Joined
-            {
-                lifecycle.cancel();
-                return Err("Previous Instant startup cleanup is unconfirmed".into());
-            }
-            *self.0.directory.lock().unwrap() = Some(directory);
-            *self.0.lifecycle.lock().unwrap() = Some(lifecycle.clone());
-            if self.cancelled() {
-                lifecycle.cancel();
-                return Err("Instant startup cancelled".into());
-            }
-            Ok(())
-        }
-
-        async fn capture_cleanup(&self) -> bool {
-            match self.lifecycle() {
-                Some(lifecycle) => {
-                    lifecycle.wait_for_quiescence().await
-                        == instant_recording::InstantQuiescence::Joined
-                }
-                None => true,
-            }
-        }
-
-        pub(super) async fn upload_cleanup(&self) -> bool {
-            !self.0.uploading.load(Ordering::Acquire) || self.0.upload.joined().await
-        }
-
-        async fn join_upload(&self, upload: InstantUploader) -> Result<(), String> {
-            if let Some(result) = self.0.upload_result.lock().unwrap().clone() {
-                return result;
-            }
-            let result = await_instant_upload(upload)
-                .await
-                .and_then(|result| result.map_err(|error| error.to_string()));
-            *self.0.upload_result.lock().unwrap() = Some(result.clone());
-            result
-        }
-
-        async fn wait_started(&self) -> Result<(), String> {
-            let mut started = self.0.started.subscribe();
-            loop {
-                if *started.borrow_and_update() {
-                    return Ok(());
-                }
-                started
-                    .changed()
-                    .await
-                    .map_err(|_| "Instant startup owner was lost")?;
-            }
-        }
-
-        fn authorize(&self) -> Result<(), String> {
-            if self.cancelled() {
-                return Err("Instant attempt was cancelled".into());
-            }
-            self.0
-                .permission
-                .lock()
-                .unwrap()
-                .take()
-                .ok_or("Instant completion permission was consumed")?
-                .grant()
-                .map_err(|error| error.to_string())
-        }
-    }
-
-    struct Waiter(Option);
-    impl Drop for Waiter {
-        fn drop(&mut self) {
-            if let Some(attempt) = self.0.take() {
-                attempt.cancel();
-            }
-        }
-    }
-
-    pub fn current(app: &AppHandle) -> Option {
-        app.try_state::()
-            .and_then(|state| state.instant.lock().unwrap().clone())
-    }
-
-    fn is_current(app: &AppHandle, attempt: &Attempt) -> bool {
-        current(app).is_some_and(|value| value.same(attempt))
-    }
-
-    fn release(app: &AppHandle, attempt: &Attempt) {
-        let state = app.state::();
-        let mut current = state.instant.lock().unwrap();
-        if current.as_ref().is_some_and(|value| value.same(attempt)) {
-            drop(current.take());
-        }
-    }
-
-    pub fn blocks_cleanup(app: &AppHandle) -> bool {
-        current(app).is_some_and(|attempt| !attempt.capture_joined())
-    }
-
-    pub(crate) fn validate_screen_request(
-        inputs: &StartRecordingInputs,
-        requested: &crate::RequestedInputs,
-    ) -> Result<(), String> {
-        validate_screen_camera_support(
-            inputs,
-            requested.camera.value.is_some(),
-            std::env::var_os("DISPLAY").is_some()
-                && std::env::var_os("WAYLAND_DISPLAY").is_none()
-                && std::env::var("XDG_SESSION_TYPE")
-                    .is_ok_and(|value| value.eq_ignore_ascii_case("x11")),
-        )
-    }
-
-    fn validate_screen_camera_support(
-        inputs: &StartRecordingInputs,
-        camera_requested: bool,
-        x11: bool,
-    ) -> Result<(), String> {
-        if inputs.mode != RecordingMode::Instant
-            || !camera_requested
-            || matches!(inputs.capture_target, ScreenCaptureTarget::CameraOnly)
-        {
-            return Ok(());
-        }
-        if !x11 {
-            return Err(
-                "Instant camera composition requires an X11 desktop; Wayland is not supported."
-                    .into(),
-            );
-        }
-        Ok(())
-    }
-
-    pub(crate) fn capture_rect(
-        target: &ScreenCaptureTarget,
-    ) -> Result {
-        let (display, crop) =
-            cap_recording::target_to_display_and_crop(target).map_err(|error| error.to_string())?;
-        let position = display
-            .raw_handle()
-            .physical_position()
-            .ok_or("Display physical position unavailable")?;
-        if matches!(target, ScreenCaptureTarget::Window { .. }) {
-            let crop = crop.ok_or("Capture window bounds unavailable")?;
-            return physical_window_capture_rect(
-                position.x() + crop.position().x(),
-                position.y() + crop.position().y(),
-                crop.size().width(),
-                crop.size().height(),
-            );
-        }
-        let size = display
-            .physical_size()
-            .ok_or("Display physical size unavailable")?;
-        physical_capture_rect(
-            (position.x(), position.y(), size.width(), size.height()),
-            crop.map(|crop| {
-                (
-                    crop.position().x(),
-                    crop.position().y(),
-                    crop.size().width(),
-                    crop.size().height(),
-                )
-            }),
-        )
-    }
-
-    fn physical_window_capture_rect(
-        x: f64,
-        y: f64,
-        width: f64,
-        height: f64,
-    ) -> Result {
-        let coordinates = f64::from(i32::MIN)..=f64::from(i32::MAX);
-        let dimensions = 2.0..=f64::from(i32::MAX);
-        if ![x, y, width, height]
-            .iter()
-            .all(|value| value.is_finite() && value.fract() == 0.0)
-            || !coordinates.contains(&x)
-            || !coordinates.contains(&y)
-            || !dimensions.contains(&width)
-            || !dimensions.contains(&height)
-        {
-            return Err("Capture window has invalid physical bounds".into());
-        }
-        Ok(crate::linux_instant_camera::PhysicalRect {
-            x: x as i32,
-            y: y as i32,
-            width: width as u32,
-            height: height as u32,
-        })
-    }
-
-    fn physical_capture_rect(
-        display: (f64, f64, f64, f64),
-        crop: Option<(f64, f64, f64, f64)>,
-    ) -> Result {
-        let (x, y, width, height) = cap_recording::sources::screen_capture::x11_capture_rect(
-            display.0, display.1, display.2, display.3, crop,
-        )
-        .map_err(|error| error.to_string())?;
-        Ok(crate::linux_instant_camera::PhysicalRect {
-            x,
-            y,
-            width,
-            height,
-        })
-    }
-
-    pub(crate) struct PreparedScreenCamera {
-        pub source: instant_recording::LinuxProcessedCameraSource,
-        pub presentation: instant_recording::LinuxCameraPresentation,
-        pub reference_size: (u32, u32),
-    }
-
-    pub(crate) fn configure_screen_camera(
-        builder: instant_recording::ActorBuilder,
-        target: &ScreenCaptureTarget,
-        camera_requested: bool,
-        prepared: Option,
-    ) -> Result {
-        if let Some(prepared) = prepared {
-            if !camera_requested || matches!(target, ScreenCaptureTarget::CameraOnly) {
-                return Err("Unexpected Instant screen camera preparation".into());
-            }
-            Ok(builder.with_linux_processed_camera(
-                prepared.source,
-                prepared.presentation,
-                prepared.reference_size,
-            ))
-        } else if camera_requested && !matches!(target, ScreenCaptureTarget::CameraOnly) {
-            Err(
-                "Requested Instant screen camera was not prepared; no raw fallback is allowed"
-                    .into(),
-            )
-        } else {
-            Ok(builder)
-        }
-    }
-
-    pub(crate) async fn prepare_screen_camera(
-        app: &AppHandle,
-        attempt: &Attempt,
-        generation: u32,
-        inputs: &StartRecordingInputs,
-        requested: &crate::RequestedInputs,
-        camera: Option>,
-    ) -> Result, String> {
-        validate_screen_request(inputs, requested)?;
-        if camera.is_some() != requested.camera.value.is_some() {
-            return Err("Requested camera lock is missing or unexpected".into());
-        }
-        let capture = capture_rect(&inputs.capture_target)?;
-        let prepared = if let Some(camera) = camera {
-            let presentation = attempt
-                .while_active(crate::linux_instant_camera::request_presentation(
-                    app, generation, capture,
-                ))
-                .await?;
-            let state = app.state::>();
-            let factory = state.read().await.camera_processing.clone();
-            let source = attempt
-                .while_active(async {
-                    factory
-                        .subscribe(camera, &presentation)
-                        .await
-                        .map_err(|error| error.to_string())
-                })
-                .await?;
-            Some((presentation, source))
-        } else {
-            None
-        };
-        let (presentation, source) = match prepared {
-            Some((presentation, source)) => (Some(presentation), Some(source)),
-            None => (None, None),
-        };
-        let seal = crate::clean_capture::seal_instant(
-            app,
-            crate::clean_capture::InstantSeal {
-                generation,
-                attempt: attempt.clone(),
-                requested: requested.clone(),
-                target: inputs.capture_target.clone(),
-                capture,
-                presentation,
-            },
-        )
-        .await?;
-        match (seal.presentation, source) {
-            (Some(presentation), Some(source)) => Ok(Some(PreparedScreenCamera {
-                source,
-                presentation: presentation.presentation,
-                reference_size: presentation.reference_size,
-            })),
-            (None, None) => Ok(None),
-            _ => Err("Instant prepared camera ownership was lost".into()),
-        }
-    }
-
-    pub fn validate_inputs(inputs: &StartRecordingInputs) -> Result<(), String> {
-        if inputs.mode == RecordingMode::Instant
-            && matches!(inputs.capture_target, ScreenCaptureTarget::CameraOnly)
-            && inputs.capture_system_audio
-        {
-            Err("System audio is not supported for Linux Instant CameraOnly. Disable it before recording.".into())
-        } else {
-            Ok(())
-        }
-    }
-
-    pub async fn start(
-        app: AppHandle,
-        state: MutableState<'_, App>,
-        inputs: StartRecordingInputs,
-    ) -> Result {
-        validate_inputs(&inputs)?;
-        let attempt = Attempt::new();
-        {
-            let app_state = state.write().await;
-            if !matches!(app_state.recording_state, RecordingState::None) {
-                return Err("Recording already in progress".into());
-            }
-            let state = app.state::();
-            let mut slot = state.instant.lock().unwrap();
-            if slot.is_some() {
-                return Err("Finish the previous Instant attempt before recording".into());
-            }
-            *slot = Some(attempt.clone());
-        }
-        let work_attempt = attempt.clone();
-        let abandoned_attempt = attempt.clone();
-        let abandoned_app = app.clone();
-        owned_reply(
-            attempt,
-            async move {
-                let attempt = work_attempt;
-                let state = app.state::>();
-                let result =
-                    AssertUnwindSafe(start_recording_inner(app.clone(), state.clone(), inputs))
-                        .catch_unwind()
-                        .await
-                        .unwrap_or_else(|panic| {
-                            Err(format!(
-                                "Instant startup panicked: {}",
-                                panic_message(panic)
-                            ))
-                        });
-                let started =
-                    matches!(result, Ok(RecordingAction::Started)) && !attempt.cancelled();
-                if !started {
-                    attempt.cancel();
-                    let joined = attempt.capture_cleanup().await;
-                    let upload_joined = attempt.upload_cleanup().await;
-                    if joined && upload_joined && is_current(&app, &attempt) {
-                        let upload = {
-                            let state = state.read().await;
-                            match state.current_recording() {
-                                Some(InProgressRecording::Instant { segment_upload, .. }) => {
-                                    Some(segment_upload.clone())
-                                }
-                                _ => None,
-                            }
-                        };
-                        if let Some(upload) = upload {
-                            let _ = attempt.join_upload(upload).await;
-                        }
-                        attempt.0.ui_ready.store(true, Ordering::Release);
-                        let directory = attempt.0.directory.lock().unwrap().clone();
-                        if let Some(directory) = directory {
-                            let mut state = state.write().await;
-                            let _ = handle_recording_end(
-                                app.clone(),
-                                Err("Instant startup failed or was cancelled".into()),
-                                &mut state,
-                                directory,
-                            )
-                            .await;
-                        } else {
-                            state.write().await.clear_pending_recording();
-                        }
-                        let terminal = result.as_ref().err().cloned().unwrap_or_else(|| {
-                            "Instant startup did not establish a recording".into()
-                        });
-                        let _ = attempt.record_terminal(false, Err(terminal));
-                        release(&app, &attempt);
-                    }
-                }
-                attempt.0.started.send_replace(true);
-                match result {
-                    Ok(RecordingAction::Started) if !started => {
-                        Err("Instant startup cancelled".into())
-                    }
-                    result => result,
-                }
-            },
-            async move {
-                let _ = execute(abandoned_app, abandoned_attempt, false).await;
-            },
-        )
-        .await
-    }
-
-    pub fn control(
-        app: AppHandle,
-        attempt: Attempt,
-        discard: bool,
-    ) -> futures::future::BoxFuture<'static, Result<(), String>> {
-        Box::pin(async move {
-            attempt.prepare_control();
-            let worker = attempt.clone();
-            owned_reply(
-                attempt,
-                async move {
-                    let result = execute(app.clone(), worker.clone(), discard).await;
-                    let result = storage_preflight_control_result(result, worker.has_capture());
-                    if let Err(error) = &result {
-                        let _ = RecordingEvent::Failed {
-                            error: error.clone(),
-                        }
-                        .emit(&app);
-                    }
-                    result
-                },
-                async {},
-            )
-            .await
-        })
-    }
-
-    async fn owned_reply(attempt: Attempt, work: F, abandoned: A) -> Result
-    where
-        T: Send + 'static,
-        F: std::future::Future> + Send + 'static,
-        A: std::future::Future + Send + 'static,
-    {
-        let mut waiter = Waiter(Some(attempt.clone()));
-        let (reply, result) = tokio::sync::oneshot::channel();
-        drop(tauri::async_runtime::spawn(async move {
-            let result = match AssertUnwindSafe(work).catch_unwind().await {
-                Ok(result) => result,
-                Err(panic) => {
-                    attempt.0.cleanup_uncertain.store(true, Ordering::Release);
-                    attempt.cancel();
-                    attempt.0.started.send_replace(true);
-                    let _ = attempt.upload_cleanup().await;
-                    Err(format!(
-                        "Instant owned work panicked; cleanup is unconfirmed: {}",
-                        panic_message(panic)
-                    ))
-                }
-            };
-            if result.is_err() {
-                attempt.cancel();
-            }
-            if reply.send(result).is_err() {
-                attempt.cancel();
-                abandoned.await;
-            }
-        }));
-        let result = result
-            .await
-            .map_err(|_| "Instant cleanup owner was lost".to_string())?;
-        drop(waiter.0.take());
-        result
-    }
-
-    async fn run_control(
-        attempt: &Attempt,
-        discard: bool,
-        current: impl FnOnce() -> bool,
-        work: W,
-    ) -> Result<(), String>
-    where
-        F: std::future::Future>,
-        W: FnOnce() -> F,
-    {
-        attempt.wait_started().await?;
-        let _operation = attempt.0.operation.lock().await;
-        if let Some(result) = attempt.terminal_result(discard) {
-            return result;
-        }
-        if !current() {
-            return Err("Instant attempt was superseded without a terminal result".into());
-        }
-        work().await
-    }
-
-    async fn complete_local(
-        attempt: &Attempt,
-        outcome: Result,
-        acquire: L,
-        finish: W,
-    ) -> Result<(), String>
-    where
-        L: std::future::Future,
-        F: std::future::Future>,
-        W: FnOnce(G, Result) -> F,
-    {
-        let guard = acquire.await;
-        let outcome = attempt.checked(outcome);
-        let failure = outcome.as_ref().err().cloned();
-        let cleanup = finish(guard, outcome).await;
-        attempt.checked(failure.map_or(cleanup, Err))
-    }
-
-    async fn execute(app: AppHandle, attempt: Attempt, discard: bool) -> Result<(), String> {
-        run_control(
-            &attempt,
-            discard,
-            || is_current(&app, &attempt),
-            || execute_current(app.clone(), attempt.clone(), discard),
-        )
-        .await
-    }
-
-    async fn execute_current(
-        app: AppHandle,
-        attempt: Attempt,
-        discard: bool,
-    ) -> Result<(), String> {
-        if attempt.0.cleanup_uncertain.load(Ordering::Acquire) {
-            attempt.cancel();
-            return Err("Instant finalization cleanup is unconfirmed; local recording and Stop ownership retained".into());
-        }
-        let state = app.state::>();
-        let (handle, directory, segment_upload, video_upload_info, target_name) = {
-            let state = state.read().await;
-            match state.current_recording() {
-                Some(InProgressRecording::Instant {
-                    handle,
-                    common,
-                    segment_upload,
-                    video_upload_info,
-                    ..
-                }) if attempt.owns_directory(&common.recording_dir) => (
-                    handle.clone(),
-                    common.recording_dir.clone(),
-                    segment_upload.clone(),
-                    video_upload_info.clone(),
-                    common.target_name.clone(),
-                ),
-                _ => return Err("Instant recording is unavailable; cleanup state retained".into()),
-            }
-        };
-        if discard {
-            attempt.upload().deny();
-        }
-        let stopped = if discard || attempt.cancelled() {
-            handle.cancel().await.map(|()| None)
-        } else {
-            handle.stop().await.map(Some)
-        };
-        if stopped.is_err() {
-            attempt.cancel();
-        }
-        if !attempt.capture_cleanup().await {
-            return Err("Instant capture cleanup is unconfirmed. Local recording retained; use Stop to retry.".into());
-        }
-        let video_id = video_upload_info.id.clone();
-        let share_info = video_upload_info.clone();
-        let result = match stopped {
-            Ok(Some(recording)) if !attempt.cancelled() => {
-                let mut completed = CompletedRecording::Instant {
-                    recording,
-                    segment_upload: segment_upload.clone(),
-                    video_upload_info,
-                    target_name,
-                    finalized: false,
-                };
-                match finalize(&attempt, &mut completed).await {
-                    Ok(()) => Ok(Some(completed)),
-                    Err(error) => {
-                        attempt.cancel();
-                        let _ = attempt.upload_cleanup().await;
-                        Err(error)
-                    }
-                }
-            }
-            result => {
-                attempt.upload().deny();
-                if !attempt.upload_cleanup().await {
-                    return Err(
-                        "Instant upload reader cleanup is unconfirmed; local recording retained"
-                            .into(),
-                    );
-                }
-                match result {
-                    Ok(None) if discard && !attempt.cancelled() => Ok(None),
-                    Ok(_) => {
-                        Err("Instant recording was cancelled; local recording retained".into())
-                    }
-                    Err(error) => Err(error.to_string()),
-                }
-            }
-        };
-        if !matches!(result, Ok(Some(_))) {
-            if !attempt.upload_cleanup().await {
-                return Err(
-                    "Instant upload cleanup is unconfirmed; local recording retained".into(),
-                );
-            }
-            let _ = attempt.join_upload(segment_upload.clone()).await;
-        }
-        let successful_discard = matches!(result, Ok(None));
-        let successful_upload = matches!(result, Ok(Some(_)));
-        let finish_app = app.clone();
-        let finish_attempt = attempt.clone();
-        let finish_directory = directory.clone();
-        let mut result = complete_local(
-            &attempt,
-            result,
-            state.write(),
-            move |mut state, result| async move {
-                if !is_current(&finish_app, &finish_attempt)
-                    || state
-                        .current_recording()
-                        .is_none_or(|recording| recording.recording_dir() != &finish_directory)
-                {
-                    return Err("Instant completion no longer owns the recording".into());
-                }
-                let outcome = match result {
-                    Ok(Some(completed)) => Ok(completed),
-                    Ok(None) => Err("Recording discarded".into()),
-                    Err(error) => Err(error),
-                };
-                finish_attempt.0.ui_ready.store(true, Ordering::Release);
-                handle_recording_end(finish_app, outcome, &mut state, finish_directory).await
-            },
-        )
-        .await;
-        if result.is_ok() && successful_upload {
-            let session = segment_upload.lock().await.session.clone();
-            result = session.mark_ready(false).map_err(|error| error.to_string());
-            if result.is_ok() {
-                let network_attempt = attempt.clone();
-                let network_app = app.clone();
-                let network_video = share_info.clone();
-                let network_session = session.clone();
-                result = crate::upload::lifecycle::supervise(app.clone(), session, async move {
-                    let authorized = network_attempt.authorize();
-                    let uploaded = network_attempt.join_upload(segment_upload).await;
-                    let joined = network_attempt.upload_cleanup().await;
-                    authorized.map_err(AuthedApiError::from)?;
-                    uploaded.map_err(AuthedApiError::from)?;
-                    if !joined {
-                        return Err("Instant upload cleanup is unconfirmed".into());
-                    }
-                    let bytes =
-                        compress_image(network_session.directory.join("screenshots/display.jpg"))
-                            .await?;
-                    crate::upload::strict_instant::upload_thumbnail(
-                        &network_app,
-                        &network_video.id,
-                        bytes,
-                        &network_attempt.upload(),
-                    )
-                    .await?;
-                    network_session.complete_locally(&network_app).await?;
-                    crate::automation::run_upload_completed_automations(
-                        network_app,
-                        network_session.directory.clone(),
-                        Some(network_video.link),
-                        Some(network_video.id),
-                    );
-                    Ok(())
-                })
-                .await
-                .map_err(|error| error.to_string());
-            }
-            if result.is_ok() {
-                result = successful_effects(&app, &attempt, &directory, &share_info);
-            }
-        }
-        result = attempt.checked(result);
-        if result.is_ok() && successful_discard {
-            result = delete_remote_instant_video(&app, &video_id).await;
-            result = attempt.checked(result);
-            if result.is_ok() {
-                result = crate::upload::lifecycle::mark_cancelled(&directory)
-                    .map_err(|error| error.to_string());
-            }
-            if result.is_ok() {
-                result = remove_owned_directory(directory.clone(), attempt.clone(), false).await;
-                result = attempt.checked(result);
-            }
-        }
-        result = attempt.checked(result);
-        if let Err(error) = &result {
-            attempt.cancel();
-            persist_terminal_failure(&directory, error).await;
-        }
-        let result = attempt.record_terminal(discard, result);
-        release(&app, &attempt);
-        attempt.terminal_result(discard).unwrap_or(result)
-    }
-
-    async fn persist_terminal_failure(directory: &Path, error: &str) {
-        let directory = directory.to_path_buf();
-        let failure = error.to_string();
-        let result = tokio::task::spawn_blocking(move || -> Result<(), String> {
-            let mut meta =
-                RecordingMeta::load_for_project(&directory).map_err(|error| error.to_string())?;
-            meta.inner =
-                RecordingMetaInner::Instant(InstantRecordingMeta::Failed { error: failure });
-            meta.save_for_project().map_err(|error| error.to_string())
-        })
-        .await;
-        if !matches!(&result, Ok(Ok(()))) {
-            error!(
-                ?result,
-                "Failed to persist Instant terminal error; local recording retained"
-            );
-        }
-    }
-
-    struct SuccessEffects {
-        recording_automation: R,
-        upload_automation: U,
-        open_link: O,
-        copy_link: C,
-        sound: S,
-    }
-
-    fn dispatch_success_effects(
-        attempt: &Attempt,
-        share_link: &str,
-        effects: SuccessEffects,
-    ) -> Result<(), String>
-    where
-        R: FnOnce(),
-        U: FnOnce(),
-        O: FnOnce(String) -> Result<(), String>,
-        C: FnOnce(String) -> Result<(), String>,
-        S: FnOnce(),
-    {
-        attempt.checked(Ok(()))?;
-        (effects.recording_automation)();
-        attempt.checked(Ok(()))?;
-        (effects.upload_automation)();
-        attempt.checked(Ok(()))?;
-        (effects.open_link)(recording_stopped_share_url(share_link))?;
-        attempt.checked(Ok(()))?;
-        let _ = (effects.copy_link)(share_link.to_string());
-        attempt.checked(Ok(()))?;
-        (effects.sound)();
-        attempt.checked(Ok(()))
-    }
-
-    fn successful_effects(
-        app: &AppHandle,
-        attempt: &Attempt,
-        directory: &Path,
-        video: &VideoUploadInfo,
-    ) -> Result<(), String> {
-        use tauri_plugin_clipboard_manager::ClipboardExt;
-        dispatch_success_effects(
-            attempt,
-            &video.link,
-            SuccessEffects {
-                recording_automation: || {
-                    crate::automation::run_instant_recording_automations(
-                        app.clone(),
-                        directory.to_path_buf(),
-                        Some(video.link.clone()),
-                        Some(video.id.clone()),
-                    )
-                },
-                upload_automation: || {},
-                open_link: |link| open_external_link(app.clone(), link),
-                copy_link: |link| {
-                    app.clipboard()
-                        .write_text(link)
-                        .map_err(|error| error.to_string())
-                },
-                sound: || AppSounds::StopRecording.play(),
-            },
-        )
-    }
-
-    async fn remove_owned_directory(
-        directory: PathBuf,
-        attempt: Attempt,
-        uploaded: bool,
-    ) -> Result<(), String> {
-        if attempt.cancelled() {
-            return Err("Instant cleanup cancelled; local recording retained".into());
-        }
-        let worker = attempt.clone();
-        tokio::task::spawn_blocking(move || {
-            if worker.cancelled() {
-                return Err("Instant cleanup cancelled before deletion".to_string());
-            }
-            if uploaded {
-                worker.upload().check().map_err(|error| error.to_string())?;
-            }
-            std::fs::remove_dir_all(directory).map_err(|error| error.to_string())
-        })
-        .await
-        .map_err(|error| error.to_string())??;
-        if attempt.cancelled() {
-            return Err("Instant cleanup cancelled during deletion".into());
-        }
-        Ok(())
-    }
-
-    pub fn persist_upload_start(
-        directory: &Path,
-        video: &VideoUploadInfo,
-        segmented: bool,
-    ) -> Result<(), String> {
-        let mut meta =
-            RecordingMeta::load_for_project(directory).map_err(|error| error.to_string())?;
-        meta.upload = Some(if segmented {
-            cap_project::UploadMeta::SegmentUpload {
-                video_id: video.id.clone(),
-                pre_created_video: video.clone(),
-                recording_dir: directory.into(),
-            }
-        } else {
-            cap_project::UploadMeta::MultipartUpload {
-                video_id: video.id.clone(),
-                pre_created_video: video.clone(),
-                recording_dir: directory.into(),
-                file_path: directory.join("content/output.mp4"),
-            }
-        });
-        meta.save_for_project().map_err(|error| error.to_string())
-    }
-
-    async fn finalize(attempt: &Attempt, completed: &mut CompletedRecording) -> Result<(), String> {
-        let CompletedRecording::Instant {
-            recording,
-            segment_upload: _,
-            video_upload_info,
-            finalized,
-            ..
-        } = completed
-        else {
-            unreachable!()
-        };
-        if !recording.health.is_uploadable() {
-            return Err("Instant recording output is damaged".into());
-        }
-        let directory = &recording.project_path;
-        let screenshots = directory.join("screenshots");
-        std::fs::create_dir_all(&screenshots).map_err(|error| error.to_string())?;
-        let screenshot = screenshots.join("display.jpg");
-        let source = if matches!(recording.display_source, ScreenCaptureTarget::CameraOnly) {
-            directory.join("content/output.mp4")
-        } else {
-            create_screenshot_source_from_segments(&directory.join("content/display")).await?
-        };
-        create_screenshot(source, screenshot.clone(), None).await?;
-        let mut meta =
-            RecordingMeta::load_for_project(directory).map_err(|error| error.to_string())?;
-        attempt.checked(Ok(()))?;
-        meta.sharing = Some(SharingMeta {
-            link: video_upload_info.link.clone(),
-            id: video_upload_info.id.clone(),
-            content_hash: None,
-        });
-        meta.inner = RecordingMetaInner::Instant(recording.meta.clone());
-        meta.save_for_project().map_err(|error| error.to_string())?;
-        attempt.checked(Ok(()))?;
-        *finalized = true;
-        Ok(())
-    }
-
-    #[cfg(test)]
-    mod tests {
-        use super::*;
-        #[tokio::test]
-        async fn preflight_cancel_before_f9_unblocks_start_and_stop_only_after_owned_cleanup() {
-            for discard in [false, true] {
-                let state = Arc::new(crate::clean_capture::instant_preflight_fixture(7));
-                let attempt = Attempt::new();
-                let starter = attempt.clone();
-                let waiting = state.clone();
-                let (polled_tx, polled_rx) = tokio::sync::oneshot::channel();
-                let (cancelled_tx, cancelled_rx) = tokio::sync::oneshot::channel();
-                let (cleanup_tx, cleanup_rx) = tokio::sync::oneshot::channel();
-                let startup = tokio::spawn(async move {
-                    polled_tx.send(()).unwrap();
-                    let error = crate::clean_capture::await_instant_shortcut(&waiting, 7, &starter)
-                        .await
-                        .unwrap_err();
-                    cancelled_tx.send(()).unwrap();
-                    cleanup_rx.await.unwrap();
-                    assert!(starter.capture_cleanup().await);
-                    assert!(starter.upload_cleanup().await);
-                    let result = starter.record_terminal(false, Err(error));
-                    starter.0.started.send_replace(true);
-                    result
-                });
-                polled_rx.await.unwrap();
-                attempt.prepare_control();
-                let controller = attempt.clone();
-                let stop = tokio::spawn(async move {
-                    run_control(
-                        &controller,
-                        discard,
-                        || true,
-                        || async { panic!("cancelled preflight has no active actor to finalize") },
-                    )
-                    .await
-                });
-                tokio::time::timeout(std::time::Duration::from_secs(2), cancelled_rx)
-                    .await
-                    .expect("Cancel must wake preflight without F9")
-                    .unwrap();
-                assert!(!stop.is_finished());
-                assert!(!*attempt.0.started.borrow());
-                assert!(!attempt.ui_ready());
-                cleanup_tx.send(()).unwrap();
-                let startup_error = startup.await.unwrap().unwrap_err();
-                assert_eq!(stop.await.unwrap().unwrap_err(), startup_error);
-                assert!(attempt.upload().check().is_err());
-            }
-        }
-
-        #[tokio::test]
-        async fn preflight_cancelled_before_wait_poll_does_not_need_state_notification() {
-            let state = crate::clean_capture::instant_preflight_fixture(7);
-            let attempt = Attempt::new();
-            attempt.cancel();
-            assert!(
-                tokio::time::timeout(
-                    std::time::Duration::from_secs(2),
-                    crate::clean_capture::await_instant_shortcut(&state, 7, &attempt),
-                )
-                .await
-                .expect("pre-cancelled wait must return")
-                .is_err()
-            );
-        }
-
-        #[tokio::test]
-        async fn preflight_command_waiter_drop_wakes_shortcut_wait_without_aborting_cleanup() {
-            let state = Arc::new(crate::clean_capture::instant_preflight_fixture(7));
-            let attempt = Attempt::new();
-            let waiter = Waiter(Some(attempt.clone()));
-            let owner = attempt.clone();
-            let (polled_tx, polled_rx) = tokio::sync::oneshot::channel();
-            let task = tokio::spawn(async move {
-                polled_tx.send(()).unwrap();
-                crate::clean_capture::await_instant_shortcut(&state, 7, &owner).await
-            });
-            polled_rx.await.unwrap();
-            drop(waiter);
-            assert!(
-                tokio::time::timeout(std::time::Duration::from_secs(2), task)
-                    .await
-                    .expect("dropped command must wake preflight")
-                    .unwrap()
-                    .is_err()
-            );
-            assert!(attempt.capture_cleanup().await);
-            assert!(attempt.upload_cleanup().await);
-            assert!(attempt.authorize().is_err());
-        }
-
-        #[tokio::test]
-        async fn preflight_cancel_wins_when_f9_and_cancel_are_ready_together() {
-            let state = Arc::new(crate::clean_capture::instant_preflight_fixture(7));
-            let attempt = Attempt::new();
-            let owner = attempt.clone();
-            let waiting = state.clone();
-            let (polled_tx, polled_rx) = tokio::sync::oneshot::channel();
-            let task = tokio::spawn(async move {
-                polled_tx.send(()).unwrap();
-                crate::clean_capture::await_instant_shortcut(&waiting, 7, &owner).await
-            });
-            polled_rx.await.unwrap();
-            crate::clean_capture::deliver_preflight_shortcut(&state);
-            attempt.cancel();
-            assert!(task.await.unwrap().is_err());
-        }
-
-        #[tokio::test]
-        async fn preflight_actual_shortcut_wait_preserves_success_and_rejects_wrong_generation() {
-            let state = Arc::new(crate::clean_capture::instant_preflight_fixture(7));
-            assert!(
-                crate::clean_capture::wait_for_shortcut(&state, 8)
-                    .await
-                    .is_err()
-            );
-            let waiting = state.clone();
-            let task =
-                tokio::spawn(
-                    async move { crate::clean_capture::wait_for_shortcut(&waiting, 7).await },
-                );
-            crate::clean_capture::deliver_preflight_shortcut(&state);
-            task.await.unwrap().unwrap();
-        }
-
-        #[test]
-        fn instant_window_capture_reference_preserves_exact_size_and_origin() {
-            assert_eq!(
-                physical_window_capture_rect(-40.0, 31.0, 1281.0, 721.0).unwrap(),
-                crate::linux_instant_camera::PhysicalRect {
-                    x: -40,
-                    y: 31,
-                    width: 1281,
-                    height: 721,
-                }
-            );
-            assert_eq!(
-                physical_window_capture_rect(-1921.0, -1081.0, 1919.0, 1079.0).unwrap(),
-                crate::linux_instant_camera::PhysicalRect {
-                    x: -1921,
-                    y: -1081,
-                    width: 1919,
-                    height: 1079,
-                }
-            );
-        }
-
-        #[test]
-        fn instant_window_capture_reference_rejects_invalid_geometry() {
-            for value in [
-                f64::NAN,
-                f64::INFINITY,
-                0.0,
-                1.0,
-                400.5,
-                f64::from(u32::MAX),
-            ] {
-                assert!(physical_window_capture_rect(0.0, 0.0, value, 720.0).is_err());
-                assert!(physical_window_capture_rect(0.0, 0.0, 1280.0, value).is_err());
-            }
-            for value in [
-                f64::NAN,
-                f64::NEG_INFINITY,
-                -0.5,
-                f64::from(i32::MIN) - 1.0,
-                f64::from(i32::MAX) + 1.0,
-            ] {
-                assert!(physical_window_capture_rect(value, 0.0, 1280.0, 720.0).is_err());
-                assert!(physical_window_capture_rect(0.0, value, 1280.0, 720.0).is_err());
-            }
-        }
-
-        #[test]
-        fn instant_physical_capture_reference_matches_negative_origin_fractional_crop_and_even_rounding()
-         {
-            assert_eq!(
-                physical_capture_rect(
-                    (-1920.0, 0.0, 1920.0, 1080.0),
-                    Some((10.25, 20.75, 301.25, 199.5))
-                )
-                .unwrap(),
-                crate::linux_instant_camera::PhysicalRect {
-                    x: -1910,
-                    y: 20,
-                    width: 302,
-                    height: 200
-                },
-            );
-            assert_eq!(
-                physical_capture_rect((0.0, -1080.0, 1919.0, 1079.0), None).unwrap(),
-                crate::linux_instant_camera::PhysicalRect {
-                    x: 0,
-                    y: -1080,
-                    width: 1918,
-                    height: 1078
-                },
-            );
-        }
-
-        #[test]
-        fn instant_physical_capture_reference_clamps_and_rejects_invalid_geometry() {
-            assert_eq!(
-                physical_capture_rect(
-                    (0.0, 0.0, 1920.0, 1080.0),
-                    Some((-50.0, -10.0, 3000.0, 2000.0))
-                )
-                .unwrap(),
-                crate::linux_instant_camera::PhysicalRect {
-                    x: 0,
-                    y: 0,
-                    width: 1920,
-                    height: 1080
-                },
-            );
-            assert!(physical_capture_rect((f64::NAN, 0.0, 1920.0, 1080.0), None).is_err());
-        }
-
-        struct PreparationLease(std::sync::Arc);
-        impl Drop for PreparationLease {
-            fn drop(&mut self) {
-                self.0.store(true, Ordering::SeqCst);
-            }
-        }
-
-        #[tokio::test]
-        async fn instant_preparation_cancel_wakes_pending_first_frame_and_drops_source_reservation()
-        {
-            let attempt = Attempt::new();
-            let dropped = Arc::new(AtomicBool::new(false));
-            let source = PreparationLease(dropped.clone());
-            let owner = attempt.clone();
-            let (tx, rx) = tokio::sync::oneshot::channel();
-            let task = tokio::spawn(async move {
-                owner
-                    .while_active(async move {
-                        let _source = source;
-                        tx.send(()).unwrap();
-                        std::future::pending::>().await
-                    })
-                    .await
-            });
-            rx.await.unwrap();
-            attempt.cancel();
-            assert!(task.await.unwrap().is_err());
-            assert!(dropped.load(Ordering::SeqCst));
-            assert!(!attempt.has_capture());
-            assert!(attempt.upload().check().is_err());
-        }
-
-        #[tokio::test]
-        async fn instant_preparation_cancel_before_poll_never_requests_or_hides_preview() {
-            let attempt = Attempt::new();
-            attempt.cancel();
-            let result: Result<(), String> = attempt
-                .while_active(async {
-                    panic!("cancelled preparation must not contact the preview or hide windows")
-                })
-                .await;
-            assert!(result.is_err());
-        }
-
-        #[tokio::test]
-        async fn instant_preparation_rechecks_cancel_after_first_frame_arrives() {
-            let attempt = Attempt::new();
-            let owner = attempt.clone();
-            let result = attempt
-                .while_active(async move {
-                    owner.cancel();
-                    Ok(7)
-                })
-                .await;
-            assert!(result.is_err());
-        }
-
-        #[tokio::test]
-        async fn instant_preparation_preserves_fresh_source_and_failure_identity() {
-            let attempt = Attempt::new();
-            assert_eq!(attempt.while_active(async { Ok(7) }).await.unwrap(), 7);
-            let result: Result<(), String> = attempt
-                .while_active(async { Err("first mask unavailable".into()) })
-                .await;
-            assert_eq!(result.unwrap_err(), "first mask unavailable");
-            assert!(!attempt.cancelled());
-        }
-
-        #[tokio::test]
-        async fn instant_builder_rejects_unprepared_screen_camera_and_joins_unused_attempt() {
-            let target = ScreenCaptureTarget::Window {
-                id: "1".parse().unwrap(),
-            };
-            let builder = instant_recording::Actor::builder(
-                PathBuf::from("unused-activation-test"),
-                target.clone(),
-            );
-            let lifecycle = builder.lifecycle();
-            assert!(configure_screen_camera(builder, &target, true, None).is_err());
-            assert_eq!(
-                lifecycle.wait_for_quiescence().await,
-                instant_recording::InstantQuiescence::Joined
-            );
-        }
-
-        #[tokio::test]
-        async fn instant_builder_preserves_camera_only_and_unselected_camera_paths() {
-            for (target, requested) in [
-                (ScreenCaptureTarget::CameraOnly, true),
-                (
-                    ScreenCaptureTarget::Window {
-                        id: "1".parse().unwrap(),
-                    },
-                    false,
-                ),
-            ] {
-                let builder = instant_recording::Actor::builder(
-                    PathBuf::from("unused-activation-test"),
-                    target.clone(),
-                );
-                let lifecycle = builder.lifecycle();
-                drop(configure_screen_camera(builder, &target, requested, None).unwrap());
-                assert_eq!(
-                    lifecycle.wait_for_quiescence().await,
-                    instant_recording::InstantQuiescence::Joined
-                );
-            }
-        }
-
-        #[test]
-        fn instant_screen_camera_support_allows_x11_window_and_preserves_wayland_rejection() {
-            let mut inputs = StartRecordingInputs {
-                capture_target: ScreenCaptureTarget::Window {
-                    id: "1".parse().unwrap(),
-                },
-                capture_system_audio: false,
-                mode: RecordingMode::Instant,
-                organization_id: None,
-            };
-            assert!(validate_screen_camera_support(&inputs, true, true).is_ok());
-            assert!(validate_screen_camera_support(&inputs, true, false).is_err());
-            assert!(validate_screen_camera_support(&inputs, false, false).is_ok());
-            inputs.capture_target = ScreenCaptureTarget::Display {
-                id: "1".parse().unwrap(),
-            };
-            assert!(validate_screen_camera_support(&inputs, true, true).is_ok());
-            assert!(validate_screen_camera_support(&inputs, true, false).is_err());
-            inputs.mode = RecordingMode::Studio;
-            assert!(validate_screen_camera_support(&inputs, true, false).is_ok());
-            inputs.mode = RecordingMode::Instant;
-            inputs.capture_target = ScreenCaptureTarget::CameraOnly;
-            assert!(validate_screen_camera_support(&inputs, true, false).is_ok());
-        }
-
-        #[tokio::test]
-        async fn owned_waiter_drop_cancels_without_aborting_cleanup() {
-            let attempt = Attempt::new();
-            let (release, released) = tokio::sync::oneshot::channel();
-            let (finished, finished_rx) = tokio::sync::oneshot::channel();
-            let cleaned = Arc::new(AtomicBool::new(false));
-            let worker_cleaned = cleaned.clone();
-            let mut waiter = Box::pin(owned_reply(
-                attempt.clone(),
-                async move {
-                    released.await.unwrap();
-                    worker_cleaned.store(true, Ordering::Release);
-                    Ok(())
-                },
-                async move {
-                    finished.send(()).unwrap();
-                },
-            ));
-            assert!(
-                tokio::time::timeout(Duration::from_millis(10), &mut waiter)
-                    .await
-                    .is_err()
-            );
-            drop(waiter);
-            assert!(attempt.cancelled());
-            assert!(!cleaned.load(Ordering::Acquire));
-            release.send(()).unwrap();
-            tokio::time::timeout(Duration::from_secs(1), finished_rx)
-                .await
-                .unwrap()
-                .unwrap();
-            assert!(cleaned.load(Ordering::Acquire));
-        }
-        #[tokio::test]
-        async fn owned_work_failure_returns_error_without_success_or_permission() {
-            let attempt = Attempt::new();
-            let result: Result<(), _> = owned_reply(
-                attempt.clone(),
-                async { Err("required output failed".into()) },
-                async {},
-            )
-            .await;
-            assert!(result.is_err());
-            assert!(!attempt.ui_ready());
-            attempt.cancel();
-            assert!(attempt.authorize().is_err());
-        }
-        #[tokio::test]
-        async fn owned_work_panic_retains_unconfirmed_cleanup() {
-            let attempt = Attempt::new();
-            let result: Result<(), _> = owned_reply(
-                attempt.clone(),
-                async { panic!("failed finalization owner") },
-                async {},
-            )
-            .await;
-            assert!(result.unwrap_err().contains("unconfirmed"));
-            assert!(attempt.0.cleanup_uncertain.load(Ordering::Acquire));
-            assert!(attempt.cancelled());
-            assert!(!attempt.ui_ready());
-        }
-        #[tokio::test]
-        async fn cancel_before_builder_poll_joins_unused_core_lifecycle() {
-            let attempt = Attempt::new();
-            let builder = instant_recording::Actor::builder(
-                PathBuf::from("unused-synthetic.cap"),
-                ScreenCaptureTarget::CameraOnly,
-            );
-            attempt
-                .attach(PathBuf::from("unused-synthetic.cap"), builder.lifecycle())
-                .await
-                .unwrap();
-            attempt.cancel();
-            drop(builder);
-            assert!(attempt.capture_cleanup().await);
-            assert!(attempt.cancelled());
-            assert!(attempt.authorize().is_err());
-        }
-        #[tokio::test]
-        async fn stop_retry_signals_cancellation_before_waiting_for_operation_lock() {
-            let attempt = Attempt::new();
-            attempt.0.started.send_replace(true);
-            let active = attempt.0.operation.lock().await;
-            attempt.prepare_control();
-            assert!(attempt.cancelled());
-            assert!(attempt.upload().check().is_err());
-            drop(active);
-        }
-        #[test]
-        fn explicit_camera_only_system_audio_request_is_rejected_before_normalization() {
-            let mut inputs = StartRecordingInputs {
-                capture_target: ScreenCaptureTarget::CameraOnly,
-                capture_system_audio: true,
-                mode: RecordingMode::Instant,
-                organization_id: None,
-            };
-            assert!(validate_inputs(&inputs).is_err());
-            assert!(inputs.capture_system_audio);
-            inputs.capture_system_audio = false;
-            assert!(validate_inputs(&inputs).is_ok());
-            inputs.capture_system_audio = true;
-            inputs.mode = RecordingMode::Studio;
-            assert!(validate_inputs(&inputs).is_ok());
-        }
-        #[tokio::test]
-        async fn terminal_observer_does_not_revoke_an_owned_successful_stop() {
-            let attempt = Attempt::new();
-            attempt.0.started.send_replace(true);
-            let active = attempt.0.operation.lock().await;
-            assert!(!attempt.terminal_needs_cleanup());
-            assert!(!attempt.cancelled());
-            drop(active);
-            assert!(attempt.terminal_needs_cleanup());
-            assert!(attempt.cancelled());
-        }
-        #[tokio::test]
-        async fn local_completion_rechecks_after_held_app_lock_before_success_or_delete() {
-            for delete_after_upload in [false, true] {
-                let attempt = Attempt::new();
-                attempt.0.started.send_replace(true);
-                let state = tokio::sync::RwLock::new(Vec::new());
-                let held = state.read().await;
-                let deleted = AtomicBool::new(false);
-                let shared = AtomicBool::new(false);
-                let future = run_control(
-                    &attempt,
-                    false,
-                    || true,
-                    || async {
-                        let result = complete_local(
-                            &attempt,
-                            Ok(()),
-                            state.write(),
-                            |mut state, result| async move {
-                                state.push(result.is_ok());
-                                Ok(())
-                            },
-                        )
-                        .await;
-                        if result.is_ok() {
-                            shared.store(true, Ordering::Release);
-                            if delete_after_upload {
-                                deleted.store(true, Ordering::Release);
-                            }
-                        }
-                        attempt.record_terminal(false, result)
-                    },
-                );
-                tokio::pin!(future);
-                assert!(
-                    tokio::time::timeout(Duration::from_millis(10), &mut future)
-                        .await
-                        .is_err()
-                );
-                attempt.prepare_control();
-                drop(held);
-                assert!(future.await.is_err());
-                assert_eq!(*state.read().await, vec![false]);
-                assert!(!deleted.load(Ordering::Acquire));
-                assert!(!shared.load(Ordering::Acquire));
-            }
-        }
-
-        #[tokio::test]
-        async fn local_completion_rechecks_after_owned_cleanup_await() {
-            let attempt = Attempt::new();
-            attempt.0.started.send_replace(true);
-            let state = tokio::sync::RwLock::new(false);
-            let (release, released) = tokio::sync::oneshot::channel();
-            let (entered, entering) = tokio::sync::oneshot::channel();
-            let shared = AtomicBool::new(false);
-            let future = run_control(
-                &attempt,
-                false,
-                || true,
-                || async {
-                    let result = complete_local(
-                        &attempt,
-                        Ok(()),
-                        state.write(),
-                        |mut state, result| async move {
-                            assert!(result.is_ok());
-                            entered.send(()).unwrap();
-                            released.await.unwrap();
-                            *state = true;
-                            Ok(())
-                        },
-                    )
-                    .await;
-                    if result.is_ok() {
-                        shared.store(true, Ordering::Release);
-                    }
-                    attempt.record_terminal(false, result)
-                },
-            );
-            tokio::pin!(future);
-            assert!(
-                tokio::time::timeout(Duration::from_millis(10), &mut future)
-                    .await
-                    .is_err()
-            );
-            entering.await.unwrap();
-            attempt.prepare_control();
-            release.send(()).unwrap();
-            assert!(future.await.is_err());
-            assert!(*state.read().await);
-            assert!(!shared.load(Ordering::Acquire));
-        }
-
-        #[tokio::test]
-        async fn queued_stop_and_discard_replay_first_joined_error() {
-            for queued_discard in [false, true] {
-                let attempt = Attempt::new();
-                attempt.0.started.send_replace(true);
-                let current = AtomicBool::new(true);
-                let state = tokio::sync::RwLock::new(());
-                let (release, released) = tokio::sync::oneshot::channel();
-                let first = run_control(
-                    &attempt,
-                    false,
-                    || current.load(Ordering::Acquire),
-                    || async {
-                        released.await.unwrap();
-                        let result = complete_local(
-                            &attempt,
-                            Err::<(), _>("required audio failed".into()),
-                            state.write(),
-                            |_, result| async move {
-                                assert_eq!(result.unwrap_err(), "required audio failed");
-                                Err("later cleanup error".into())
-                            },
-                        )
-                        .await;
-                        attempt.0.ui_ready.store(true, Ordering::Release);
-                        let result = attempt.record_terminal(false, result);
-                        current.store(false, Ordering::Release);
-                        result
-                    },
-                );
-                tokio::pin!(first);
-                assert!(
-                    tokio::time::timeout(Duration::from_millis(10), &mut first)
-                        .await
-                        .is_err()
-                );
-                attempt.prepare_control();
-                let second = run_control(
-                    &attempt,
-                    queued_discard,
-                    || current.load(Ordering::Acquire),
-                    || async { panic!("queued control must not finalize or delete again") },
-                );
-                tokio::pin!(second);
-                assert!(
-                    tokio::time::timeout(Duration::from_millis(10), &mut second)
-                        .await
-                        .is_err()
-                );
-                release.send(()).unwrap();
-                assert_eq!(first.await.unwrap_err(), "required audio failed");
-                assert_eq!(second.await.unwrap_err(), "required audio failed");
-            }
-        }
-
-        #[tokio::test]
-        async fn successful_stop_is_idempotent_but_is_not_successful_discard() {
-            let attempt = Attempt::new();
-            attempt.0.started.send_replace(true);
-            run_control(
-                &attempt,
-                false,
-                || true,
-                || async { attempt.record_terminal(false, Ok(())) },
-            )
-            .await
-            .unwrap();
-            run_control(
-                &attempt,
-                false,
-                || false,
-                || async { panic!("already finished") },
-            )
-            .await
-            .unwrap();
-            let result = run_control(
-                &attempt,
-                true,
-                || false,
-                || async { panic!("must not delete") },
-            )
-            .await;
-            assert!(result.unwrap_err().contains("not discarded"));
-            run_control(
-                &attempt,
-                false,
-                || false,
-                || async { panic!("already finished") },
-            )
-            .await
-            .unwrap();
-        }
-
-        #[tokio::test]
-        async fn uncertain_cleanup_and_unrelated_generation_never_replay_ui_ready_success() {
-            let attempt = Attempt::new();
-            attempt.0.started.send_replace(true);
-            attempt.0.ui_ready.store(true, Ordering::Release);
-            for _ in 0..2 {
-                assert_eq!(
-                    run_control(
-                        &attempt,
-                        false,
-                        || true,
-                        || async { Err("cleanup unconfirmed".into()) }
-                    )
-                    .await
-                    .unwrap_err(),
-                    "cleanup unconfirmed"
-                );
-            }
-            assert!(attempt.0.terminal.lock().unwrap().is_none());
-            let result = run_control(
-                &attempt,
-                false,
-                || false,
-                || async { panic!("stale generation must not execute") },
-            )
-            .await;
-            assert!(result.unwrap_err().contains("superseded"));
-        }
-
-        #[tokio::test]
-        async fn terminal_failure_persists_failed_metadata_and_keeps_local_media() {
-            let path =
-                std::env::temp_dir().join(format!("cap-instant-terminal-{}", uuid::Uuid::new_v4()));
-            std::fs::create_dir_all(&path).unwrap();
-            let media = path.join("synthetic-bytes");
-            std::fs::write(&media, b"preserve").unwrap();
-            RecordingMeta {
-                platform: None,
-                project_path: path.clone(),
-                pretty_name: "Synthetic terminal failure".into(),
-                sharing: None,
-                inner: RecordingMetaInner::Instant(InstantRecordingMeta::InProgress {
-                    recording: false,
-                }),
-                upload: Some(cap_project::UploadMeta::Complete),
-            }
-            .save_for_project()
-            .unwrap();
-            persist_terminal_failure(&path, "late cancellation").await;
-            let meta = RecordingMeta::load_for_project(&path).unwrap();
-            assert!(
-                matches!(meta.inner, RecordingMetaInner::Instant(InstantRecordingMeta::Failed { error }) if error == "late cancellation")
-            );
-            assert_eq!(std::fs::read(&media).unwrap(), b"preserve");
-            std::fs::remove_dir_all(path).unwrap();
-        }
-        fn synthetic_success_effects(
-            attempt: &Attempt,
-            copies: &Mutex>,
-            cancel_before_copy: bool,
-            clipboard_error: bool,
-        ) -> Result<(), String> {
-            dispatch_success_effects(
-                attempt,
-                "https://example.invalid/s/fixture?existing=1",
-                SuccessEffects {
-                    recording_automation: || {},
-                    upload_automation: || {},
-                    open_link: |_| {
-                        if cancel_before_copy {
-                            attempt.cancel();
-                        }
-                        Ok(())
-                    },
-                    copy_link: |link| {
-                        copies.lock().unwrap().push(link);
-                        if clipboard_error {
-                            Err("synthetic clipboard unavailable".into())
-                        } else {
-                            Ok(())
-                        }
-                    },
-                    sound: || {},
-                },
-            )
-        }
-
-        async fn finish_synthetic_control(
-            attempt: &Attempt,
-            state: &tokio::sync::RwLock<()>,
-            copies: &Mutex>,
-            outcome: Result, String>,
-            discard: bool,
-        ) -> Result<(), String> {
-            let successful_upload = matches!(outcome, Ok(Some(())));
-            let mut result =
-                complete_local(attempt, outcome, state.write(), |_, _| async { Ok(()) }).await;
-            if result.is_ok() && successful_upload {
-                result = synthetic_success_effects(attempt, copies, false, false);
-            }
-            attempt.record_terminal(discard, result)
-        }
-
-        #[tokio::test]
-        async fn normal_instant_success_copies_original_link_once_without_auto_open_and_not_on_replay()
-         {
-            let attempt = Attempt::new();
-            attempt.0.started.send_replace(true);
-            let state = tokio::sync::RwLock::new(());
-            let copies = Mutex::new(Vec::new());
-            run_control(
-                &attempt,
-                false,
-                || true,
-                || finish_synthetic_control(&attempt, &state, &copies, Ok(Some(())), false),
-            )
-            .await
-            .unwrap();
-            run_control(
-                &attempt,
-                false,
-                || false,
-                || async { panic!("successful replay must not dispatch effects") },
-            )
-            .await
-            .unwrap();
-            assert_eq!(
-                *copies.lock().unwrap(),
-                vec!["https://example.invalid/s/fixture?existing=1"]
-            );
-        }
-
-        #[tokio::test]
-        async fn failed_and_discarded_controls_never_copy_share_link() {
-            for (outcome, discard) in [
-                (Err("required source failed".into()), false),
-                (Ok(None), true),
-            ] {
-                let attempt = Attempt::new();
-                attempt.0.started.send_replace(true);
-                let state = tokio::sync::RwLock::new(());
-                let copies = Mutex::new(Vec::new());
-                let result = run_control(
-                    &attempt,
-                    discard,
-                    || true,
-                    || finish_synthetic_control(&attempt, &state, &copies, outcome, discard),
-                )
-                .await;
-                assert_eq!(result.is_ok(), discard);
-                assert!(copies.lock().unwrap().is_empty());
-            }
-        }
-
-        #[tokio::test]
-        async fn cancelled_held_local_completion_and_queued_replay_never_copy_link() {
-            let attempt = Attempt::new();
-            attempt.0.started.send_replace(true);
-            let state = tokio::sync::RwLock::new(());
-            let held = state.read().await;
-            let copies = Mutex::new(Vec::new());
-            let first = run_control(
-                &attempt,
-                false,
-                || true,
-                || finish_synthetic_control(&attempt, &state, &copies, Ok(Some(())), false),
-            );
-            tokio::pin!(first);
-            assert!(
-                tokio::time::timeout(Duration::from_millis(10), &mut first)
-                    .await
-                    .is_err()
-            );
-            attempt.prepare_control();
-            let second = run_control(
-                &attempt,
-                false,
-                || false,
-                || async { panic!("cancelled replay must not dispatch effects") },
-            );
-            tokio::pin!(second);
-            assert!(
-                tokio::time::timeout(Duration::from_millis(10), &mut second)
-                    .await
-                    .is_err()
-            );
-            drop(held);
-            assert!(first.await.is_err());
-            assert!(second.await.is_err());
-            assert!(copies.lock().unwrap().is_empty());
-        }
-
-        #[test]
-        fn clipboard_boundary_rechecks_revocation_and_preserves_nonfatal_clipboard_error_policy() {
-            let cancelled = Attempt::new();
-            let cancelled_copies = Mutex::new(Vec::new());
-            assert!(synthetic_success_effects(&cancelled, &cancelled_copies, true, false).is_err());
-            assert!(cancelled_copies.lock().unwrap().is_empty());
-            let healthy = Attempt::new();
-            let attempted_copies = Mutex::new(Vec::new());
-            synthetic_success_effects(&healthy, &attempted_copies, false, true).unwrap();
-            assert_eq!(attempted_copies.lock().unwrap().len(), 1);
-        }
-    }
-}
-
-#[cfg(test)]
-mod editor_recording_restart_tests {
-    use super::*;
-    use std::sync::Mutex;
-
-    fn editor_target(path: &str) -> EditorRecordingTarget {
-        EditorRecordingTarget(Arc::new(Mutex::new(Some(PathBuf::from(path)))))
-    }
-
-    #[tokio::test]
-    async fn successful_restart_keeps_destination_through_terminal_cleanup() {
-        let target = editor_target("original.cap");
-        let result = restart_with_editor_target(
-            &target,
-            async {
-                assert!(take_editor_target_after_recording(&target, true).is_none());
-                Ok(())
-            },
-            async { Ok(()) },
-            || async {
-                assert_eq!(
-                    target.0.lock().unwrap().as_deref(),
-                    Some(Path::new("original.cap"))
-                );
-                Ok(RecordingAction::Started)
-            },
-            |_, _| async { panic!("successful restart must retain the destination") },
-        )
-        .await;
-        assert!(matches!(result, Ok(RecordingAction::Started)));
-        assert_eq!(
-            take_editor_target_after_recording(&target, false),
-            Some(PathBuf::from("original.cap"))
-        );
-        assert!(target.0.lock().unwrap().is_none());
-    }
-
-    #[tokio::test]
-    async fn failed_replacement_start_clears_only_its_editor_destination() {
-        let target = editor_target("original.cap");
-        let restored = Mutex::new(None);
-        let result = restart_with_editor_target(
-            &target,
-            async { Ok(()) },
-            async { Ok(()) },
-            || async { Err("requested microphone unavailable".into()) },
-            |expected, cleanup_completed| {
-                let target = ⌖
-                let restored = &restored;
-                async move {
-                    *restored.lock().unwrap() = take_failed_restart_editor_target(
-                        target,
-                        expected.as_deref(),
-                        cleanup_completed,
-                    );
-                }
-            },
-        )
-        .await;
-        assert!(result.is_err());
-        assert_eq!(
-            *restored.lock().unwrap(),
-            Some(PathBuf::from("original.cap"))
-        );
-        assert!(target.0.lock().unwrap().is_none());
-    }
-
-    #[tokio::test]
-    async fn unconfirmed_old_stop_keeps_active_editor_ownership() {
-        let target = editor_target("original.cap");
-        let result = restart_with_editor_target(
-            &target,
-            async { Err("Studio cleanup is unconfirmed".into()) },
-            async { panic!("controls cannot restore before confirmed cleanup") },
-            || async { panic!("replacement cannot start before confirmed cleanup") },
-            |expected, cleanup_completed| {
-                let target = ⌖
-                async move {
-                    assert!(
-                        take_failed_restart_editor_target(
-                            target,
-                            expected.as_deref(),
-                            cleanup_completed
-                        )
-                        .is_none()
-                    );
-                }
-            },
-        )
-        .await;
-        assert!(result.is_err());
-        assert_eq!(
-            target.0.lock().unwrap().as_deref(),
-            Some(Path::new("original.cap"))
-        );
-    }
-
-    #[tokio::test]
-    async fn replaced_editor_destination_cancels_restart_without_consuming_new_target() {
-        let target = editor_target("original.cap");
-        let result = restart_with_editor_target(
-            &target,
-            async {
-                *target.0.lock().unwrap() = Some(PathBuf::from("replacement.cap"));
-                Ok(())
-            },
-            async { Ok(()) },
-            || async { panic!("a different editor now owns recording") },
-            |expected, cleanup_completed| {
-                let target = ⌖
-                async move {
-                    assert!(
-                        take_failed_restart_editor_target(
-                            target,
-                            expected.as_deref(),
-                            cleanup_completed
-                        )
-                        .is_none()
-                    );
-                }
-            },
-        )
-        .await;
-        assert!(result.is_err());
-        assert_eq!(
-            target.0.lock().unwrap().as_deref(),
-            Some(Path::new("replacement.cap"))
-        );
-    }
-
-    #[tokio::test]
-    async fn losing_restart_cannot_clear_the_winners_target_after_recording_state_is_cleared() {
-        let target = editor_target("original.cap");
-        let result = restart_with_editor_target(
-            &target,
-            async { Err("Studio terminal completion is stale".into()) },
-            async { panic!("the losing restart cannot restore controls") },
-            || async { panic!("the losing restart cannot start another recording") },
-            |expected, cleanup_completed| {
-                let target = ⌖
-                async move {
-                    let recording_cleared = true;
-                    assert!(
-                        take_failed_restart_editor_target(
-                            target,
-                            expected.as_deref(),
-                            cleanup_completed && recording_cleared,
-                        )
-                        .is_none()
-                    );
-                }
-            },
-        )
-        .await;
-        assert!(result.is_err());
-        assert_eq!(
-            target.0.lock().unwrap().as_deref(),
-            Some(Path::new("original.cap"))
-        );
-    }
-
-    #[tokio::test]
-    async fn restoration_failure_clears_the_owned_target_before_any_replacement_start() {
-        let target = editor_target("original.cap");
-        let result = restart_with_editor_target(
-            &target,
-            async { Ok(()) },
-            async { Err("Recording controls could not be restored".into()) },
-            || async { panic!("replacement cannot start before controls are restored") },
-            |expected, cleanup_completed| {
-                let target = ⌖
-                async move {
-                    assert_eq!(
-                        take_failed_restart_editor_target(
-                            target,
-                            expected.as_deref(),
-                            cleanup_completed,
-                        ),
-                        Some(PathBuf::from("original.cap")),
-                    );
-                }
-            },
-        )
-        .await;
-        assert!(result.is_err());
-        assert!(target.0.lock().unwrap().is_none());
-    }
-
-    #[tokio::test]
-    async fn caller_cancellation_does_not_abandon_restart_after_old_capture_stops() {
-        let target = editor_target("original.cap");
-        let retained = target.clone();
-        let (entered, entry) = tokio::sync::oneshot::channel();
-        let (release, released) = tokio::sync::oneshot::channel();
-        let (finished, finish) = tokio::sync::oneshot::channel();
-        let caller = tokio::spawn(async move {
-            complete_studio_restart(async move {
-                let result = restart_with_editor_target(
-                    &target,
-                    async {
-                        assert!(take_editor_target_after_recording(&target, true).is_none());
-                        entered.send(()).unwrap();
-                        released.await.unwrap();
-                        Ok(())
-                    },
-                    async { Ok(()) },
-                    || async { Ok(RecordingAction::Started) },
-                    |_, _| async {
-                        panic!("owned replacement must finish after caller cancellation")
-                    },
-                )
-                .await;
-                finished.send(()).unwrap();
-                result
-            })
-            .await
-        });
-        entry.await.unwrap();
-        caller.abort();
-        assert!(matches!(caller.await, Err(error) if error.is_cancelled()));
-        release.send(()).unwrap();
-        tokio::time::timeout(Duration::from_secs(2), finish)
-            .await
-            .unwrap()
-            .unwrap();
-        assert_eq!(
-            retained.0.lock().unwrap().as_deref(),
-            Some(Path::new("original.cap"))
-        );
-    }
-}
-
-#[cfg(all(test, target_os = "linux"))]
-mod studio_joined_completion_tests {
-    use super::*;
-    use std::sync::atomic::{AtomicUsize, Ordering};
-
-    #[tokio::test]
-    async fn unconfirmed_stop_never_enters_local_completion() {
-        let effects = AtomicUsize::new(0);
-        let result = after_studio_join(
-            async {
-                studio_recording::StudioStopReport {
-                    accepted_intent: true,
-                    quiescence: studio_recording::StudioQuiescence::Unconfirmed,
-                    result: Err("source stop unknown".into()),
-                }
-            },
-            |_| async {
-                effects.fetch_add(1, Ordering::SeqCst);
-                Ok(())
-            },
-        )
-        .await;
-        assert!(result.is_err());
-        assert_eq!(effects.load(Ordering::SeqCst), 0);
-    }
-
-    #[tokio::test]
-    async fn losing_preserve_cannot_finish_while_discard_local_cleanup_is_waiting() {
-        let effects = Arc::new(AtomicUsize::new(0));
-        let (entered, entry) = tokio::sync::oneshot::channel();
-        let (release, released) = tokio::sync::oneshot::channel();
-        let owner = tokio::spawn({
-            let effects = effects.clone();
-            async move {
-                after_studio_join(
-                    async {
-                        studio_recording::StudioStopReport {
-                            accepted_intent: true,
-                            quiescence: studio_recording::StudioQuiescence::Joined,
-                            result: Ok(studio_recording::CompletedRecording {
-                                project_path: std::path::PathBuf::from("synthetic.cap"),
-                                meta: cap_project::StudioRecordingMeta::MultipleSegments {
-                                    inner: cap_project::MultipleSegments {
-                                        segments: Vec::new(),
-                                        cursors: Default::default(),
-                                        status: Some(cap_project::StudioRecordingStatus::Complete),
-                                    },
-                                },
-                                cursor_data: Default::default(),
-                                clean_stopped: None,
-                            }),
-                        }
-                    },
-                    |_| async move {
-                        entered.send(()).unwrap();
-                        released.await.unwrap();
-                        effects.fetch_add(1, Ordering::SeqCst);
-                        Ok(())
-                    },
-                )
-                .await
-            }
-        });
-        entry.await.unwrap();
-        let losing = after_studio_join(
-            async {
-                studio_recording::StudioStopReport {
-                    accepted_intent: false,
-                    quiescence: studio_recording::StudioQuiescence::Joined,
-                    result: Err("different terminal action owns attempt".into()),
-                }
-            },
-            |_| async {
-                effects.fetch_add(100, Ordering::SeqCst);
-                Ok(())
-            },
-        )
-        .await;
-        assert!(losing.is_err());
-        assert!(!owner.is_finished());
-        assert_eq!(effects.load(Ordering::SeqCst), 0);
-        release.send(()).unwrap();
-        owner.await.unwrap().unwrap();
-        assert_eq!(effects.load(Ordering::SeqCst), 1);
-    }
-
-    #[tokio::test]
-    async fn joined_failure_waits_for_app_lock_without_turning_into_success() {
-        let app_lock = Arc::new(tokio::sync::RwLock::new(()));
-        let held = app_lock.clone().write_owned().await;
-        let effects = Arc::new(AtomicUsize::new(0));
-        let (joined_tx, joined_rx) = tokio::sync::oneshot::channel();
-        let (entered_tx, entered_rx) = tokio::sync::oneshot::channel();
-        let task = tokio::spawn({
-            let effects = effects.clone();
-            async move {
-                after_studio_join(
-                    async {
-                        joined_rx.await.unwrap();
-                        studio_recording::StudioStopReport {
-                            accepted_intent: true,
-                            quiescence: studio_recording::StudioQuiescence::Joined,
-                            result: Err("requested microphone failed".into()),
-                        }
-                    },
-                    |result| async move {
-                        let _ = entered_tx.send(());
-                        let _state = app_lock.write().await;
-                        effects.fetch_add(1, Ordering::SeqCst);
-                        result.map(|_| ())
-                    },
-                )
-                .await
-            }
-        });
-        assert_eq!(effects.load(Ordering::SeqCst), 0);
-        joined_tx.send(()).unwrap();
-        entered_rx.await.unwrap();
-        assert!(!task.is_finished());
-        assert_eq!(effects.load(Ordering::SeqCst), 0);
-        drop(held);
-        assert!(task.await.unwrap().is_err());
-        assert_eq!(effects.load(Ordering::SeqCst), 1);
-    }
-}
-
-#[cfg(all(test, any(target_os = "linux", target_os = "macos", windows)))]
-mod studio_failure_presentation_tests {
-    use super::*;
-
-    #[test]
-    fn confirmed_disk_full_message_keeps_exact_recording_path() {
-        let directory = Path::new("/recordings/Unfinished capture.cap");
-        for error in [
-            "out-of-process media finalization failed: disk full: encoder exited with code 60",
-            "Could not save cursor events: No space left on device (os error 28)",
-            "Failed to write keyboard events file: No space left on device (os error 28)",
-        ] {
-            let message = stopped_studio_error(error, directory, StudioTerminalAction::Stop);
-            assert!(message.starts_with("Recording stopped because your disk is full."));
-            assert!(message.contains(&directory.display().to_string()));
-            assert!(message.ends_with("Free up space before recording again."));
-            assert!(!message.contains("playable"));
-        }
-    }
-
-    #[test]
-    fn discard_and_restart_errors_do_not_claim_files_were_kept() {
-        let error = "partial directory removal failed: No space left on device (os error 28)";
-        for action in [StudioTerminalAction::Discard, StudioTerminalAction::Restart] {
-            assert_eq!(
-                stopped_studio_error(error, Path::new("recording.cap"), action),
-                error
-            );
-        }
-    }
-
-    #[test]
-    fn unrelated_recording_failures_keep_their_details() {
-        for error in [
-            "camera disconnected",
-            "Permission denied (os error 13)",
-            "could not open /recordings/disk full recording.cap",
-        ] {
-            assert_eq!(
-                stopped_studio_error(
-                    error,
-                    Path::new("recording.cap"),
-                    StudioTerminalAction::Stop
-                ),
-                error
-            );
-        }
-    }
-
-    #[cfg(windows)]
-    #[test]
-    fn windows_storage_full_codes_are_recognized() {
-        for error in ["write failed (os error 112)", "write failed (os error 39)"] {
-            assert!(
-                stopped_studio_error(
-                    error,
-                    Path::new("recording.cap"),
-                    StudioTerminalAction::Stop
-                )
-                .contains("your disk is full")
-            );
-        }
-    }
-}
-
-#[cfg(all(test, any(target_os = "macos", windows)))]
-mod studio_capture_control_tests {
-    use super::*;
-
-    #[tokio::test]
-    async fn studio_unconfirmed_or_losing_stop_cannot_restore_or_delete() {
-        for (accepted_intent, stop_acknowledged) in [(true, false), (false, true), (false, false)] {
-            let effects = std::sync::atomic::AtomicUsize::new(0);
-            let result = after_studio_capture_stop(
-                async {
-                    studio_recording::WindowsStudioStopReport {
-                        accepted_intent,
-                        stop_acknowledged,
-                        result: Err("encoder join unconfirmed".into()),
-                    }
-                },
-                |_| async {
-                    effects.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
-                    Ok(())
-                },
-            )
-            .await;
-            assert!(result.is_err());
-            assert_eq!(effects.load(std::sync::atomic::Ordering::SeqCst), 0);
-        }
-    }
-
-    #[tokio::test]
-    async fn acknowledged_media_failure_reaches_cleanup_with_its_error() {
-        let effects = std::sync::atomic::AtomicUsize::new(0);
-        let result = after_studio_capture_stop(
-            async {
-                studio_recording::WindowsStudioStopReport {
-                    accepted_intent: true,
-                    stop_acknowledged: true,
-                    result: Err("encoder exited before completing media".into()),
-                }
-            },
-            |result| async {
-                effects.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
-                result.map(|_| ())
-            },
-        )
-        .await;
-        assert_eq!(effects.load(std::sync::atomic::Ordering::SeqCst), 1);
-        assert_eq!(
-            result.unwrap_err(),
-            "encoder exited before completing media"
-        );
-    }
-
-    #[tokio::test]
-    async fn pending_stop_does_not_enter_cleanup() {
-        let effects = std::sync::atomic::AtomicUsize::new(0);
-        let (send, receive) = tokio::sync::oneshot::channel();
-        let stop = after_studio_capture_stop(async { receive.await.unwrap() }, |result| async {
-            effects.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
-            result.map(|_| ())
-        });
-        tokio::pin!(stop);
-        assert!(
-            tokio::time::timeout(Duration::from_millis(10), &mut stop)
-                .await
-                .is_err()
-        );
-        assert_eq!(effects.load(std::sync::atomic::Ordering::SeqCst), 0);
-        send.send(studio_recording::WindowsStudioStopReport {
-            accepted_intent: true,
-            stop_acknowledged: true,
-            result: Err("media finalization failed".into()),
-        })
-        .unwrap_or_else(|_| panic!("Stop receiver closed before acknowledgement"));
-        assert!(stop.await.is_err());
-        assert_eq!(effects.load(std::sync::atomic::Ordering::SeqCst), 1);
-    }
-
-    #[tokio::test]
-    async fn disk_full_presentation_requires_confirmed_stop_ownership() {
-        for (accepted_intent, stop_acknowledged) in [(true, true), (true, false), (false, true)] {
-            let entered = std::sync::atomic::AtomicBool::new(false);
-            let result = after_studio_capture_stop(
-                async {
-                    studio_recording::WindowsStudioStopReport {
-                        accepted_intent,
-                        stop_acknowledged,
-                        result: Err("disk full: encoder exited with code 60".into()),
-                    }
-                },
-                |result| async {
-                    entered.store(true, std::sync::atomic::Ordering::SeqCst);
-                    result.map_err(|error| {
-                        stopped_studio_error(
-                            &error,
-                            Path::new("retained.cap"),
-                            StudioTerminalAction::Stop,
-                        )
-                    })
-                },
-            )
-            .await;
-            let confirmed = accepted_intent && stop_acknowledged;
-            assert_eq!(entered.load(std::sync::atomic::Ordering::SeqCst), confirmed);
-            assert_eq!(
-                result
-                    .err()
-                    .unwrap()
-                    .starts_with("Recording stopped because your disk is full."),
-                confirmed
-            );
-        }
-    }
-}
-
-pub(crate) fn preparing_presentation_snapshot(
-    preset: Option<&ProjectConfiguration>,
-    capture_target: Option<&ScreenCaptureTarget>,
-) -> Result {
-    let mut config = preset
-        .cloned()
-        .ok_or("Default presentation requires ordinary finalization")?;
-    if matches!(capture_target, None | Some(ScreenCaptureTarget::CameraOnly))
-        || !matches!(
-            config.background.source,
-            cap_project::BackgroundSource::Color { .. }
-                | cap_project::BackgroundSource::Gradient {
-                    animated: None | Some(false),
-                    ..
-                }
-        )
-        || config.background.notch.is_some()
-    {
-        return Err("Presentation requires ordinary finalization".into());
-    }
-    config.cursor.size = cap_project::CursorConfiguration::default().size;
-    apply_screen_recording_presentation_defaults(&mut config, capture_target, false, None);
-    Ok(config)
-}
-
-#[cfg(test)]
-mod preparing_presentation_tests {
-    use super::*;
-
-    #[test]
-    fn stopped_camera_snapshot_matches_preparing_and_final_presentation() {
-        let target = ScreenCaptureTarget::Display {
-            id: "1".parse().unwrap(),
-        };
-        for blur in [
-            cap_project::BackgroundBlurMode::Off,
-            cap_project::BackgroundBlurMode::Remove,
-        ] {
-            let snapshot = StudioCameraSnapshot {
-                state: crate::camera::CameraPreviewState {
-                    background_blur: blur,
-                    ..Default::default()
-                },
-                placement: cap_recording::camera_placement::RecordingCameraPlacement::from_bounds(
-                    [860.0, 20.0, 200.0, 200.0],
-                    [0.0, 0.0, 1920.0, 1080.0],
-                ),
-            };
-            let original = ProjectConfiguration::default();
-            let mut preparing =
-                preparing_presentation_snapshot(Some(&original), Some(&target)).unwrap();
-            let mut finished = original.clone();
-            snapshot.apply(&mut preparing);
-            snapshot.apply(&mut finished);
-            assert_eq!(
-                serde_json::to_value(&preparing.camera).unwrap(),
-                serde_json::to_value(&finished.camera).unwrap()
-            );
-            assert!(finished.camera.manual_position.is_none());
-            assert_eq!(
-                serde_json::to_value(&finished.camera.position).unwrap(),
-                serde_json::json!({"x": "center", "y": "top"})
-            );
-            assert_eq!(finished.camera.size, original.camera.size);
-            assert_eq!(
-                serde_json::to_value(&finished.timeline).unwrap(),
-                serde_json::to_value(&original.timeline).unwrap()
-            );
-        }
-    }
-
-    #[test]
-    fn preparing_never_guesses_default_wallpaper_or_animated_background() {
-        assert!(preparing_presentation_snapshot(None, None).is_err());
-        let config = ProjectConfiguration::default();
-        assert!(preparing_presentation_snapshot(Some(&config), None).is_err());
-        assert!(
-            preparing_presentation_snapshot(Some(&config), Some(&ScreenCaptureTarget::CameraOnly))
-                .is_err()
-        );
-    }
-
-    #[test]
-    fn static_preset_defaults_match_the_existing_screen_defaults() {
-        let target = ScreenCaptureTarget::Display {
-            id: "1".parse().unwrap(),
-        };
-        let mut config = ProjectConfiguration::default();
-        config.cursor.size = 173;
-        config.background.padding = 0.0;
-        config.background.rounding = 0.0;
-        let projected = preparing_presentation_snapshot(Some(&config), Some(&target)).unwrap();
-        let mut ordinary = config;
-        ordinary.cursor.size = cap_project::CursorConfiguration::default().size;
-        apply_screen_recording_presentation_defaults(&mut ordinary, Some(&target), false, None);
-        assert_eq!(
-            serde_json::to_value(projected).unwrap(),
-            serde_json::to_value(ordinary).unwrap()
-        );
-    }
-}
-
-#[cfg(test)]
-mod preparing_presentation_parity_tests {
-    use super::*;
-    use cap_project::{BackgroundSource, ClipConfiguration, ClipOffsets, ScreenMovementSpring};
-
-    fn value(config: &ProjectConfiguration) -> serde_json::Value {
-        serde_json::to_value(config).unwrap()
-    }
-
-    fn targets() -> Vec {
-        vec![
-            ScreenCaptureTarget::Display {
-                id: "1".parse().unwrap(),
-            },
-            ScreenCaptureTarget::Window {
-                id: "1".parse().unwrap(),
-            },
-            ScreenCaptureTarget::Area {
-                screen: "1".parse().unwrap(),
-                bounds: scap_targets::bounds::LogicalBounds::new(
-                    scap_targets::bounds::LogicalPosition::new(10.0, 20.0),
-                    scap_targets::bounds::LogicalSize::new(320.0, 240.0),
-                ),
-            },
-        ]
-    }
-
-    fn one_segment(end: f64) -> Vec {
-        vec![TimelineSegment {
-            recording_clip: 0,
-            start: 0.0,
-            end,
-            timescale: 1.0,
-            name: None,
-            speed_audio_mode: None,
-            hide_cursor: None,
-            volume: None,
-        }]
-    }
-
-    fn preset() -> ProjectConfiguration {
-        ProjectConfiguration::default()
-    }
-
-    fn preparing_static_projection(
-        preset: &ProjectConfiguration,
-        target: &ScreenCaptureTarget,
-        stopped: &TimelineConfiguration,
-    ) -> ProjectConfiguration {
-        let mut snapshot = preparing_presentation_snapshot(Some(preset), Some(target)).unwrap();
-        apply_recording_camera_preview_state(
-            &mut snapshot,
-            &crate::camera::CameraPreviewState::default(),
-        );
-        crate::editor_preparing::project_from_preparing_presentation(&snapshot, stopped)
-    }
-
-    fn ordinary_static_projection(
-        preset: &ProjectConfiguration,
-        target: &ScreenCaptureTarget,
-        segments: Vec,
-    ) -> ProjectConfiguration {
-        let mut config = preset.clone();
-        config.cursor.size = cap_project::CursorConfiguration::default().size;
-        apply_screen_recording_presentation_defaults(&mut config, Some(target), false, None);
-        apply_recording_camera_preview_state(
-            &mut config,
-            &crate::camera::CameraPreviewState::default(),
-        );
-        config.timeline = Some(recording_timeline(segments, Vec::new()));
-        config
-    }
-
-    #[test]
-    fn static_color_projection_preserves_preset_and_matches_ordinary_screen_defaults() {
-        for target in targets() {
-            let mut preset = preset();
-            preset.cursor.size = 173;
-            preset.background.padding = 0.0;
-            preset.background.rounding = 0.0;
-            preset.background.source = BackgroundSource::Color {
-                value: [32, 64, 128],
-                alpha: 160,
-            };
-            preset.screen_movement_spring = ScreenMovementSpring {
-                stiffness: 120.0,
-                damping: 14.0,
-                mass: 1.0,
-            };
-            let original = value(&preset);
-            let stopped = recording_timeline(one_segment(6.0), Vec::new());
-            let projected = preparing_static_projection(&preset, &target, &stopped);
-            let ordinary = ordinary_static_projection(&preset, &target, one_segment(6.0));
-            assert_eq!(value(&projected), value(&ordinary));
-            assert_eq!(value(&preset), original);
-            assert_eq!(projected.background.padding, 10.0);
-            assert_eq!(
-                projected.background.rounding,
-                if matches!(target, ScreenCaptureTarget::Area { .. }) {
-                    0.0
-                } else {
-                    7.5
-                }
-            );
-            assert_eq!(
-                projected.cursor.size,
-                cap_project::CursorConfiguration::default().size
-            );
-            assert_eq!(
-                serde_json::to_value(projected.screen_movement_spring).unwrap(),
-                serde_json::to_value(ScreenMovementSpring::default()).unwrap()
-            );
-            assert!(matches!(
-                projected.background.source,
-                BackgroundSource::Color {
-                    value: [32, 64, 128],
-                    alpha: 160
-                }
-            ));
-        }
-    }
-
-    #[test]
-    fn static_gradients_preserve_explicit_presentation_values_for_each_screen_target() {
-        for target in targets() {
-            for animated in [None, Some(false)] {
-                let mut preset = preset();
-                preset.background.padding = 23.0;
-                preset.background.rounding = 11.0;
-                preset.background.source = BackgroundSource::Gradient {
-                    from: [17, 41, 65],
-                    to: [193, 211, 227],
-                    angle: 217,
-                    noise_intensity: Some(0.125),
-                    noise_scale: Some(1.5),
-                    animated,
-                    animation_speed: Some(0.25),
-                };
-                preset.screen_movement_spring = ScreenMovementSpring {
-                    stiffness: 150.0,
-                    damping: 22.0,
-                    mass: 0.8,
-                };
-                let stopped = recording_timeline(one_segment(6.0), Vec::new());
-                let projected = preparing_static_projection(&preset, &target, &stopped);
-                assert_eq!(
-                    value(&projected),
-                    value(&ordinary_static_projection(
-                        &preset,
-                        &target,
-                        one_segment(6.0)
-                    ))
-                );
-                assert_eq!(projected.background.padding, 23.0);
-                assert_eq!(projected.background.rounding, 11.0);
-                assert_eq!(
-                    serde_json::to_value(&projected.background.source).unwrap(),
-                    serde_json::to_value(&preset.background.source).unwrap()
-                );
-            }
-        }
-    }
-
-    #[test]
-    fn unresolved_and_late_presentation_inputs_are_declined_without_mutating_presets() {
-        let target = targets().remove(0);
-        assert!(preparing_presentation_snapshot(None, Some(&target)).is_err());
-        let mut preset = preset();
-        for source in [
-            BackgroundSource::Wallpaper {
-                path: Some("wallpaper.jpg".into()),
-            },
-            BackgroundSource::Image {
-                path: Some("image.png".into()),
-            },
-            BackgroundSource::AnimatedGradient {
-                config: Default::default(),
-            },
-            BackgroundSource::Gradient {
-                from: [0, 0, 0],
-                to: [255, 255, 255],
-                angle: 90,
-                noise_intensity: None,
-                noise_scale: None,
-                animated: Some(true),
-                animation_speed: None,
-            },
-        ] {
-            preset.background.source = source;
-            let original = value(&preset);
-            assert!(preparing_presentation_snapshot(Some(&preset), Some(&target)).is_err());
-            assert_eq!(value(&preset), original);
-        }
-        preset.background.source = BackgroundSource::default();
-        for enabled in [false, true] {
-            preset.background.notch = Some(cap_project::NotchConfiguration {
-                enabled,
-                ..Default::default()
-            });
-            assert!(preparing_presentation_snapshot(Some(&preset), Some(&target)).is_err());
-        }
-        preset.background.notch = None;
-        assert!(preparing_presentation_snapshot(Some(&preset), None).is_err());
-        assert!(
-            preparing_presentation_snapshot(Some(&preset), Some(&ScreenCaptureTarget::CameraOnly))
-                .is_err()
-        );
-    }
-
-    #[test]
-    fn stopped_timeline_replaces_preset_edits_but_keeps_explicit_clip_offsets() {
-        let target = targets().remove(0);
-        let mut preset = preset();
-        preset.clips = vec![ClipConfiguration {
-            index: 0,
-            offsets: ClipOffsets {
-                camera: 0.125,
-                mic: -0.25,
-                system_audio: 0.0625,
-            },
-            offsets_auto_calculated: false,
-        }];
-        let old_zoom: ZoomSegment = serde_json::from_value(serde_json::json!({
-            "start": 1.0, "end": 4.0, "amount": 2.0, "mode": "auto"
-        }))
-        .unwrap();
-        preset.timeline = Some(recording_timeline(one_segment(2.0), vec![old_zoom]));
-        let stopped = recording_timeline(one_segment(6.0), Vec::new());
-        let projected = preparing_static_projection(&preset, &target, &stopped);
-        let ordinary = ordinary_static_projection(&preset, &target, one_segment(6.0));
-        assert_eq!(value(&projected), value(&ordinary));
-        let timeline = projected.timeline.as_ref().unwrap();
-        assert_eq!(timeline.segments.len(), 1);
-        assert_eq!(timeline.segments[0].end, 6.0);
-        assert!(timeline.zoom_segments.is_empty());
-        assert_eq!(
-            serde_json::to_value(&projected.clips).unwrap(),
-            serde_json::to_value(&preset.clips).unwrap()
-        );
-        assert_eq!(preset.timeline.as_ref().unwrap().segments[0].end, 2.0);
-        assert_eq!(preset.timeline.as_ref().unwrap().zoom_segments.len(), 1);
-    }
-
-    #[test]
-    fn ordinary_late_camera_state_preserves_unrelated_camera_fields() {
-        for (shape, expected_shape, rounding) in [
-            (CameraPreviewShape::Round, CameraShape::Square, 100.0),
-            (CameraPreviewShape::Square, CameraShape::Square, 25.0),
-            (CameraPreviewShape::Full, CameraShape::Source, 25.0),
-        ] {
-            for blur in [
-                cap_project::BackgroundBlurMode::Off,
-                cap_project::BackgroundBlurMode::Light,
-                cap_project::BackgroundBlurMode::Heavy,
-            ] {
-                let mut config = preset();
-                config.camera.size = 41.0;
-                config.camera.mirror = true;
-                let mut expected = config.clone();
-                expected.camera.shape = expected_shape;
-                expected.camera.rounding = rounding;
-                if shape == CameraPreviewShape::Round {
-                    expected.camera.rounding_type = CornerStyle::Rounded;
-                }
-                expected.camera.background_blur.mode = blur;
-                apply_recording_camera_preview_state(
-                    &mut config,
-                    &crate::camera::CameraPreviewState {
-                        size: 99.0,
-                        shape: shape.clone(),
-                        mirrored: false,
-                        background_blur: blur,
-                    },
-                );
-                assert_eq!(value(&config), value(&expected));
-                assert_eq!(config.camera.size, 41.0);
-                assert!(config.camera.mirror);
-            }
-        }
-    }
-}
diff --git a/apps/desktop/src-tauri/src/recording_settings.rs b/apps/desktop/src-tauri/src/recording_settings.rs
deleted file mode 100644
index 4341d34688b..00000000000
--- a/apps/desktop/src-tauri/src/recording_settings.rs
+++ /dev/null
@@ -1,168 +0,0 @@
-use cap_recording::{
-    RecordingMode,
-    feeds::{
-        camera::{CameraDeviceSettings, DeviceOrModelID},
-        microphone::MicrophoneDeviceSettings,
-    },
-    sources::screen_capture::ScreenCaptureTarget,
-};
-use std::collections::HashMap;
-use tauri::{AppHandle, Wry};
-use tauri_plugin_store::StoreExt;
-
-use crate::tray;
-
-#[derive(serde::Serialize, serde::Deserialize, specta::Type, Debug, Clone, Copy)]
-#[serde(rename_all = "camelCase")]
-pub enum RecordingTargetMode {
-    Display,
-    Window,
-    Area,
-    Camera,
-}
-
-#[derive(serde::Serialize, serde::Deserialize, specta::Type, Debug, Clone, Default)]
-#[serde(rename_all = "camelCase", default)]
-pub struct RecordingSettingsStore {
-    pub target: Option,
-    pub mic_name: Option,
-    #[serde(deserialize_with = "deserialize_camera_id")]
-    pub camera_id: Option,
-    pub mode: Option,
-    pub system_audio: bool,
-    pub organization_id: Option,
-    pub camera_device_settings: HashMap,
-    pub microphone_device_settings: HashMap,
-}
-
-fn deserialize_camera_id<'de, D>(deserializer: D) -> Result, D::Error>
-where
-    D: serde::Deserializer<'de>,
-{
-    let value = ::deserialize(deserializer)?;
-    match serde_json::from_value(value) {
-        Ok(camera_id) => Ok(camera_id),
-        Err(error) => {
-            tracing::warn!(%error, "Ignoring invalid saved camera selection");
-            Ok(None)
-        }
-    }
-}
-
-impl RecordingSettingsStore {
-    const KEY: &'static str = "recording_settings";
-
-    pub fn get(app: &AppHandle) -> Result, String> {
-        match app.store("store").map(|s| s.get(Self::KEY)) {
-            Ok(Some(store)) => match serde_json::from_value(store) {
-                Ok(settings) => Ok(Some(settings)),
-                Err(e) => Err(format!(
-                    "Failed to deserialize recording settings store: {e}"
-                )),
-            },
-            _ => Ok(None),
-        }
-    }
-
-    pub fn set_mode(app: &AppHandle, mode: RecordingMode) -> Result<(), String> {
-        let store = app.store("store").map_err(|e| e.to_string())?;
-
-        let mut settings = Self::get(app)?.unwrap_or_default();
-        settings.mode = Some(mode);
-
-        store.set(Self::KEY, serde_json::json!(settings));
-        store.save().map_err(|e| e.to_string())
-    }
-
-    pub fn camera_settings_for(
-        app: &AppHandle,
-        id: &DeviceOrModelID,
-    ) -> Option {
-        Self::get(app).ok().flatten().and_then(|settings| {
-            settings
-                .camera_device_settings
-                .get(&camera_key(id))
-                .copied()
-        })
-    }
-
-    pub fn microphone_settings_for(
-        app: &AppHandle,
-        label: &str,
-    ) -> Option {
-        Self::get(app)
-            .ok()
-            .flatten()
-            .and_then(|settings| settings.microphone_device_settings.get(label).copied())
-    }
-}
-
-pub fn camera_key(id: &DeviceOrModelID) -> String {
-    match id {
-        DeviceOrModelID::DeviceID(device_id) => format!("device:{device_id}"),
-        DeviceOrModelID::ModelID(model_id) => format!("model:{model_id}"),
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-pub fn set_recording_mode(app: AppHandle, mode: RecordingMode) -> Result<(), String> {
-    RecordingSettingsStore::set_mode(&app, mode)?;
-    tray::update_tray_icon_for_mode(&app, mode);
-    Ok(())
-}
-
-#[cfg(test)]
-mod tests {
-    use super::RecordingSettingsStore;
-    use serde_json::json;
-
-    #[test]
-    fn invalid_camera_selection_preserves_other_recording_preferences() {
-        for camera_id in [
-            json!({"DeviceID": "camera-a", "ModelID": "046d:08e5"}),
-            json!({"ModelID": "missing-separator"}),
-            json!({"DeviceID": 123}),
-            json!({"unknown": "camera-a"}),
-            json!({}),
-            json!("camera-a"),
-        ] {
-            let mut saved = json!({
-                "target": {"variant": "cameraOnly"},
-                "micName": "Saved microphone",
-                "cameraId": camera_id,
-                "mode": "studio",
-                "systemAudio": true,
-                "organizationId": "saved-organization",
-                "cameraDeviceSettings": {
-                    "model:046d:08e5": {"width": 1280, "height": 720, "frameRate": 60.0}
-                },
-                "microphoneDeviceSettings": {
-                    "Saved microphone": {"sampleRate": 48000, "channels": 1}
-                }
-            });
-            let settings: RecordingSettingsStore = serde_json::from_value(saved.clone()).unwrap();
-            assert!(settings.camera_id.is_none());
-            saved["cameraId"] = serde_json::Value::Null;
-            assert_eq!(serde_json::to_value(settings).unwrap(), saved);
-        }
-    }
-
-    #[test]
-    fn valid_camera_variants_and_none_round_trip() {
-        for camera_id in [
-            json!({"DeviceID": "camera-a"}),
-            json!({"ModelID": "046d:08e5"}),
-            serde_json::Value::Null,
-        ] {
-            let settings: RecordingSettingsStore =
-                serde_json::from_value(json!({"cameraId": camera_id})).unwrap();
-            assert_eq!(
-                serde_json::to_value(settings).unwrap()["cameraId"],
-                camera_id
-            );
-        }
-        let settings: RecordingSettingsStore = serde_json::from_value(json!({})).unwrap();
-        assert!(settings.camera_id.is_none());
-    }
-}
diff --git a/apps/desktop/src-tauri/src/recording_telemetry.rs b/apps/desktop/src-tauri/src/recording_telemetry.rs
deleted file mode 100644
index 5d3238f8762..00000000000
--- a/apps/desktop/src-tauri/src/recording_telemetry.rs
+++ /dev/null
@@ -1,271 +0,0 @@
-use cap_recording::PipelineHealthEvent;
-use std::{
-    sync::{
-        Arc,
-        atomic::{AtomicBool, AtomicU64, Ordering},
-    },
-    time::Instant,
-};
-
-#[derive(Debug)]
-pub struct RecordingHealthAccumulator {
-    started_at: Instant,
-    capture_stalls_count: AtomicU64,
-    capture_stalls_max_ms: AtomicU64,
-    mixer_stalls_count: AtomicU64,
-    mixer_stalls_max_ms: AtomicU64,
-    audio_gaps_count: AtomicU64,
-    audio_gaps_total_ms: AtomicU64,
-    frame_drop_rate_high_count: AtomicU64,
-    source_restarts_count: AtomicU64,
-    muxer_crash_count: AtomicU64,
-    audio_degraded_count: AtomicU64,
-    muxer_crashed_fired: AtomicBool,
-    audio_degraded_fired: AtomicBool,
-}
-
-#[derive(Debug, Clone, Copy)]
-pub struct RecordingHealthSnapshot {
-    pub capture_stalls_count: u64,
-    pub capture_stalls_max_ms: u64,
-    pub mixer_stalls_count: u64,
-    pub mixer_stalls_max_ms: u64,
-    pub audio_gaps_count: u64,
-    pub audio_gaps_total_ms: u64,
-    pub frame_drop_rate_high_count: u64,
-    pub source_restarts_count: u64,
-    pub muxer_crash_count: u64,
-    pub audio_degraded_count: u64,
-}
-
-#[derive(Debug, Clone, Copy)]
-pub enum CriticalEvent {
-    MuxerCrashed {
-        reason_index: usize,
-        seconds_into_recording: f64,
-    },
-    AudioDegraded {
-        reason_index: usize,
-        seconds_into_recording: f64,
-    },
-}
-
-impl RecordingHealthAccumulator {
-    pub fn new() -> Arc {
-        Arc::new(Self {
-            started_at: Instant::now(),
-            capture_stalls_count: AtomicU64::new(0),
-            capture_stalls_max_ms: AtomicU64::new(0),
-            mixer_stalls_count: AtomicU64::new(0),
-            mixer_stalls_max_ms: AtomicU64::new(0),
-            audio_gaps_count: AtomicU64::new(0),
-            audio_gaps_total_ms: AtomicU64::new(0),
-            frame_drop_rate_high_count: AtomicU64::new(0),
-            source_restarts_count: AtomicU64::new(0),
-            muxer_crash_count: AtomicU64::new(0),
-            audio_degraded_count: AtomicU64::new(0),
-            muxer_crashed_fired: AtomicBool::new(false),
-            audio_degraded_fired: AtomicBool::new(false),
-        })
-    }
-
-    pub fn seconds_since_start(&self) -> f64 {
-        self.started_at.elapsed().as_secs_f64()
-    }
-
-    pub fn record_event(&self, event: &PipelineHealthEvent) -> Option<(String, CriticalEvent)> {
-        match event {
-            PipelineHealthEvent::Stalled { source, waited_ms } => {
-                let is_mixer = source.starts_with("mixer:");
-                let waited = *waited_ms;
-                if is_mixer {
-                    self.mixer_stalls_count.fetch_add(1, Ordering::Relaxed);
-                    update_max(&self.mixer_stalls_max_ms, waited);
-                } else {
-                    self.capture_stalls_count.fetch_add(1, Ordering::Relaxed);
-                    update_max(&self.capture_stalls_max_ms, waited);
-                }
-                None
-            }
-            PipelineHealthEvent::AudioGapDetected { gap_ms } => {
-                self.audio_gaps_count.fetch_add(1, Ordering::Relaxed);
-                self.audio_gaps_total_ms
-                    .fetch_add(*gap_ms, Ordering::Relaxed);
-                None
-            }
-            PipelineHealthEvent::FrameDropRateHigh { .. } => {
-                self.frame_drop_rate_high_count
-                    .fetch_add(1, Ordering::Relaxed);
-                None
-            }
-            PipelineHealthEvent::SourceRestarting => {
-                self.source_restarts_count.fetch_add(1, Ordering::Relaxed);
-                None
-            }
-            PipelineHealthEvent::SourceRestarted => None,
-            PipelineHealthEvent::MuxerCrashed { reason } => {
-                self.muxer_crash_count.fetch_add(1, Ordering::Relaxed);
-                let first = !self.muxer_crashed_fired.swap(true, Ordering::AcqRel);
-                if first {
-                    Some((
-                        reason.clone(),
-                        CriticalEvent::MuxerCrashed {
-                            reason_index: 0,
-                            seconds_into_recording: self.seconds_since_start(),
-                        },
-                    ))
-                } else {
-                    None
-                }
-            }
-            PipelineHealthEvent::AudioDegradedToVideoOnly { reason } => {
-                self.audio_degraded_count.fetch_add(1, Ordering::Relaxed);
-                let first = !self.audio_degraded_fired.swap(true, Ordering::AcqRel);
-                if first {
-                    Some((
-                        reason.clone(),
-                        CriticalEvent::AudioDegraded {
-                            reason_index: 0,
-                            seconds_into_recording: self.seconds_since_start(),
-                        },
-                    ))
-                } else {
-                    None
-                }
-            }
-            PipelineHealthEvent::DiskSpaceLow { .. }
-            | PipelineHealthEvent::DiskSpaceExhausted { .. }
-            | PipelineHealthEvent::DeviceLost { .. }
-            | PipelineHealthEvent::EncoderRebuilt { .. }
-            | PipelineHealthEvent::SourceAudioReset { .. }
-            | PipelineHealthEvent::RecoveryFragmentCorrupt { .. }
-            | PipelineHealthEvent::CaptureTargetLost { .. }
-            | PipelineHealthEvent::MicrophoneDigitalSilence => None,
-        }
-    }
-
-    pub fn snapshot(&self) -> RecordingHealthSnapshot {
-        RecordingHealthSnapshot {
-            capture_stalls_count: self.capture_stalls_count.load(Ordering::Acquire),
-            capture_stalls_max_ms: self.capture_stalls_max_ms.load(Ordering::Acquire),
-            mixer_stalls_count: self.mixer_stalls_count.load(Ordering::Acquire),
-            mixer_stalls_max_ms: self.mixer_stalls_max_ms.load(Ordering::Acquire),
-            audio_gaps_count: self.audio_gaps_count.load(Ordering::Acquire),
-            audio_gaps_total_ms: self.audio_gaps_total_ms.load(Ordering::Acquire),
-            frame_drop_rate_high_count: self.frame_drop_rate_high_count.load(Ordering::Acquire),
-            source_restarts_count: self.source_restarts_count.load(Ordering::Acquire),
-            muxer_crash_count: self.muxer_crash_count.load(Ordering::Acquire),
-            audio_degraded_count: self.audio_degraded_count.load(Ordering::Acquire),
-        }
-    }
-}
-
-fn update_max(cell: &AtomicU64, candidate: u64) {
-    let mut current = cell.load(Ordering::Acquire);
-    while candidate > current {
-        match cell.compare_exchange_weak(current, candidate, Ordering::AcqRel, Ordering::Acquire) {
-            Ok(_) => return,
-            Err(observed) => current = observed,
-        }
-    }
-}
-
-pub fn mode_label(mode: cap_recording::RecordingMode) -> &'static str {
-    match mode {
-        cap_recording::RecordingMode::Studio => "studio",
-        cap_recording::RecordingMode::Instant => "instant",
-        cap_recording::RecordingMode::Screenshot => "screenshot",
-    }
-}
-
-pub fn target_kind_label(
-    target: &cap_recording::sources::screen_capture::ScreenCaptureTarget,
-) -> &'static str {
-    use cap_recording::sources::screen_capture::ScreenCaptureTarget;
-    match target {
-        ScreenCaptureTarget::Display { .. } => "display",
-        ScreenCaptureTarget::Window { .. } => "window",
-        ScreenCaptureTarget::Area { .. } => "area",
-        ScreenCaptureTarget::CameraOnly => "camera_only",
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    fn make_stall(source: &str, waited_ms: u64) -> PipelineHealthEvent {
-        PipelineHealthEvent::Stalled {
-            source: source.to_string(),
-            waited_ms,
-        }
-    }
-
-    #[test]
-    fn accumulator_separates_capture_and_mixer_stalls() {
-        let acc = RecordingHealthAccumulator::new();
-        acc.record_event(&make_stall("screen-video", 80));
-        acc.record_event(&make_stall("screen-system-audio", 50));
-        acc.record_event(&make_stall("mixer:mic", 200));
-        acc.record_event(&make_stall("mixer:sys", 950));
-        let snap = acc.snapshot();
-        assert_eq!(snap.capture_stalls_count, 2);
-        assert_eq!(snap.capture_stalls_max_ms, 80);
-        assert_eq!(snap.mixer_stalls_count, 2);
-        assert_eq!(snap.mixer_stalls_max_ms, 950);
-    }
-
-    #[test]
-    fn accumulator_fires_muxer_crash_once() {
-        let acc = RecordingHealthAccumulator::new();
-        let first = acc.record_event(&PipelineHealthEvent::MuxerCrashed {
-            reason: "boom".to_string(),
-        });
-        let second = acc.record_event(&PipelineHealthEvent::MuxerCrashed {
-            reason: "again".to_string(),
-        });
-        assert!(
-            first.is_some(),
-            "first muxer crash must fire critical event"
-        );
-        assert!(
-            second.is_none(),
-            "second muxer crash must not re-fire (still increments counter)"
-        );
-        let snap = acc.snapshot();
-        assert_eq!(snap.muxer_crash_count, 2);
-    }
-
-    #[test]
-    fn accumulator_fires_audio_degraded_once() {
-        let acc = RecordingHealthAccumulator::new();
-        let first = acc.record_event(&PipelineHealthEvent::AudioDegradedToVideoOnly {
-            reason: "mic died".to_string(),
-        });
-        let second = acc.record_event(&PipelineHealthEvent::AudioDegradedToVideoOnly {
-            reason: "sys died".to_string(),
-        });
-        assert!(first.is_some());
-        assert!(second.is_none());
-        let snap = acc.snapshot();
-        assert_eq!(snap.audio_degraded_count, 2);
-    }
-
-    #[test]
-    fn accumulator_accumulates_audio_gaps_and_drop_rate() {
-        let acc = RecordingHealthAccumulator::new();
-        acc.record_event(&PipelineHealthEvent::AudioGapDetected { gap_ms: 120 });
-        acc.record_event(&PipelineHealthEvent::AudioGapDetected { gap_ms: 340 });
-        acc.record_event(&PipelineHealthEvent::FrameDropRateHigh {
-            source: "screen-video".to_string(),
-            rate_pct: 12.5,
-        });
-        acc.record_event(&PipelineHealthEvent::SourceRestarting);
-        acc.record_event(&PipelineHealthEvent::SourceRestarted);
-        let snap = acc.snapshot();
-        assert_eq!(snap.audio_gaps_count, 2);
-        assert_eq!(snap.audio_gaps_total_ms, 460);
-        assert_eq!(snap.frame_drop_rate_high_count, 1);
-        assert_eq!(snap.source_restarts_count, 1);
-    }
-}
diff --git a/apps/desktop/src-tauri/src/recordings_locations.rs b/apps/desktop/src-tauri/src/recordings_locations.rs
deleted file mode 100644
index 13f3c57ea55..00000000000
--- a/apps/desktop/src-tauri/src/recordings_locations.rs
+++ /dev/null
@@ -1,655 +0,0 @@
-use std::{
-    collections::HashSet,
-    path::{Path, PathBuf},
-};
-
-use serde::{Deserialize, Serialize};
-use specta::Type;
-use tauri::{AppHandle, Manager, Wry};
-use tauri_specta::Event;
-use tracing::{info, warn};
-
-use crate::{
-    ArcLock, RecordingState, editor_window::EditorInstances, general_settings::GeneralSettingsStore,
-};
-
-/// Staging directory (inside the destination) used for cross-volume moves.
-/// Projects are copied here first, then renamed into place, so a partially
-/// copied project can never appear in the recordings list: the staging dir
-/// itself has no recording-meta.json and every scanner skips it.
-const MIGRATION_STAGING_DIR: &str = ".migrating-tmp";
-
-/// How many previously used custom folders we remember so their recordings
-/// stay visible after switching away from them.
-const MAX_PREVIOUS_PATHS: usize = 20;
-
-pub fn default_recordings_dir(app: &AppHandle) -> PathBuf {
-    app.path().app_data_dir().unwrap().join("recordings")
-}
-
-/// Every directory that may contain recordings: the active directory first,
-/// then the default location and any previously used custom folders.
-/// Deduplicated by canonical path; directories that don't exist are skipped.
-pub fn known_recordings_dirs(app: &AppHandle) -> Vec {
-    let mut dirs = vec![
-        GeneralSettingsStore::recordings_dir(app),
-        default_recordings_dir(app),
-    ];
-
-    if let Ok(Some(settings)) = GeneralSettingsStore::get(app) {
-        dirs.extend(
-            settings
-                .previous_recordings_paths
-                .iter()
-                .map(PathBuf::from)
-                .filter(|p| p.is_absolute()),
-        );
-    }
-
-    dedupe_existing_dirs(dirs)
-}
-
-fn dedupe_existing_dirs(dirs: Vec) -> Vec {
-    let mut seen = HashSet::new();
-    let mut out = Vec::new();
-    for dir in dirs {
-        if !dir.is_dir() {
-            continue;
-        }
-        // Canonicalize so the same folder reached via different spellings
-        // (trailing components, symlinks, Windows case differences) is only
-        // scanned once; otherwise every recording would be listed twice.
-        let key = dir.canonicalize().unwrap_or_else(|_| dir.clone());
-        if seen.insert(key) {
-            out.push(dir);
-        }
-    }
-    out
-}
-
-/// Records the folder we're switching away from so its recordings remain
-/// visible. `new_path` is removed from history since it's current again.
-pub fn remember_previous_recordings_path(
-    settings: &mut GeneralSettingsStore,
-    previous: Option,
-    new_path: Option<&str>,
-) {
-    if let Some(new_path) = new_path {
-        settings.previous_recordings_paths.retain(|p| p != new_path);
-    }
-
-    if let Some(previous) = previous
-        && new_path != Some(previous.as_str())
-        && !settings.previous_recordings_paths.contains(&previous)
-    {
-        settings.previous_recordings_paths.push(previous);
-        let len = settings.previous_recordings_paths.len();
-        if len > MAX_PREVIOUS_PATHS {
-            settings
-                .previous_recordings_paths
-                .drain(..len - MAX_PREVIOUS_PATHS);
-        }
-    }
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, Type, Event)]
-pub struct RecordingsMigrationProgress {
-    pub total: u32,
-    pub done: u32,
-    pub current: Option,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, Type)]
-#[serde(rename_all = "camelCase")]
-pub struct RecordingsMigrationFailure {
-    pub name: String,
-    pub error: String,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, Type)]
-#[serde(rename_all = "camelCase")]
-pub struct RecordingsMigrationSummary {
-    pub moved: u32,
-    pub skipped_in_use: u32,
-    pub failed: Vec,
-}
-
-/// Project directories that live in a known location other than the current
-/// recordings directory.
-fn migratable_projects(app: &AppHandle) -> Vec {
-    let current = GeneralSettingsStore::recordings_dir(app);
-    let current_key = current.canonicalize().unwrap_or(current);
-
-    let mut projects = Vec::new();
-    for dir in known_recordings_dirs(app) {
-        if dir.canonicalize().unwrap_or_else(|_| dir.clone()) == current_key {
-            continue;
-        }
-        let Ok(entries) = std::fs::read_dir(&dir) else {
-            continue;
-        };
-        for entry in entries.flatten() {
-            let path = entry.path();
-            if !path.is_dir() || path.extension().and_then(|e| e.to_str()) != Some("cap") {
-                continue;
-            }
-            // Never try to move a folder into itself if the user nested the
-            // new location inside an old project dir. Compare canonicalized
-            // paths on both sides (canonicalize is not prefix-stable on
-            // Windows, where it adds `\\?\`).
-            let path_key = path.canonicalize().unwrap_or_else(|_| path.clone());
-            if current_key.starts_with(&path_key) {
-                continue;
-            }
-            projects.push(path);
-        }
-    }
-    projects
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn count_recordings_to_migrate(app: AppHandle) -> Result {
-    let app = app.clone();
-    tokio::task::spawn_blocking(move || migratable_projects(&app).len() as u32)
-        .await
-        .map_err(|e| format!("Migration scan failed: {e}"))
-}
-
-static MIGRATION_IN_PROGRESS: std::sync::atomic::AtomicBool =
-    std::sync::atomic::AtomicBool::new(false);
-
-/// Releases the migration lock on every exit path, including `?` returns.
-struct MigrationLockGuard;
-
-impl Drop for MigrationLockGuard {
-    fn drop(&mut self) {
-        MIGRATION_IN_PROGRESS.store(false, std::sync::atomic::Ordering::SeqCst);
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn migrate_recordings_to_current_dir(
-    app: AppHandle,
-) -> Result {
-    // Two concurrent migrations would race on the shared staging dir and
-    // report projects the other run already moved as failures.
-    if MIGRATION_IN_PROGRESS
-        .compare_exchange(
-            false,
-            true,
-            std::sync::atomic::Ordering::SeqCst,
-            std::sync::atomic::Ordering::SeqCst,
-        )
-        .is_err()
-    {
-        return Err("A recordings migration is already in progress".to_string());
-    }
-    let _lock = MigrationLockGuard;
-
-    let dest = GeneralSettingsStore::recordings_dir(&app);
-
-    // Leftover staging from an interrupted previous run: the copies in there
-    // are incomplete by definition (their source was kept), so remove them.
-    let stale_staging = dest.join(MIGRATION_STAGING_DIR);
-    if stale_staging.exists()
-        && let Err(e) = std::fs::remove_dir_all(&stale_staging)
-    {
-        warn!("Failed to clean stale migration staging dir: {e}");
-    }
-
-    let projects = {
-        let app = app.clone();
-        tokio::task::spawn_blocking(move || migratable_projects(&app))
-            .await
-            .map_err(|e| format!("Migration scan failed: {e}"))?
-    };
-
-    let total = projects.len() as u32;
-    let mut summary = RecordingsMigrationSummary {
-        moved: 0,
-        skipped_in_use: 0,
-        failed: Vec::new(),
-    };
-
-    for (i, project) in projects.into_iter().enumerate() {
-        let name = project
-            .file_name()
-            .map(|n| n.to_string_lossy().into_owned())
-            .unwrap_or_else(|| project.display().to_string());
-
-        RecordingsMigrationProgress {
-            total,
-            done: i as u32,
-            current: Some(name.clone()),
-        }
-        .emit(&app)
-        .ok();
-
-        // Re-resolved for every project: an editor can open (or a recording
-        // stop) while earlier projects are still being copied.
-        let in_use = in_use_project_dirs(&app).await;
-
-        if project_is_in_use(&project, &in_use) {
-            info!(?project, "Migration: skipping in-use recording");
-            summary.skipped_in_use += 1;
-            continue;
-        }
-
-        let dest = dest.clone();
-        let src = project.clone();
-        let result = tokio::task::spawn_blocking(move || move_project_dir(&src, &dest))
-            .await
-            .map_err(|e| format!("Move task failed: {e}"))
-            .and_then(|r| r);
-
-        match result {
-            Ok(new_path) => {
-                info!(from = ?project, to = ?new_path, "Migration: moved recording");
-                summary.moved += 1;
-            }
-            Err(error) => {
-                warn!(?project, %error, "Migration: failed to move recording; kept in place");
-                summary
-                    .failed
-                    .push(RecordingsMigrationFailure { name, error });
-            }
-        }
-    }
-
-    RecordingsMigrationProgress {
-        total,
-        done: total,
-        current: None,
-    }
-    .emit(&app)
-    .ok();
-
-    Ok(summary)
-}
-
-async fn in_use_project_dirs(app: &AppHandle) -> HashSet {
-    let mut in_use = HashSet::new();
-
-    let state = app.state::>();
-    {
-        let state = state.read().await;
-        if let RecordingState::Active(recording) = &state.recording_state {
-            let dir = &recording.common().recording_dir;
-            in_use.insert(dir.canonicalize().unwrap_or_else(|_| dir.clone()));
-        }
-    }
-
-    for path in EditorInstances::open_project_paths(app).await {
-        in_use.insert(path.canonicalize().unwrap_or(path));
-    }
-
-    in_use
-}
-
-fn project_is_in_use(project: &Path, in_use: &HashSet) -> bool {
-    let key = project
-        .canonicalize()
-        .unwrap_or_else(|_| project.to_path_buf());
-    if in_use.contains(&key) {
-        return true;
-    }
-
-    // Belt and braces: a recording that is mid-write has InProgress status in
-    // its meta even if we failed to resolve it from app state.
-    match cap_project::RecordingMeta::load_for_project(project) {
-        Ok(meta) => match &meta.inner {
-            cap_project::RecordingMetaInner::Studio(studio) => {
-                if let cap_project::StudioRecordingMeta::MultipleSegments { inner, .. } =
-                    studio.as_ref()
-                {
-                    matches!(
-                        inner.status,
-                        Some(cap_project::StudioRecordingStatus::InProgress)
-                    )
-                } else {
-                    false
-                }
-            }
-            cap_project::RecordingMetaInner::Instant(instant) => {
-                matches!(
-                    instant,
-                    cap_project::InstantRecordingMeta::InProgress { .. }
-                )
-            }
-        },
-        // Unreadable meta is not proof of activity; old or partially written
-        // projects still deserve to be moved rather than stranded.
-        Err(_) => false,
-    }
-}
-
-/// Moves one project directory into `dest_dir`, keeping the name unique.
-/// Tries a plain rename first; on failure (typically a cross-volume move)
-/// falls back to copy + verify + delete, staged so the destination never
-/// exposes a partially copied project. The source is only removed after the
-/// copy has been verified.
-pub fn move_project_dir(src: &Path, dest_dir: &Path) -> Result {
-    let name = src
-        .file_name()
-        .and_then(|n| n.to_str())
-        .ok_or_else(|| "Invalid project directory name".to_string())?;
-
-    // A destination inside the source would make the recursive copy descend
-    // into its own output and never terminate. Refuse outright.
-    let src_key = src.canonicalize().unwrap_or_else(|_| src.to_path_buf());
-    let dest_key = dest_dir
-        .canonicalize()
-        .unwrap_or_else(|_| dest_dir.to_path_buf());
-    if dest_key.starts_with(&src_key) {
-        return Err("Destination folder is inside this recording".to_string());
-    }
-
-    let unique = cap_utils::ensure_unique_filename(name, dest_dir)?;
-    let target = dest_dir.join(&unique);
-
-    match std::fs::rename(src, &target) {
-        Ok(()) => Ok(target),
-        Err(rename_err) => copy_verify_delete(src, dest_dir, &unique).map_err(|copy_err| {
-            format!("rename failed ({rename_err}); copy fallback failed: {copy_err}")
-        }),
-    }
-}
-
-fn copy_verify_delete(src: &Path, dest_dir: &Path, unique: &str) -> Result {
-    let staging_root = dest_dir.join(MIGRATION_STAGING_DIR);
-    let staging = staging_root.join(unique);
-
-    if staging.exists() {
-        std::fs::remove_dir_all(&staging)
-            .map_err(|e| format!("Failed to clear staging dir: {e}"))?;
-    }
-    std::fs::create_dir_all(&staging_root)
-        .map_err(|e| format!("Failed to create staging dir: {e}"))?;
-
-    let cleanup = |err: String| -> String {
-        let _ = std::fs::remove_dir_all(&staging);
-        err
-    };
-
-    copy_dir_recursive(src, &staging).map_err(cleanup)?;
-
-    let src_stats = dir_stats(src).map_err(cleanup)?;
-    let staged_stats = dir_stats(&staging).map_err(cleanup)?;
-    if src_stats != staged_stats {
-        return Err(cleanup(format!(
-            "verification failed: source has {} files / {} bytes, copy has {} files / {} bytes",
-            src_stats.0, src_stats.1, staged_stats.0, staged_stats.1
-        )));
-    }
-
-    let target = dest_dir.join(unique);
-    std::fs::rename(&staging, &target)
-        .map_err(|e| cleanup(format!("Failed to finalize copied project: {e}")))?;
-
-    let _ = std::fs::remove_dir_all(&staging_root);
-
-    // The copy is verified and in place; a failure to delete the source only
-    // leaves a duplicate behind, which is safe. Don't fail the migration.
-    if let Err(e) = std::fs::remove_dir_all(src) {
-        warn!(
-            ?src,
-            "Migration: copied project but failed to remove the original: {e}"
-        );
-    }
-
-    Ok(target)
-}
-
-fn copy_dir_recursive(src: &Path, dest: &Path) -> Result<(), String> {
-    std::fs::create_dir_all(dest).map_err(|e| format!("Failed to create {dest:?}: {e}"))?;
-
-    for entry in std::fs::read_dir(src).map_err(|e| format!("Failed to read {src:?}: {e}"))? {
-        let entry = entry.map_err(|e| format!("Failed to read entry in {src:?}: {e}"))?;
-        let from = entry.path();
-        let to = dest.join(entry.file_name());
-        let file_type = entry
-            .file_type()
-            .map_err(|e| format!("Failed to stat {from:?}: {e}"))?;
-
-        if file_type.is_dir() {
-            copy_dir_recursive(&from, &to)?;
-        } else {
-            std::fs::copy(&from, &to).map_err(|e| format!("Failed to copy {from:?}: {e}"))?;
-        }
-    }
-
-    Ok(())
-}
-
-/// (file count, total bytes), following the same traversal as
-/// `copy_dir_recursive` so the two are comparable.
-fn dir_stats(dir: &Path) -> Result<(u64, u64), String> {
-    let mut files = 0u64;
-    let mut bytes = 0u64;
-
-    for entry in std::fs::read_dir(dir).map_err(|e| format!("Failed to read {dir:?}: {e}"))? {
-        let entry = entry.map_err(|e| format!("Failed to read entry in {dir:?}: {e}"))?;
-        let file_type = entry
-            .file_type()
-            .map_err(|e| format!("Failed to stat {:?}: {e}", entry.path()))?;
-
-        if file_type.is_dir() {
-            let (f, b) = dir_stats(&entry.path())?;
-            files += f;
-            bytes += b;
-        } else {
-            files += 1;
-            bytes += entry
-                .metadata()
-                .map_err(|e| format!("Failed to stat {:?}: {e}", entry.path()))?
-                .len();
-        }
-    }
-
-    Ok((files, bytes))
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    fn make_project(parent: &Path, name: &str, files: &[(&str, &str)]) -> PathBuf {
-        let dir = parent.join(name);
-        std::fs::create_dir_all(dir.join("content")).unwrap();
-        for (rel, contents) in files {
-            std::fs::write(dir.join(rel), contents).unwrap();
-        }
-        dir
-    }
-
-    #[test]
-    fn move_project_same_volume() {
-        let tmp = tempfile::tempdir().unwrap();
-        let src_dir = tmp.path().join("old");
-        let dest_dir = tmp.path().join("new");
-        std::fs::create_dir_all(&src_dir).unwrap();
-        std::fs::create_dir_all(&dest_dir).unwrap();
-
-        let project = make_project(
-            &src_dir,
-            "Test.cap",
-            &[
-                ("recording-meta.json", "{}"),
-                ("content/display.mp4", "vid"),
-            ],
-        );
-
-        let moved = move_project_dir(&project, &dest_dir).unwrap();
-
-        assert_eq!(moved, dest_dir.join("Test.cap"));
-        assert!(!project.exists());
-        assert_eq!(
-            std::fs::read_to_string(moved.join("content/display.mp4")).unwrap(),
-            "vid"
-        );
-    }
-
-    #[test]
-    fn move_project_renames_on_collision() {
-        let tmp = tempfile::tempdir().unwrap();
-        let src_dir = tmp.path().join("old");
-        let dest_dir = tmp.path().join("new");
-        std::fs::create_dir_all(&src_dir).unwrap();
-        std::fs::create_dir_all(&dest_dir).unwrap();
-
-        make_project(
-            &dest_dir,
-            "Test.cap",
-            &[("recording-meta.json", "existing")],
-        );
-        let project = make_project(&src_dir, "Test.cap", &[("recording-meta.json", "incoming")]);
-
-        let moved = move_project_dir(&project, &dest_dir).unwrap();
-
-        assert_ne!(moved, dest_dir.join("Test.cap"));
-        assert!(moved.starts_with(&dest_dir));
-        assert!(!project.exists());
-        assert_eq!(
-            std::fs::read_to_string(dest_dir.join("Test.cap/recording-meta.json")).unwrap(),
-            "existing"
-        );
-        assert_eq!(
-            std::fs::read_to_string(moved.join("recording-meta.json")).unwrap(),
-            "incoming"
-        );
-    }
-
-    #[test]
-    fn copy_fallback_moves_and_removes_source() {
-        let tmp = tempfile::tempdir().unwrap();
-        let src_dir = tmp.path().join("old");
-        let dest_dir = tmp.path().join("new");
-        std::fs::create_dir_all(&src_dir).unwrap();
-        std::fs::create_dir_all(&dest_dir).unwrap();
-
-        let project = make_project(
-            &src_dir,
-            "Test.cap",
-            &[
-                ("recording-meta.json", "{}"),
-                ("content/display.mp4", "0123456789"),
-            ],
-        );
-
-        let moved = copy_verify_delete(&project, &dest_dir, "Test.cap").unwrap();
-
-        assert_eq!(moved, dest_dir.join("Test.cap"));
-        assert!(!project.exists());
-        assert!(!dest_dir.join(MIGRATION_STAGING_DIR).exists());
-        assert_eq!(
-            std::fs::read_to_string(moved.join("content/display.mp4")).unwrap(),
-            "0123456789"
-        );
-    }
-
-    #[test]
-    fn copy_fallback_cleans_stale_staging_of_same_project() {
-        let tmp = tempfile::tempdir().unwrap();
-        let src_dir = tmp.path().join("old");
-        let dest_dir = tmp.path().join("new");
-        std::fs::create_dir_all(&src_dir).unwrap();
-
-        // A leftover partial copy from an interrupted run must not corrupt
-        // the fresh copy or trip verification.
-        let stale = dest_dir.join(MIGRATION_STAGING_DIR).join("Test.cap");
-        std::fs::create_dir_all(&stale).unwrap();
-        std::fs::write(stale.join("recording-meta.json"), "stale partial").unwrap();
-
-        let project = make_project(&src_dir, "Test.cap", &[("recording-meta.json", "fresh")]);
-
-        let moved = copy_verify_delete(&project, &dest_dir, "Test.cap").unwrap();
-
-        assert_eq!(
-            std::fs::read_to_string(moved.join("recording-meta.json")).unwrap(),
-            "fresh"
-        );
-        assert!(!project.exists());
-    }
-
-    #[test]
-    fn move_refuses_destination_inside_source() {
-        let tmp = tempfile::tempdir().unwrap();
-        let project = make_project(tmp.path(), "Test.cap", &[("recording-meta.json", "{}")]);
-        let nested_dest = project.join("content/new-storage");
-        std::fs::create_dir_all(&nested_dest).unwrap();
-
-        let result = move_project_dir(&project, &nested_dest);
-
-        assert!(result.is_err());
-        assert!(project.exists());
-        assert_eq!(
-            std::fs::read_to_string(project.join("recording-meta.json")).unwrap(),
-            "{}"
-        );
-    }
-
-    #[test]
-    fn dir_stats_detects_mismatch() {
-        let tmp = tempfile::tempdir().unwrap();
-        let a = make_project(tmp.path(), "a.cap", &[("recording-meta.json", "same")]);
-        let b = make_project(
-            tmp.path(),
-            "b.cap",
-            &[("recording-meta.json", "different!")],
-        );
-        let c = make_project(tmp.path(), "c.cap", &[("recording-meta.json", "same")]);
-
-        assert_ne!(dir_stats(&a).unwrap(), dir_stats(&b).unwrap());
-        assert_eq!(dir_stats(&a).unwrap(), dir_stats(&c).unwrap());
-    }
-
-    #[test]
-    fn dedupe_existing_dirs_skips_missing_and_duplicates() {
-        let tmp = tempfile::tempdir().unwrap();
-        let a = tmp.path().join("a");
-        let b = tmp.path().join("b");
-        std::fs::create_dir_all(&a).unwrap();
-        std::fs::create_dir_all(&b).unwrap();
-
-        let deduped = dedupe_existing_dirs(vec![
-            a.clone(),
-            b.clone(),
-            a.clone(),
-            tmp.path().join("missing"),
-        ]);
-
-        assert_eq!(deduped, vec![a, b]);
-    }
-
-    #[test]
-    fn remember_previous_path_dedupes_and_caps() {
-        let mut settings = GeneralSettingsStore::default();
-
-        remember_previous_recordings_path(&mut settings, Some("/old".into()), Some("/new"));
-        assert_eq!(settings.previous_recordings_paths, vec!["/old"]);
-
-        // Switching again to the same target doesn't duplicate history.
-        remember_previous_recordings_path(&mut settings, Some("/old".into()), Some("/new"));
-        assert_eq!(settings.previous_recordings_paths, vec!["/old"]);
-
-        // Switching back to a remembered folder removes it from history.
-        remember_previous_recordings_path(&mut settings, Some("/new".into()), Some("/old"));
-        assert_eq!(settings.previous_recordings_paths, vec!["/new"]);
-
-        // Re-picking the current folder records nothing and keeps history.
-        remember_previous_recordings_path(&mut settings, Some("/old".into()), Some("/old"));
-        assert_eq!(settings.previous_recordings_paths, vec!["/new"]);
-
-        for i in 0..(MAX_PREVIOUS_PATHS + 5) {
-            remember_previous_recordings_path(&mut settings, Some(format!("/dir{i}")), None);
-        }
-        assert_eq!(settings.previous_recordings_paths.len(), MAX_PREVIOUS_PATHS);
-        assert!(
-            settings
-                .previous_recordings_paths
-                .contains(&format!("/dir{}", MAX_PREVIOUS_PATHS + 4))
-        );
-    }
-}
diff --git a/apps/desktop/src-tauri/src/recovery.rs b/apps/desktop/src-tauri/src/recovery.rs
deleted file mode 100644
index 2538b2c4e03..00000000000
--- a/apps/desktop/src-tauri/src/recovery.rs
+++ /dev/null
@@ -1,242 +0,0 @@
-use cap_project::StudioRecordingMeta;
-use cap_recording::recovery::{RecoveryError, RecoveryManager};
-use chrono::NaiveDate;
-use serde::{Deserialize, Serialize};
-use specta::Type;
-use std::path::{Path, PathBuf};
-use tauri::{AppHandle, Emitter, Manager};
-use tracing::info;
-
-use crate::create_screenshot;
-
-const RECOVERY_CUTOFF_DATE: (i32, u32, u32) = (2025, 12, 31);
-
-pub(crate) fn finalization_storage_error(path: &Path) -> String {
-    format!(
-        "Not enough space to finish this recording. Your recording files have been kept at {}. Free up space, then click Recover Recording.",
-        path.display()
-    )
-}
-
-fn ensure_finalization_storage_with(
-    path: &Path,
-    inspect: impl FnOnce(&Path) -> std::io::Result,
-) -> Result<(), String> {
-    let storage = inspect(path)
-        .map_err(|error| format!("Could not check available space for this recording: {error}"))?;
-    if !storage.can_finalize() {
-        return Err(finalization_storage_error(path));
-    }
-    Ok(())
-}
-
-pub(crate) fn ensure_finalization_storage(
-    work_path: &Path,
-    display_path: &Path,
-) -> Result<(), String> {
-    ensure_finalization_storage_with(display_path, |_| {
-        cap_utils::disk_space::recording_storage(work_path)
-    })
-}
-
-fn is_storage_full_remux_error(error: &cap_enc_ffmpeg::remux::RemuxError) -> bool {
-    match error {
-        cap_enc_ffmpeg::remux::RemuxError::Io(error) => {
-            error.kind() == std::io::ErrorKind::StorageFull
-        }
-        cap_enc_ffmpeg::remux::RemuxError::Ffmpeg(ffmpeg::Error::Other { errno }) => {
-            *errno == ffmpeg::error::ENOSPC
-        }
-        _ => false,
-    }
-}
-
-pub(crate) fn is_storage_full_recovery_error(error: &RecoveryError) -> bool {
-    match error {
-        RecoveryError::Io(error) => error.kind() == std::io::ErrorKind::StorageFull,
-        RecoveryError::VideoConcat(error)
-        | RecoveryError::AudioConcat(error)
-        | RecoveryError::MediaMerge(error) => is_storage_full_remux_error(error),
-        _ => false,
-    }
-}
-
-fn recovery_error_message(path: &Path, error: RecoveryError) -> String {
-    let storage_full = is_storage_full_recovery_error(&error);
-    tracing::error!(project_path = %path.display(), error = %error, "Recording recovery failed");
-    if storage_full {
-        finalization_storage_error(path)
-    } else {
-        error.to_string()
-    }
-}
-
-fn parse_recording_date(pretty_name: &str) -> Option {
-    let date_part = pretty_name.strip_prefix("Cap ")?;
-    let date_str = date_part.split(" at ").next()?;
-    NaiveDate::parse_from_str(date_str, "%Y-%m-%d").ok()
-}
-
-fn is_recording_after_cutoff(pretty_name: &str) -> bool {
-    let Some(recording_date) = parse_recording_date(pretty_name) else {
-        return false;
-    };
-    let cutoff = NaiveDate::from_ymd_opt(
-        RECOVERY_CUTOFF_DATE.0,
-        RECOVERY_CUTOFF_DATE.1,
-        RECOVERY_CUTOFF_DATE.2,
-    )
-    .expect("Invalid cutoff date");
-    recording_date > cutoff
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, Type)]
-#[serde(rename_all = "camelCase")]
-pub struct IncompleteRecordingInfo {
-    pub project_path: String,
-    pub pretty_name: String,
-    pub segment_count: u32,
-    pub estimated_duration_secs: f64,
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn find_incomplete_recordings(
-    app: AppHandle,
-) -> Result, String> {
-    let recordings_dirs = crate::recordings_locations::known_recordings_dirs(&app);
-
-    let result = tokio::task::spawn_blocking(move || {
-        let incomplete_list = recordings_dirs
-            .iter()
-            .flat_map(|dir| RecoveryManager::find_incomplete(dir));
-
-        incomplete_list
-            .into_iter()
-            .filter(|recording| is_recording_after_cutoff(&recording.meta.pretty_name))
-            .map(|recording| IncompleteRecordingInfo {
-                project_path: recording.project_path.to_string_lossy().to_string(),
-                pretty_name: recording.meta.pretty_name.clone(),
-                segment_count: recording.recoverable_segments.len() as u32,
-                estimated_duration_secs: recording.estimated_duration.as_secs_f64(),
-            })
-            .collect::>()
-    })
-    .await
-    .map_err(|e| format!("Recovery scan task failed: {e}"))?;
-
-    Ok(result)
-}
-
-#[tauri::command]
-pub async fn get_recording_recovery_success(
-    app: AppHandle,
-    project_path: String,
-) -> Result, String> {
-    app.state::()
-        .recovery_success(Path::new(&project_path))
-        .await
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn recover_recording(app: AppHandle, project_path: String) -> Result {
-    let project = crate::FinalizationProject::admit(PathBuf::from(&project_path)).await?;
-    let token = app
-        .state::()
-        .start_recovering(project)?;
-    let recover_start = std::time::Instant::now();
-    let app_for_recovery = app.clone();
-    let result = crate::run_finalization_worker(token, move |project| {
-        let path = project.work_path();
-        ensure_finalization_storage(path, project.display_path())?;
-        let recording = RecoveryManager::inspect_recording(path)
-            .ok_or_else(|| "No recoverable segments found".to_string())?;
-        if recording.recoverable_segments.is_empty() {
-            return Err("No recoverable segments found".to_string());
-        }
-        let estimated_duration_secs = recording.estimated_duration.as_secs();
-        let recovered = RecoveryManager::recover(&recording)
-            .map_err(|error| recovery_error_message(project.display_path(), error))?;
-        project.validate()?;
-        let validation_took_ms = recover_start.elapsed().as_millis() as u64;
-
-        let segment_count = match &recovered.meta {
-            StudioRecordingMeta::SingleSegment { .. } => 1,
-            StudioRecordingMeta::MultipleSegments { inner } => inner.segments.len(),
-        };
-
-        info!(
-            "Recovered recording with {} segments: {}",
-            segment_count, project_path
-        );
-
-        crate::telemetry::async_capture_event(
-            &app_for_recovery,
-            crate::telemetry::AnalyticsEvent::RecordingRecovered {
-                trigger: "app_startup",
-                recovered_duration_secs: estimated_duration_secs,
-                segments_recovered: segment_count as u32,
-                validation_took_ms,
-            },
-        );
-
-        let display_output_path = match &recovered.meta {
-            StudioRecordingMeta::SingleSegment { segment } => {
-                segment.display.path.to_path(&recovered.project_path)
-            }
-            StudioRecordingMeta::MultipleSegments { inner, .. } => inner.segments[0]
-                .display
-                .path
-                .to_path(&recovered.project_path),
-        };
-
-        let screenshots_dir = recovered.project_path.join("screenshots");
-        match std::fs::create_dir_all(&screenshots_dir) {
-            Ok(()) => {
-                let display_screenshot = screenshots_dir.join("display.jpg");
-                tokio::spawn(async move {
-                    if let Err(e) = create_screenshot(display_output_path, display_screenshot, None).await {
-                        tracing::error!("Failed to create screenshot during recovery: {}", e);
-                    }
-                });
-            }
-            Err(error) => {
-                tracing::warn!(project_path = %project_path, error = %error, "Failed to create recovery screenshots directory");
-            }
-        }
-
-        if let Err(error) = app_for_recovery.emit("recording-recovery-completed", &project_path) {
-            tracing::warn!(project_path = %project_path, error = %error, "Failed to notify editors of completed recording recovery");
-        }
-
-        Ok(project_path)
-    })
-    .await;
-    if let Err(reason) = &result {
-        crate::telemetry::async_capture_event(
-            &app,
-            crate::telemetry::AnalyticsEvent::RecordingRecoveryFailed {
-                trigger: "app_startup",
-                reason: reason.clone(),
-            },
-        );
-    }
-    result
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn discard_incomplete_recording(project_path: String) -> Result<(), String> {
-    let path = PathBuf::from(&project_path);
-
-    if !path.exists() {
-        return Err("Recording path does not exist".to_string());
-    }
-
-    std::fs::remove_dir_all(&path).map_err(|e| e.to_string())?;
-
-    info!("Discarded incomplete recording: {}", project_path);
-
-    Ok(())
-}
diff --git a/apps/desktop/src-tauri/src/render_frame_event.rs b/apps/desktop/src-tauri/src/render_frame_event.rs
deleted file mode 100644
index 41092676035..00000000000
--- a/apps/desktop/src-tauri/src/render_frame_event.rs
+++ /dev/null
@@ -1,140 +0,0 @@
-use tauri::{EventId, Listener, Runtime};
-use tauri_specta::Event;
-
-use crate::RenderFrameEvent;
-
-impl RenderFrameEvent {
-    pub(crate) fn listen_checked(
-        handle: &impl Listener,
-        handler: impl Fn(Self) + Send + 'static,
-    ) -> EventId {
-        // tauri-specta's typed listener panics when a numeric JS payload becomes JSON null.
-        handle.listen_any(Self::NAME, move |event| {
-            let Ok(payload) = serde_json::from_str::(event.payload()) else {
-                return;
-            };
-            handler(payload);
-        })
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use std::sync::{Arc, Mutex};
-
-    use serde_json::{Value, json};
-    use tauri::{Emitter, EventTarget, Listener, test::mock_app};
-    use tauri_specta::Event;
-
-    use crate::RenderFrameEvent;
-
-    fn request(frame_number: u32) -> Value {
-        json!({
-            "frame_number": frame_number,
-            "fps": 60,
-            "resolution_base": { "x": 1248, "y": 702 }
-        })
-    }
-
-    #[test]
-    fn malformed_requests_do_not_dispatch_and_valid_requests_still_arrive() {
-        let app = mock_app();
-        let received = Arc::new(Mutex::new(Vec::new()));
-        let received_by_handler = received.clone();
-        let id = RenderFrameEvent::listen_checked(&app, move |event| {
-            received_by_handler.lock().unwrap().push((
-                event.frame_number,
-                event.fps,
-                event.resolution_base.x,
-                event.resolution_base.y,
-            ));
-        });
-
-        app.emit(RenderFrameEvent::NAME, request(0)).unwrap();
-        for pointer in [
-            "/frame_number",
-            "/fps",
-            "/resolution_base/x",
-            "/resolution_base/y",
-        ] {
-            for invalid in [
-                Value::Null,
-                json!(-1),
-                json!(u64::from(u32::MAX) + 1),
-                json!(1.5),
-                json!("60"),
-                json!(false),
-                json!({}),
-                json!([]),
-            ] {
-                let mut payload = request(1);
-                *payload.pointer_mut(pointer).unwrap() = invalid;
-                app.emit(RenderFrameEvent::NAME, payload).unwrap();
-            }
-        }
-        for malformed in [
-            "null",
-            "{}",
-            "[]",
-            "{",
-            "false",
-            r#"{"frame_number":0,"fps":60}"#,
-            r#"{"frame_number":0,"fps":60,"resolution_base":null}"#,
-        ] {
-            app.emit_str(RenderFrameEvent::NAME, malformed.to_string())
-                .unwrap();
-        }
-        assert_eq!(*received.lock().unwrap(), [(0, 60, 1248, 702)]);
-
-        app.emit_to(EventTarget::app(), RenderFrameEvent::NAME, request(150))
-            .unwrap();
-        app.emit_to(
-            EventTarget::labeled("editor-1"),
-            RenderFrameEvent::NAME,
-            request(u32::MAX),
-        )
-        .unwrap();
-        assert_eq!(
-            *received.lock().unwrap(),
-            [
-                (0, 60, 1248, 702),
-                (150, 60, 1248, 702),
-                (u32::MAX, 60, 1248, 702)
-            ]
-        );
-
-        app.unlisten(id);
-        app.emit(RenderFrameEvent::NAME, request(200)).unwrap();
-        assert_eq!(received.lock().unwrap().len(), 3);
-    }
-
-    #[test]
-    fn checked_listener_preserves_the_existing_u32_contract() {
-        let app = mock_app();
-        let received = Arc::new(Mutex::new(Vec::new()));
-        let received_by_handler = received.clone();
-        RenderFrameEvent::listen_checked(&app, move |event| {
-            received_by_handler.lock().unwrap().push((
-                event.frame_number,
-                event.fps,
-                event.resolution_base.x,
-                event.resolution_base.y,
-            ));
-        });
-        for value in [0, u32::MAX] {
-            app.emit(
-                RenderFrameEvent::NAME,
-                json!({
-                    "frame_number": value,
-                    "fps": value,
-                    "resolution_base": { "x": value, "y": value }
-                }),
-            )
-            .unwrap();
-        }
-        assert_eq!(
-            *received.lock().unwrap(),
-            [(0, 0, 0, 0), (u32::MAX, u32::MAX, u32::MAX, u32::MAX)]
-        );
-    }
-}
diff --git a/apps/desktop/src-tauri/src/resource.rs b/apps/desktop/src-tauri/src/resource.rs
deleted file mode 100644
index 46fdda50169..00000000000
--- a/apps/desktop/src-tauri/src/resource.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-// i've got an idea
-
-use std::{future::Future, sync::Arc};
-
-use futures::pin_mut;
-use tokio::sync::{watch, Mutex};
-
-#[derive(Clone)]
-pub struct Resource(Arc>);
-
-struct ResourceInner {
-    fetcher: Box Box>>,
-    value: watch::Receiver>,
-    value_sender: watch::Sender>,
-    current_fetch: Mutex>>,
-}
-
-impl Resource {
-    fn new(fetcher: impl Fn() -> Box + 'static> + 'static) -> Self {
-        let (tx, rx) = watch::channel(None);
-        let value = tx.clone();
-
-        let this = Self(Arc::new(ResourceInner {
-            fetcher: Box::new(fetcher),
-            value: rx,
-            value_sender: tx,
-            current_fetch: Mutex::new(None),
-        }));
-
-        tokio::spawn({
-            let this = this.clone();
-            async move { this.refetch().await }
-        });
-
-        this
-    }
-
-    pub async fn refetch(&self) -> T {
-        let this = self.clone();
-
-        tokio::spawn(async move {
-            let fut = this.0.fetcher();
-            pin_mut!(fut);
-            let value = fut.await;
-            tx.send(Some(value)).unwrap();
-        });
-    }
-
-    pub fn get(&self) -> Option<&T> {
-        self.value.borrow().as_ref()
-    }
-}
diff --git a/apps/desktop/src-tauri/src/screenshot_editor.rs b/apps/desktop/src-tauri/src/screenshot_editor.rs
deleted file mode 100644
index 0d903fdc4ca..00000000000
--- a/apps/desktop/src-tauri/src/screenshot_editor.rs
+++ /dev/null
@@ -1,1897 +0,0 @@
-use crate::PendingScreenshots;
-use crate::frame_ws::{WSFrame, create_watch_frame_ws};
-use crate::gpu_context;
-use crate::windows::{CapWindowId, ScreenshotEditorWindowIds};
-use cap_project::{
-    ProjectConfiguration, RecordingMeta, RecordingMetaInner, SingleSegment, StudioRecordingMeta,
-    VideoMeta,
-};
-use cap_rendering::{
-    DecodedFrame, DecodedSegmentFrames, FrameRenderer, ProjectUniforms, RenderVideoConstants,
-    RendererLayers, ZoomTransformTimeline,
-};
-use image::{
-    GenericImageView, ImageEncoder, RgbImage, buffer::ConvertBuffer, codecs::png::PngEncoder,
-};
-use relative_path::RelativePathBuf;
-use serde::{Deserialize, Serialize};
-use specta::Type;
-use std::io::Cursor;
-use std::str::FromStr;
-use std::sync::atomic::{AtomicU8, Ordering};
-use std::time::Instant;
-use std::{collections::HashMap, ops::Deref, path::PathBuf, sync::Arc};
-use tauri::{
-    AppHandle, Manager, Runtime, Window,
-    ipc::{CommandArg, InvokeError},
-};
-use tokio::sync::{RwLock, watch};
-use tokio_util::sync::CancellationToken;
-
-const MAX_DIMENSION: u32 = 16_384;
-
-type PendingResult = Result, String>;
-type PendingReceiver = watch::Receiver>;
-
-pub(crate) struct ScreenshotEditorInstanceDelivery {
-    instance: Arc,
-    cleanup_runtime: tokio::runtime::Handle,
-    state: AtomicU8,
-}
-
-impl ScreenshotEditorInstanceDelivery {
-    const PENDING: u8 = 0;
-    const ADOPTED: u8 = 1;
-    const RETIRED: u8 = 2;
-
-    fn new(
-        instance: Arc,
-        cleanup_runtime: tokio::runtime::Handle,
-    ) -> Arc {
-        Arc::new(Self {
-            instance,
-            cleanup_runtime,
-            state: AtomicU8::new(Self::PENDING),
-        })
-    }
-
-    fn adopt_into(
-        &self,
-        instances: &mut HashMap>,
-        window_label: &str,
-    ) -> Result, String> {
-        self.state
-            .compare_exchange(
-                Self::PENDING,
-                Self::ADOPTED,
-                Ordering::AcqRel,
-                Ordering::Acquire,
-            )
-            .map_err(|_| "Editor instance delivery is no longer pending".to_string())?;
-        let instance = self.instance.clone();
-        let _ = instances.insert(window_label.to_string(), instance.clone());
-        Ok(instance)
-    }
-
-    fn retire(&self) -> Option> {
-        self.state
-            .compare_exchange(
-                Self::PENDING,
-                Self::RETIRED,
-                Ordering::AcqRel,
-                Ordering::Acquire,
-            )
-            .ok()?;
-        let instance = self.instance.clone();
-        Some(self.cleanup_runtime.spawn(async move {
-            instance.dispose().await;
-        }))
-    }
-
-    async fn dispose(&self) {
-        if let Some(cleanup) = self.retire() {
-            let _ = cleanup.await;
-        }
-    }
-}
-
-impl Drop for ScreenshotEditorInstanceDelivery {
-    fn drop(&mut self) {
-        drop(self.retire());
-    }
-}
-
-#[derive(Clone)]
-pub struct ScreenshotConfigUpdate {
-    pub revision: u32,
-    pub config: ProjectConfiguration,
-}
-
-pub struct ScreenshotEditorInstance {
-    pub ws_port: u16,
-    pub ws_shutdown_token: CancellationToken,
-    pub config_tx: watch::Sender,
-    pub path: PathBuf,
-    pub pretty_name: String,
-    pub image_width: u32,
-    pub image_height: u32,
-    source_rgba: Arc>,
-}
-
-impl ScreenshotEditorInstance {
-    pub async fn dispose(&self) {
-        self.ws_shutdown_token.cancel();
-    }
-}
-
-impl Drop for ScreenshotEditorInstance {
-    fn drop(&mut self) {
-        self.ws_shutdown_token.cancel();
-    }
-}
-
-#[derive(Clone, Default)]
-pub struct PendingScreenshotEditorInstances(Arc>>);
-
-#[derive(Clone)]
-pub struct ScreenshotEditorInstances(Arc>>>);
-
-pub struct WindowScreenshotEditorInstance(pub Arc);
-
-impl specta::function::FunctionArg for WindowScreenshotEditorInstance {
-    fn to_datatype(_: &mut specta::TypeMap) -> Option {
-        None
-    }
-}
-
-impl Deref for WindowScreenshotEditorInstance {
-    type Target = Arc;
-
-    fn deref(&self) -> &Self::Target {
-        &self.0
-    }
-}
-
-impl<'de, R: Runtime> CommandArg<'de, R> for WindowScreenshotEditorInstance {
-    fn from_command(command: tauri::ipc::CommandItem<'de, R>) -> Result {
-        let window = Window::from_command(command)?;
-
-        let instances = window.state::();
-        let instance = futures::executor::block_on(instances.0.read());
-
-        if let Some(instance) = instance.get(window.label()).cloned() {
-            Ok(Self(instance))
-        } else {
-            Err(InvokeError::from(format!(
-                "no ScreenshotEditor instance for window '{}'",
-                window.label(),
-            )))
-        }
-    }
-}
-
-impl ScreenshotEditorInstances {
-    async fn create_standalone_instance(
-        app_handle: &AppHandle,
-        path: PathBuf,
-        start_preview: bool,
-    ) -> Result, String> {
-        let create_started = Instant::now();
-
-        let (data, width, height) = {
-            let key = path
-                .parent()
-                .map(|p| p.to_string_lossy().to_string())
-                .unwrap_or_default();
-            let pending = app_handle.try_state::();
-            let pending_frame = pending.and_then(|p| p.remove(&key));
-
-            if let Some(frame) = pending_frame {
-                let width = frame.width;
-                let height = frame.height;
-                let channels = frame.channels;
-
-                if width > MAX_DIMENSION || height > MAX_DIMENSION {
-                    return Err(format!("Image dimensions exceed maximum: {width}x{height}"));
-                }
-
-                let expected_len = width
-                    .checked_mul(height)
-                    .and_then(|p| p.checked_mul(channels))
-                    .ok_or_else(|| format!("Image dimensions overflow: {width}x{height}"))?;
-                let expected_len = usize::try_from(expected_len)
-                    .map_err(|_| format!("Image size too large: {width}x{height}"))?;
-
-                let data = frame.data;
-
-                if data.len() != expected_len {
-                    return Err(format!(
-                        "Image data length mismatch: expected {expected_len} bytes for {width}x{height}x{channels} frame, got {}",
-                        data.len()
-                    ));
-                }
-
-                let rgba_data = if channels == 4 {
-                    let rgba_img = image::RgbaImage::from_raw(width, height, data)
-                        .ok_or_else(|| format!("Invalid RGBA data for {width}x{height} frame"))?;
-                    rgba_img.into_raw()
-                } else {
-                    let rgb_img = RgbImage::from_raw(width, height, data)
-                        .ok_or_else(|| format!("Invalid RGB data for {width}x{height} frame"))?;
-                    let rgba_img: image::RgbaImage = rgb_img.convert();
-                    rgba_img.into_raw()
-                };
-                (rgba_data, width, height)
-            } else {
-                let image_path = if path.is_dir() {
-                    let original = path.join("original.png");
-                    if original.exists() {
-                        original
-                    } else {
-                        std::fs::read_dir(&path)
-                            .ok()
-                            .and_then(|dir| {
-                                dir.flatten()
-                                    .find(|e| {
-                                        e.path().extension().and_then(|s| s.to_str()) == Some("png")
-                                    })
-                                    .map(|e| e.path())
-                            })
-                            .ok_or_else(|| format!("No PNG file found in directory: {path:?}"))?
-                    }
-                } else {
-                    path.clone()
-                };
-
-                let img =
-                    image::open(&image_path).map_err(|e| format!("Failed to open image: {e}"))?;
-                let (w, h) = img.dimensions();
-
-                if w > MAX_DIMENSION || h > MAX_DIMENSION {
-                    return Err(format!("Image dimensions exceed maximum: {w}x{h}"));
-                }
-
-                w.checked_mul(h)
-                    .and_then(|p| p.checked_mul(4))
-                    .ok_or_else(|| format!("Image dimensions overflow: {w}x{h}"))?;
-
-                (img.to_rgba8().into_raw(), w, h)
-            }
-        };
-
-        tracing::info!(
-            elapsed_ms = create_started.elapsed().as_millis() as u64,
-            width,
-            height,
-            "screenshot_editor timing: source image ready"
-        );
-
-        let cap_dir = if path.extension().and_then(|s| s.to_str()) == Some("cap") {
-            Some(path.clone())
-        } else if let Some(parent) = path.parent() {
-            if parent.extension().and_then(|s| s.to_str()) == Some("cap") {
-                Some(parent.to_path_buf())
-            } else {
-                None
-            }
-        } else {
-            None
-        };
-
-        let (recording_meta, loaded_config) = if let Some(cap_dir) = &cap_dir {
-            let meta = RecordingMeta::load_for_project(cap_dir).ok();
-            let config = ProjectConfiguration::load(cap_dir).ok();
-            (meta, config)
-        } else {
-            (None, None)
-        };
-
-        if !start_preview {
-            let pretty_name = recording_meta
-                .as_ref()
-                .map(|meta| meta.pretty_name.clone())
-                .unwrap_or_else(|| "Screenshot".to_string());
-            let (config_tx, _) = watch::channel(ScreenshotConfigUpdate {
-                revision: 0,
-                config: loaded_config.unwrap_or_default(),
-            });
-
-            return Ok(Arc::new(ScreenshotEditorInstance {
-                ws_port: 0,
-                ws_shutdown_token: CancellationToken::new(),
-                config_tx,
-                path,
-                pretty_name,
-                image_width: width,
-                image_height: height,
-                source_rgba: Arc::new(data),
-            }));
-        }
-
-        let (frame_tx, frame_rx) = watch::channel(None);
-        let (ws_port, ws_shutdown_token) =
-            create_watch_frame_ws(frame_rx, Default::default()).await;
-        let ws_guard = ws_shutdown_token.clone().drop_guard();
-        if ws_port == 0 {
-            return Err("Failed to start screenshot editor frame websocket".to_string());
-        }
-
-        let recording_meta = if let Some(meta) = recording_meta {
-            meta
-        } else {
-            let filename = path
-                .file_name()
-                .ok_or_else(|| "Invalid path".to_string())?
-                .to_string_lossy();
-            let relative_path = RelativePathBuf::from(filename.as_ref());
-            let video_meta = VideoMeta {
-                path: relative_path.clone(),
-                fps: 30,
-                start_time: Some(0.0),
-                device_id: None,
-            };
-            let segment = SingleSegment {
-                display: video_meta.clone(),
-                camera: None,
-                audio: None,
-                cursor: None,
-            };
-            let studio_meta = StudioRecordingMeta::SingleSegment { segment };
-            RecordingMeta {
-                platform: None,
-                project_path: path.parent().unwrap().to_path_buf(),
-                pretty_name: "Screenshot".to_string(),
-                sharing: None,
-                inner: RecordingMetaInner::Studio(Box::new(studio_meta.clone())),
-                upload: None,
-            }
-        };
-
-        let (shared, background_cache) = if let Some(gpu) = gpu_context::get_shared_gpu().await {
-            (
-                cap_rendering::SharedWgpuDevice {
-                    instance: (*gpu.instance).clone(),
-                    adapter: (*gpu.adapter).clone(),
-                    device: (*gpu.device).clone(),
-                    queue: (*gpu.queue).clone(),
-                    is_software_adapter: gpu.is_software_adapter,
-                },
-                gpu.background_cache.clone(),
-            )
-        } else {
-            let instance = cap_rendering::create_wgpu_instance().await;
-            let force_software_adapter = cap_rendering::force_software_wgpu_adapter();
-            let hardware_adapter = if force_software_adapter {
-                None
-            } else {
-                instance
-                    .request_adapter(&wgpu::RequestAdapterOptions {
-                        power_preference: wgpu::PowerPreference::HighPerformance,
-                        force_fallback_adapter: false,
-                        compatible_surface: None,
-                    })
-                    .await
-                    .ok()
-            };
-            let adapter = match hardware_adapter {
-                Some(adapter) => adapter,
-                None => instance
-                    .request_adapter(&wgpu::RequestAdapterOptions {
-                        power_preference: wgpu::PowerPreference::LowPower,
-                        force_fallback_adapter: true,
-                        compatible_surface: None,
-                    })
-                    .await
-                    .map_err(|_| "No GPU adapter found".to_string())?,
-            };
-            let adapter_info = adapter.get_info();
-            let is_software_adapter = cap_rendering::is_software_wgpu_adapter(&adapter_info);
-
-            let (device, queue) = adapter
-                .request_device(&wgpu::DeviceDescriptor {
-                    label: Some("cap-rendering-device"),
-                    required_features: wgpu::Features::empty(),
-                    ..Default::default()
-                })
-                .await
-                .map_err(|e| e.to_string())?;
-            (
-                cap_rendering::SharedWgpuDevice {
-                    instance,
-                    adapter,
-                    device,
-                    queue,
-                    is_software_adapter,
-                },
-                Arc::new(cap_rendering::BackgroundTextureCache::default()),
-            )
-        };
-
-        let options = cap_rendering::RenderOptions {
-            screen_size: cap_project::XY::new(width, height),
-            camera_size: None,
-            preserve_screen_alpha: true,
-        };
-
-        let studio_meta = match &recording_meta.inner {
-            RecordingMetaInner::Studio(meta) => meta.clone(),
-            _ => return Err("Invalid recording meta for screenshot".to_string()),
-        };
-
-        let constants = RenderVideoConstants::from_shared_device(
-            shared,
-            options,
-            *studio_meta,
-            recording_meta.clone(),
-            background_cache,
-        );
-
-        tracing::info!(
-            elapsed_ms = create_started.elapsed().as_millis() as u64,
-            "screenshot_editor timing: gpu + render constants ready"
-        );
-
-        let (config_tx, mut config_rx) = watch::channel(ScreenshotConfigUpdate {
-            revision: 0,
-            config: loaded_config.unwrap_or_default(),
-        });
-
-        let render_shutdown_token = ws_shutdown_token.clone();
-
-        let source_rgba = Arc::new(data);
-
-        let instance = Arc::new(ScreenshotEditorInstance {
-            ws_port,
-            ws_shutdown_token,
-            config_tx,
-            path: path.clone(),
-            pretty_name: recording_meta.pretty_name.clone(),
-            image_width: width,
-            image_height: height,
-            source_rgba: source_rgba.clone(),
-        });
-        ws_guard.disarm();
-
-        let decoded_frame = DecodedFrame::new(source_rgba.as_ref().clone(), width, height);
-
-        tokio::spawn(async move {
-            let layers_started = Instant::now();
-            let mut frame_renderer = FrameRenderer::new(&constants);
-            let mut layers = RendererLayers::new_with_options(
-                &constants.device,
-                &constants.queue,
-                constants.is_software_adapter,
-            );
-            tracing::info!(
-                layers_init_ms = layers_started.elapsed().as_millis() as u64,
-                total_ms = create_started.elapsed().as_millis() as u64,
-                "screenshot_editor timing: renderer layers initialized"
-            );
-            let shutdown_token = render_shutdown_token;
-            let mut current_update = config_rx.borrow().clone();
-            let mut current_config = std::sync::Arc::new(current_update.config.clone());
-            let mut current_revision = current_update.revision;
-            let mut first_frame_logged = false;
-
-            loop {
-                if shutdown_token.is_cancelled() {
-                    break;
-                }
-                let segment_frames = DecodedSegmentFrames {
-                    screen_size: cap_project::XY::new(
-                        decoded_frame.width(),
-                        decoded_frame.height(),
-                    ),
-                    screen_frame: Some(DecodedFrame::new(
-                        decoded_frame.data().to_vec(),
-                        decoded_frame.width(),
-                        decoded_frame.height(),
-                    )),
-                    camera_frame: None,
-                    segment_time: 0.0,
-                    recording_time: 0.0,
-                    segment_has_camera: false,
-                };
-
-                let (base_w, base_h) =
-                    ProjectUniforms::get_base_size(&constants.options, ¤t_config);
-
-                let cursor_events = cap_project::CursorEvents::default();
-                let mut zoom_timeline = ZoomTransformTimeline::from_project(
-                    ¤t_config,
-                    &cursor_events,
-                    0.0,
-                    constants.options.screen_size,
-                );
-                zoom_timeline.ensure_precomputed_until(1.0 / 30.0);
-
-                let uniforms = ProjectUniforms::new(
-                    &constants,
-                    ¤t_config,
-                    0,
-                    30,
-                    cap_project::XY::new(base_w, base_h),
-                    &cursor_events,
-                    &segment_frames,
-                    0.0,
-                    &zoom_timeline,
-                );
-
-                let render_started = Instant::now();
-                let rendered_frame = frame_renderer
-                    .render_immediate(
-                        segment_frames,
-                        uniforms,
-                        &cap_project::CursorEvents::default(),
-                        true,
-                        &mut layers,
-                    )
-                    .await;
-
-                match rendered_frame {
-                    Ok(frame) => {
-                        if !first_frame_logged {
-                            first_frame_logged = true;
-                            tracing::info!(
-                                render_ms = render_started.elapsed().as_millis() as u64,
-                                total_ms = create_started.elapsed().as_millis() as u64,
-                                frame_width = frame.width,
-                                frame_height = frame.height,
-                                frame_bytes = frame.data.len(),
-                                "screenshot_editor timing: first frame rendered + sent"
-                            );
-                        }
-                        let _ = frame_tx.send(Some(std::sync::Arc::new(WSFrame {
-                            data: frame.data.into(),
-                            width: frame.width,
-                            height: frame.height,
-                            stride: frame.padded_bytes_per_row,
-                            frame_number: current_revision,
-                            target_time_ns: frame.target_time_ns,
-                            format: crate::frame_ws::WSFrameFormat::Rgba,
-                            created_at: Instant::now(),
-                        })));
-                    }
-                    Err(e) => {
-                        tracing::error!("Failed to render screenshot frame: {e}");
-                    }
-                }
-
-                tokio::select! {
-                    res = config_rx.changed() => {
-                        if res.is_err() {
-                            break;
-                        }
-                        current_update = config_rx.borrow().clone();
-                        current_revision = current_update.revision;
-                        current_config = std::sync::Arc::new(current_update.config.clone());
-                    }
-                    _ = shutdown_token.cancelled() => {
-                        break;
-                    }
-                }
-            }
-            let _ = frame_tx.send(None);
-        });
-
-        Ok(instance)
-    }
-
-    pub async fn get_or_create(
-        window: &Window,
-        path: PathBuf,
-    ) -> Result, String> {
-        let CapWindowId::ScreenshotEditor { id } =
-            CapWindowId::from_str(window.label()).map_err(|error| error.to_string())?
-        else {
-            return Err("Invalid screenshot editor window".to_string());
-        };
-        let window_ids = ScreenshotEditorWindowIds::get(window.app_handle());
-        with_registered_screenshot_editor(&window_ids, id, || ())?;
-        let instances = match window.try_state::() {
-            Some(s) => (*s).clone(),
-            None => {
-                window.manage(Self(Arc::new(RwLock::new(HashMap::new()))));
-                (*window.state::()).clone()
-            }
-        };
-        let mut instances = instances.0.write().await;
-        if let Some(instance) = with_registered_screenshot_editor(&window_ids, id, || {
-            instances.get(window.label()).map(|instance| {
-                let instance = instance.clone();
-                let config = instance.config_tx.borrow().clone();
-                let _ = instance.config_tx.send(config);
-                instance
-            })
-        })? {
-            return Ok(instance);
-        }
-
-        let pending = PendingScreenshotEditorInstances::get(window.app_handle());
-        let mut prewarmed = None;
-        if let Some(mut prewarmed_rx) = pending.take_prewarmed(window.label()).await {
-            loop {
-                let result = prewarmed_rx.borrow_and_update().clone();
-                if let Some(result) = result {
-                    prewarmed = Some(result?);
-                    break;
-                }
-                if prewarmed_rx.changed().await.is_err() {
-                    break;
-                }
-            }
-        }
-        let instance = match prewarmed {
-            Some(instance) => instance,
-            None => {
-                with_registered_screenshot_editor(&window_ids, id, || ())?;
-                let cleanup_runtime = tokio::runtime::Handle::current();
-                let instance =
-                    Self::create_standalone_instance(window.app_handle(), path.clone(), true)
-                        .await?;
-                ScreenshotEditorInstanceDelivery::new(instance, cleanup_runtime)
-            }
-        };
-        let published = with_registered_screenshot_editor(&window_ids, id, || {
-            instance.adopt_into(&mut instances, window.label())
-        });
-        drop(instances);
-        let instance = match published {
-            Ok(Ok(instance)) => instance,
-            Ok(Err(error)) | Err(error) => {
-                instance.dispose().await;
-                return Err(error);
-            }
-        };
-        Ok(instance)
-    }
-
-    pub async fn remove(window: Window) {
-        let instances = match window.try_state::() {
-            Some(s) => (*s).clone(),
-            None => return,
-        };
-
-        let mut instances = instances.0.write().await;
-        if let Some(instance) = instances.remove(window.label()) {
-            instance.dispose().await;
-        }
-    }
-
-    pub async fn dispose_all(app: &AppHandle) {
-        let Some(instances) = app.try_state::() else {
-            return;
-        };
-
-        let instances = {
-            let mut instances = instances.0.write().await;
-            std::mem::take(&mut *instances)
-        };
-
-        let count = instances.len();
-        for (_, instance) in instances {
-            instance.dispose().await;
-        }
-
-        if count > 0 {
-            tracing::info!(
-                count,
-                "Disposed screenshot editor instances during app exit"
-            );
-        }
-    }
-}
-
-fn with_registered_screenshot_editor(
-    window_ids: &ScreenshotEditorWindowIds,
-    id: u32,
-    action: impl FnOnce() -> T,
-) -> Result {
-    let ids = window_ids.ids.lock().map_err(|error| error.to_string())?;
-    if !ids.iter().any(|(_, registered_id)| *registered_id == id) {
-        return Err("Screenshot editor window is no longer registered".to_string());
-    }
-    Ok(action())
-}
-
-impl PendingScreenshotEditorInstances {
-    pub fn get(app: &AppHandle) -> Self {
-        match app.try_state::() {
-            Some(s) => (*s).clone(),
-            None => {
-                let pending = Self::default();
-                app.manage(pending);
-                (*app.state::()).clone()
-            }
-        }
-    }
-
-    pub async fn start_prewarm(app: &AppHandle, window_label: String, path: PathBuf) {
-        let Ok(CapWindowId::ScreenshotEditor { id }) = CapWindowId::from_str(&window_label) else {
-            return;
-        };
-        let window_ids = ScreenshotEditorWindowIds::get(app);
-        let pending = Self::get(app);
-        let app = app.clone();
-        let tx = {
-            let mut instances = pending.0.write().await;
-            let admitted = with_registered_screenshot_editor(&window_ids, id, || {
-                use std::collections::hash_map::Entry;
-                match instances.entry(window_label) {
-                    Entry::Vacant(entry) => {
-                        let (tx, rx) = watch::channel(None);
-                        entry.insert(rx);
-                        Some(tx)
-                    }
-                    Entry::Occupied(_) => None,
-                }
-            });
-            match admitted {
-                Ok(Some(tx)) => tx,
-                Ok(None) => return,
-                Err(error) => {
-                    tracing::debug!(%error, "Skipping prewarm for a retired screenshot editor");
-                    return;
-                }
-            }
-        };
-
-        let cleanup_runtime = tokio::runtime::Handle::current();
-        tokio::spawn(async move {
-            let result = ScreenshotEditorInstances::create_standalone_instance(&app, path, true)
-                .await
-                .map(|instance| ScreenshotEditorInstanceDelivery::new(instance, cleanup_runtime));
-            tx.send(Some(result)).ok();
-        });
-    }
-
-    pub async fn take_prewarmed(&self, window_label: &str) -> Option {
-        let mut instances = self.0.write().await;
-        instances.remove(window_label)
-    }
-
-    pub async fn cancel_prewarm(&self, window_label: &str) {
-        let mut instances = self.0.write().await;
-        if let Some(mut rx) = instances.remove(window_label) {
-            tokio::spawn(async move {
-                let timeout = tokio::time::timeout(std::time::Duration::from_secs(10), async {
-                    loop {
-                        let instance_to_dispose = {
-                            let borrowed = rx.borrow_and_update().clone();
-                            match borrowed {
-                                Some(Ok(instance)) => Some(instance),
-                                Some(Err(_)) => break,
-                                None => None,
-                            }
-                        };
-
-                        if let Some(instance) = instance_to_dispose {
-                            instance.dispose().await;
-                            break;
-                        }
-
-                        if rx.changed().await.is_err() {
-                            break;
-                        }
-                    }
-                });
-                if timeout.await.is_err() {
-                    tracing::warn!(
-                        "Timed out waiting for prewarmed screenshot editor instance to complete for cleanup"
-                    );
-                }
-            });
-        }
-    }
-
-    pub async fn dispose_all(app: &AppHandle) {
-        let Some(pending) = app.try_state::() else {
-            return;
-        };
-
-        let pending = {
-            let mut instances = pending.0.write().await;
-            std::mem::take(&mut *instances)
-        };
-
-        let count = pending.len();
-        for (_, mut rx) in pending {
-            let result = tokio::time::timeout(std::time::Duration::from_millis(500), async {
-                loop {
-                    let instance_to_dispose = {
-                        let borrowed = rx.borrow_and_update().clone();
-                        match borrowed {
-                            Some(Ok(instance)) => Some(instance),
-                            Some(Err(_)) => break,
-                            None => None,
-                        }
-                    };
-
-                    if let Some(instance) = instance_to_dispose {
-                        instance.dispose().await;
-                        break;
-                    }
-
-                    if rx.changed().await.is_err() {
-                        break;
-                    }
-                }
-            })
-            .await;
-
-            if result.is_err() {
-                tracing::warn!(
-                    "Timed out disposing pending screenshot editor instance during app exit"
-                );
-            }
-        }
-
-        if count > 0 {
-            tracing::info!(
-                count,
-                "Disposed pending screenshot editor instances during app exit"
-            );
-        }
-    }
-}
-
-#[derive(Serialize, Type, Debug)]
-#[serde(rename_all = "camelCase")]
-pub struct SerializedScreenshotEditorInstance {
-    pub frames_socket_url: String,
-    pub path: PathBuf,
-    pub config: Option,
-    pub pretty_name: String,
-    pub image_width: u32,
-    pub image_height: u32,
-}
-
-#[derive(Serialize, Type, Debug)]
-#[serde(rename_all = "camelCase")]
-pub struct ScreenshotProjectExport {
-    pub image_bytes: Vec,
-    pub config: ProjectConfiguration,
-    pub image_width: u32,
-    pub image_height: u32,
-}
-
-#[derive(Clone, Copy, Deserialize, Serialize, Type, Debug)]
-#[serde(rename_all = "camelCase")]
-pub struct ScreenshotOcrRegion {
-    pub x: u32,
-    pub y: u32,
-    pub width: u32,
-    pub height: u32,
-}
-
-#[derive(Clone, Serialize, Type, Debug)]
-#[serde(rename_all = "camelCase")]
-pub struct ScreenshotOcrLine {
-    pub text: String,
-    pub confidence: Option,
-    pub bounds: ScreenshotOcrRegion,
-}
-
-#[derive(Clone, Serialize, Type, Debug)]
-#[serde(rename_all = "camelCase")]
-pub struct ScreenshotOcrResult {
-    pub text: String,
-    pub lines: Vec,
-    pub engine: String,
-}
-
-struct ScreenshotOcrImage {
-    bgra: Vec,
-    width: u32,
-    height: u32,
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn create_screenshot_editor_instance(
-    window: Window,
-) -> Result {
-    let CapWindowId::ScreenshotEditor { id } =
-        CapWindowId::from_str(window.label()).map_err(|e| e.to_string())?
-    else {
-        return Err("Invalid window".to_string());
-    };
-
-    let path = {
-        let window_ids = ScreenshotEditorWindowIds::get(window.app_handle());
-        let window_ids = window_ids.ids.lock().unwrap();
-        let Some((path, _)) = window_ids.iter().find(|(_, _id)| *_id == id) else {
-            return Err("Screenshot editor instance not found".to_string());
-        };
-        path.clone()
-    };
-
-    let instance = ScreenshotEditorInstances::get_or_create(&window, path).await?;
-    let config = instance.config_tx.borrow().config.clone();
-
-    Ok(SerializedScreenshotEditorInstance {
-        frames_socket_url: format!("ws://localhost:{}", instance.ws_port),
-        path: instance.path.clone(),
-        config: Some(config),
-        pretty_name: instance.pretty_name.clone(),
-        image_width: instance.image_width,
-        image_height: instance.image_height,
-    })
-}
-
-/// Renders one tiny throwaway frame on the shared GPU at startup so the Metal
-/// render pipelines are compiled before the user opens the editor. On Apple GPUs
-/// pipeline *creation* is cheap but the driver defers shader compilation to the
-/// first draw, which was costing ~3.5s on the first real frame. Doing it here moves
-/// that cost into background startup time; the compiled pipelines are cached on the
-/// shared device, so the first editor open renders immediately.
-pub async fn prewarm_screenshot_renderer() {
-    use std::sync::atomic::{AtomicBool, Ordering};
-
-    static PREWARMED: AtomicBool = AtomicBool::new(false);
-    if PREWARMED.swap(true, Ordering::SeqCst) {
-        return;
-    }
-
-    let Some(gpu) = gpu_context::get_shared_gpu().await else {
-        return;
-    };
-
-    let _ = tokio::task::spawn_blocking(cap_rendering::prewarm_fonts).await;
-
-    let started = Instant::now();
-
-    let shared = cap_rendering::SharedWgpuDevice {
-        instance: (*gpu.instance).clone(),
-        adapter: (*gpu.adapter).clone(),
-        device: (*gpu.device).clone(),
-        queue: (*gpu.queue).clone(),
-        is_software_adapter: gpu.is_software_adapter,
-    };
-
-    let width = 64u32;
-    let height = 64u32;
-
-    let video_meta = VideoMeta {
-        path: RelativePathBuf::from("prewarm.png"),
-        fps: 30,
-        start_time: Some(0.0),
-        device_id: None,
-    };
-    let studio_meta = StudioRecordingMeta::SingleSegment {
-        segment: SingleSegment {
-            display: video_meta,
-            camera: None,
-            audio: None,
-            cursor: None,
-        },
-    };
-    let recording_meta = RecordingMeta {
-        platform: None,
-        project_path: std::env::temp_dir(),
-        pretty_name: "Prewarm".to_string(),
-        sharing: None,
-        inner: RecordingMetaInner::Studio(Box::new(studio_meta.clone())),
-        upload: None,
-    };
-
-    let options = cap_rendering::RenderOptions {
-        screen_size: cap_project::XY::new(width, height),
-        camera_size: None,
-        preserve_screen_alpha: true,
-    };
-
-    let constants = RenderVideoConstants::from_shared_device(
-        shared,
-        options,
-        studio_meta,
-        recording_meta,
-        Arc::new(cap_rendering::BackgroundTextureCache::default()),
-    );
-
-    let config = std::sync::Arc::new(ProjectConfiguration::default());
-    let mut frame_renderer = FrameRenderer::new(&constants);
-    let mut layers = RendererLayers::new_with_options(
-        &constants.device,
-        &constants.queue,
-        constants.is_software_adapter,
-    );
-
-    let segment_frames = DecodedSegmentFrames {
-        screen_size: cap_project::XY::new(width, height),
-        screen_frame: Some(DecodedFrame::new(
-            vec![255u8; (width * height * 4) as usize],
-            width,
-            height,
-        )),
-        camera_frame: None,
-        segment_time: 0.0,
-        recording_time: 0.0,
-        segment_has_camera: false,
-    };
-
-    let (base_w, base_h) = ProjectUniforms::get_base_size(&constants.options, &config);
-    let cursor_events = cap_project::CursorEvents::default();
-    let mut zoom_timeline = ZoomTransformTimeline::new(
-        &[],
-        None,
-        &cursor_events,
-        config.screen_movement_spring,
-        0.0,
-        None,
-    );
-    zoom_timeline.ensure_precomputed_until(1.0 / 30.0);
-    let uniforms = ProjectUniforms::new(
-        &constants,
-        &config,
-        0,
-        30,
-        cap_project::XY::new(base_w, base_h),
-        &cursor_events,
-        &segment_frames,
-        0.0,
-        &zoom_timeline,
-    );
-
-    match frame_renderer
-        .render_immediate(
-            segment_frames,
-            uniforms,
-            &cap_project::CursorEvents::default(),
-            true,
-            &mut layers,
-        )
-        .await
-    {
-        Ok(_) => {
-            tracing::info!(
-                elapsed_ms = started.elapsed().as_millis() as u64,
-                "screenshot_editor timing: render pipeline prewarm complete"
-            );
-        }
-        Err(e) => {
-            tracing::warn!("screenshot_editor render pipeline prewarm failed: {e}");
-        }
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn prewarm_screenshot_background(path: String) -> Result<(), String> {
-    let Some(gpu) = gpu_context::get_shared_gpu().await else {
-        return Ok(());
-    };
-
-    let Some(clean_path) = cap_rendering::clean_background_path(&path) else {
-        return Ok(());
-    };
-
-    let _ = gpu
-        .background_cache
-        .ensure(&gpu.device, &gpu.queue, &clean_path)
-        .await;
-
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn update_screenshot_config(
-    instance: WindowScreenshotEditorInstance,
-    config: ProjectConfiguration,
-    save: bool,
-    revision: u32,
-) -> Result<(), String> {
-    config.validate().map_err(|error| error.to_string())?;
-
-    let _ = instance.config_tx.send(ScreenshotConfigUpdate {
-        revision,
-        config: config.clone(),
-    });
-
-    if !save {
-        return Ok(());
-    }
-
-    let Some(parent) = instance.path.parent() else {
-        return Ok(());
-    };
-
-    if parent.extension().and_then(|s| s.to_str()) == Some("cap") {
-        let path = parent.to_path_buf();
-        if let Err(e) = config.write(&path) {
-            eprintln!("Failed to save screenshot config: {e}");
-        } else {
-            println!("Saved screenshot config to {path:?}");
-        }
-    } else {
-        println!("Not saving config: parent {parent:?} is not a .cap directory");
-    }
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn recognize_screenshot_text(
-    instance: WindowScreenshotEditorInstance,
-    region: ScreenshotOcrRegion,
-) -> Result {
-    let region = clamp_screenshot_ocr_region(region, instance.image_width, instance.image_height)?;
-    let image = create_screenshot_ocr_image(
-        instance.source_rgba.as_ref(),
-        instance.image_width,
-        instance.image_height,
-        region,
-    )?;
-    let mut result = recognize_screenshot_ocr_image(image).await?;
-
-    for line in &mut result.lines {
-        line.bounds.x = line.bounds.x.saturating_add(region.x);
-        line.bounds.y = line.bounds.y.saturating_add(region.y);
-    }
-
-    Ok(result)
-}
-
-pub async fn recognize_text_from_image_path(path: &std::path::Path) -> Result {
-    let dynamic = image::open(path).map_err(|e| format!("Failed to open image for OCR: {e}"))?;
-    let rgba = dynamic.to_rgba8();
-    let width = rgba.width();
-    let height = rgba.height();
-
-    if width == 0 || height == 0 {
-        return Err("Image is empty".to_string());
-    }
-
-    let rgba_bytes = rgba.into_raw();
-    let mut bgra = vec![0u8; rgba_bytes.len()];
-    for (src, dst) in rgba_bytes.chunks_exact(4).zip(bgra.chunks_exact_mut(4)) {
-        dst[0] = src[2];
-        dst[1] = src[1];
-        dst[2] = src[0];
-        dst[3] = src[3];
-    }
-
-    let image = ScreenshotOcrImage {
-        bgra,
-        width,
-        height,
-    };
-
-    let result = recognize_screenshot_ocr_image(image).await?;
-    Ok(result.text)
-}
-
-fn clamp_screenshot_ocr_region(
-    region: ScreenshotOcrRegion,
-    image_width: u32,
-    image_height: u32,
-) -> Result {
-    if image_width == 0 || image_height == 0 {
-        return Err("Screenshot image is empty".to_string());
-    }
-
-    let x = region.x.min(image_width.saturating_sub(1));
-    let y = region.y.min(image_height.saturating_sub(1));
-    let width = region.width.min(image_width.saturating_sub(x));
-    let height = region.height.min(image_height.saturating_sub(y));
-
-    if width < 4 || height < 4 {
-        return Err("Select a larger text area".to_string());
-    }
-
-    Ok(ScreenshotOcrRegion {
-        x,
-        y,
-        width,
-        height,
-    })
-}
-
-fn create_screenshot_ocr_image(
-    source_rgba: &[u8],
-    image_width: u32,
-    image_height: u32,
-    region: ScreenshotOcrRegion,
-) -> Result {
-    let image_width = usize::try_from(image_width)
-        .map_err(|_| "Screenshot width is too large for OCR".to_string())?;
-    let image_height = usize::try_from(image_height)
-        .map_err(|_| "Screenshot height is too large for OCR".to_string())?;
-    let region_x =
-        usize::try_from(region.x).map_err(|_| "OCR region x is too large".to_string())?;
-    let region_y =
-        usize::try_from(region.y).map_err(|_| "OCR region y is too large".to_string())?;
-    let region_width =
-        usize::try_from(region.width).map_err(|_| "OCR region width is too large".to_string())?;
-    let region_height =
-        usize::try_from(region.height).map_err(|_| "OCR region height is too large".to_string())?;
-
-    let expected_len = image_width
-        .checked_mul(image_height)
-        .and_then(|pixels| pixels.checked_mul(4))
-        .ok_or_else(|| "Screenshot image is too large for OCR".to_string())?;
-
-    if source_rgba.len() != expected_len {
-        return Err("Screenshot image data is invalid for OCR".to_string());
-    }
-
-    let output_len = region_width
-        .checked_mul(region_height)
-        .and_then(|pixels| pixels.checked_mul(4))
-        .ok_or_else(|| "OCR region is too large".to_string())?;
-    let mut bgra = vec![0; output_len];
-    let source_row_bytes = image_width
-        .checked_mul(4)
-        .ok_or_else(|| "Screenshot row is too large for OCR".to_string())?;
-    let region_row_bytes = region_width
-        .checked_mul(4)
-        .ok_or_else(|| "OCR row is too large".to_string())?;
-    let region_x_bytes = region_x
-        .checked_mul(4)
-        .ok_or_else(|| "OCR region x is too large".to_string())?;
-
-    for row in 0..region_height {
-        let source_start = region_y
-            .checked_add(row)
-            .and_then(|source_row| source_row.checked_mul(source_row_bytes))
-            .and_then(|source_offset| source_offset.checked_add(region_x_bytes))
-            .ok_or_else(|| "OCR source region is invalid".to_string())?;
-        let source_end = source_start
-            .checked_add(region_row_bytes)
-            .ok_or_else(|| "OCR source region is invalid".to_string())?;
-        let output_start = row
-            .checked_mul(region_row_bytes)
-            .ok_or_else(|| "OCR output region is invalid".to_string())?;
-        let output_end = output_start
-            .checked_add(region_row_bytes)
-            .ok_or_else(|| "OCR output region is invalid".to_string())?;
-        let source_row = source_rgba
-            .get(source_start..source_end)
-            .ok_or_else(|| "OCR source region is outside the screenshot".to_string())?;
-        let output_row = bgra
-            .get_mut(output_start..output_end)
-            .ok_or_else(|| "OCR output region is invalid".to_string())?;
-
-        for (source_pixel, output_pixel) in source_row
-            .chunks_exact(4)
-            .zip(output_row.chunks_exact_mut(4))
-        {
-            output_pixel[0] = source_pixel[2];
-            output_pixel[1] = source_pixel[1];
-            output_pixel[2] = source_pixel[0];
-            output_pixel[3] = source_pixel[3];
-        }
-    }
-
-    Ok(ScreenshotOcrImage {
-        bgra,
-        width: region.width,
-        height: region.height,
-    })
-}
-
-#[cfg(target_os = "macos")]
-async fn recognize_screenshot_ocr_image(
-    image: ScreenshotOcrImage,
-) -> Result {
-    tokio::task::spawn_blocking(move || recognize_screenshot_ocr_image_macos(image))
-        .await
-        .map_err(|e| format!("OCR task failed: {e}"))?
-}
-
-#[cfg(target_os = "windows")]
-async fn recognize_screenshot_ocr_image(
-    image: ScreenshotOcrImage,
-) -> Result {
-    tokio::task::spawn_blocking(move || recognize_screenshot_ocr_image_windows(image))
-        .await
-        .map_err(|e| format!("OCR task failed: {e}"))?
-}
-
-#[cfg(not(any(target_os = "macos", target_os = "windows")))]
-async fn recognize_screenshot_ocr_image(
-    ScreenshotOcrImage {
-        bgra: _bgra,
-        width: _width,
-        height: _height,
-    }: ScreenshotOcrImage,
-) -> Result {
-    Err("OCR is only available on macOS and Windows".to_string())
-}
-
-#[cfg(target_os = "macos")]
-fn recognize_screenshot_ocr_image_macos(
-    image: ScreenshotOcrImage,
-) -> Result {
-    cidre::objc::ar_pool(|| {
-        use cidre::{cv, ns, vn};
-        use std::ffi::c_void;
-
-        extern "C" fn release_pixel_buffer_data(
-            release_ref_con: *mut c_void,
-            _base_address: *const *const c_void,
-        ) {
-            if !release_ref_con.is_null() {
-                unsafe {
-                    drop(Box::from_raw(release_ref_con.cast::>()));
-                }
-            }
-        }
-
-        let width =
-            usize::try_from(image.width).map_err(|_| "OCR image width is too large".to_string())?;
-        let height = usize::try_from(image.height)
-            .map_err(|_| "OCR image height is too large".to_string())?;
-        let bytes_per_row = width
-            .checked_mul(4)
-            .ok_or_else(|| "OCR image row is too large".to_string())?;
-        let mut data = Box::new(image.bgra);
-        let base_address = data.as_mut_ptr().cast::();
-        let release_ref_con = Box::into_raw(data).cast::();
-
-        let pixel_buffer = match cv::PixelBuf::with_bytes(
-            width,
-            height,
-            base_address,
-            bytes_per_row,
-            release_pixel_buffer_data,
-            release_ref_con,
-            cv::PixelFormat::_32_BGRA,
-            None,
-        ) {
-            Ok(pixel_buffer) => pixel_buffer,
-            Err(e) => {
-                unsafe {
-                    drop(Box::from_raw(release_ref_con.cast::>()));
-                }
-                return Err(format!("Failed to create OCR image: {e}"));
-            }
-        };
-
-        let mut request = vn::RecognizeTextRequest::new();
-        request.set_recognition_level(vn::RequestTextRecognitionLevel::Accurate);
-        request.set_uses_lang_correction(true);
-
-        if cidre::version!(macos = 13.0) {
-            request.set_revision(vn::RecognizeTextRequest::REVISION_3);
-            unsafe {
-                request.set_automatically_detects_lang(true);
-            }
-        } else {
-            request.set_revision(vn::RecognizeTextRequest::REVISION_2);
-        }
-
-        let handler = vn::ImageRequestHandler::with_cv_pixel_buf(&pixel_buffer, None)
-            .ok_or_else(|| "Failed to initialize OCR image handler".to_string())?;
-        let requests = ns::Array::::from_slice(&[&request]);
-        handler
-            .perform(&requests)
-            .map_err(|e| format!("macOS OCR failed: {e}"))?;
-
-        let observations = request.results().unwrap_or_else(ns::Array::new);
-        let mut lines = Vec::new();
-
-        for observation in observations.iter() {
-            let candidates = observation.top_candidates(1);
-            let Some(candidate) = candidates.first() else {
-                continue;
-            };
-            let text = candidate.string().to_string();
-            if text.trim().is_empty() {
-                continue;
-            }
-            lines.push(ScreenshotOcrLine {
-                text,
-                confidence: Some(candidate.confidence()),
-                bounds: normalized_macos_ocr_rect_to_region(
-                    observation.bounding_box(),
-                    image.width,
-                    image.height,
-                ),
-            });
-        }
-
-        let text = lines
-            .iter()
-            .map(|line| line.text.as_str())
-            .collect::>()
-            .join("\n");
-
-        Ok(ScreenshotOcrResult {
-            text,
-            lines,
-            engine: "macos-vision".to_string(),
-        })
-    })
-}
-
-#[cfg(target_os = "macos")]
-fn normalized_macos_ocr_rect_to_region(
-    rect: cidre::cg::Rect,
-    width: u32,
-    height: u32,
-) -> ScreenshotOcrRegion {
-    let width_f = f64::from(width);
-    let height_f = f64::from(height);
-    let left = clamp_f64(rect.origin.x * width_f, 0.0, width_f);
-    let right = clamp_f64((rect.origin.x + rect.size.width) * width_f, 0.0, width_f);
-    let top = clamp_f64(
-        (1.0 - rect.origin.y - rect.size.height) * height_f,
-        0.0,
-        height_f,
-    );
-    let bottom = clamp_f64((1.0 - rect.origin.y) * height_f, 0.0, height_f);
-    let x = left.round() as u32;
-    let y = top.round() as u32;
-    let right = right.round() as u32;
-    let bottom = bottom.round() as u32;
-
-    ScreenshotOcrRegion {
-        x,
-        y,
-        width: right.saturating_sub(x),
-        height: bottom.saturating_sub(y),
-    }
-}
-
-#[cfg(target_os = "macos")]
-fn clamp_f64(value: f64, min: f64, max: f64) -> f64 {
-    if value.is_finite() {
-        value.clamp(min, max)
-    } else {
-        min
-    }
-}
-
-#[cfg(target_os = "windows")]
-struct WindowsRuntimeGuard;
-
-#[cfg(target_os = "windows")]
-impl Drop for WindowsRuntimeGuard {
-    fn drop(&mut self) {
-        unsafe {
-            windows::Win32::System::WinRT::RoUninitialize();
-        }
-    }
-}
-
-#[cfg(target_os = "windows")]
-fn initialize_windows_runtime() -> Result {
-    use windows::Win32::System::WinRT::{RO_INIT_MULTITHREADED, RoInitialize};
-
-    unsafe { RoInitialize(RO_INIT_MULTITHREADED) }
-        .map_err(|e| format!("Windows OCR runtime failed: {e}"))?;
-
-    Ok(WindowsRuntimeGuard)
-}
-
-#[cfg(target_os = "windows")]
-fn recognize_screenshot_ocr_image_windows(
-    image: ScreenshotOcrImage,
-) -> Result {
-    use windows::Graphics::Imaging::{BitmapAlphaMode, BitmapPixelFormat, SoftwareBitmap};
-    use windows::Media::Ocr::OcrEngine;
-    use windows::Storage::Streams::DataWriter;
-
-    let _runtime = initialize_windows_runtime()?;
-
-    let max_dimension =
-        OcrEngine::MaxImageDimension().map_err(|e| format!("Windows OCR failed: {e}"))?;
-
-    if image.width > max_dimension || image.height > max_dimension {
-        return Err(format!(
-            "Select a smaller text area. Windows OCR supports up to {max_dimension}px per side"
-        ));
-    }
-
-    let width = i32::try_from(image.width).map_err(|_| "OCR image width is too large")?;
-    let height = i32::try_from(image.height).map_err(|_| "OCR image height is too large")?;
-    let writer = DataWriter::new().map_err(|e| format!("Windows OCR failed: {e}"))?;
-    writer
-        .WriteBytes(&image.bgra)
-        .map_err(|e| format!("Windows OCR failed: {e}"))?;
-    let buffer = writer
-        .DetachBuffer()
-        .map_err(|e| format!("Windows OCR failed: {e}"))?;
-    let bitmap = SoftwareBitmap::CreateCopyWithAlphaFromBuffer(
-        &buffer,
-        BitmapPixelFormat::Bgra8,
-        width,
-        height,
-        BitmapAlphaMode::Premultiplied,
-    )
-    .map_err(|e| format!("Windows OCR failed: {e}"))?;
-    let engine = OcrEngine::TryCreateFromUserProfileLanguages()
-        .map_err(|e| format!("Windows OCR is not available: {e}"))?;
-    let result = engine
-        .RecognizeAsync(&bitmap)
-        .map_err(|e| format!("Windows OCR failed: {e}"))?
-        .get()
-        .map_err(|e| format!("Windows OCR failed: {e}"))?;
-    let text = result
-        .Text()
-        .map_err(|e| format!("Windows OCR failed: {e}"))?
-        .to_string_lossy();
-    let ocr_lines = result
-        .Lines()
-        .map_err(|e| format!("Windows OCR failed: {e}"))?;
-    let mut lines = Vec::new();
-
-    for index in 0..ocr_lines
-        .Size()
-        .map_err(|e| format!("Windows OCR failed: {e}"))?
-    {
-        let line = ocr_lines
-            .GetAt(index)
-            .map_err(|e| format!("Windows OCR failed: {e}"))?;
-        let line_text = line
-            .Text()
-            .map_err(|e| format!("Windows OCR failed: {e}"))?
-            .to_string_lossy();
-        if line_text.trim().is_empty() {
-            continue;
-        }
-        let words = line
-            .Words()
-            .map_err(|e| format!("Windows OCR failed: {e}"))?;
-        let mut bounds: Option<(f32, f32, f32, f32)> = None;
-
-        for word_index in 0..words
-            .Size()
-            .map_err(|e| format!("Windows OCR failed: {e}"))?
-        {
-            let rect = words
-                .GetAt(word_index)
-                .and_then(|word| word.BoundingRect())
-                .map_err(|e| format!("Windows OCR failed: {e}"))?;
-            bounds = Some(match bounds {
-                Some((left, top, right, bottom)) => (
-                    left.min(rect.X),
-                    top.min(rect.Y),
-                    right.max(rect.X + rect.Width),
-                    bottom.max(rect.Y + rect.Height),
-                ),
-                None => (rect.X, rect.Y, rect.X + rect.Width, rect.Y + rect.Height),
-            });
-        }
-
-        lines.push(ScreenshotOcrLine {
-            text: line_text,
-            confidence: None,
-            bounds: bounds
-                .map(windows_ocr_bounds_to_region)
-                .unwrap_or(ScreenshotOcrRegion {
-                    x: 0,
-                    y: 0,
-                    width: 0,
-                    height: 0,
-                }),
-        });
-    }
-
-    Ok(ScreenshotOcrResult {
-        text,
-        lines,
-        engine: "windows-media-ocr".to_string(),
-    })
-}
-
-#[cfg(target_os = "windows")]
-fn windows_ocr_bounds_to_region(
-    (left, top, right, bottom): (f32, f32, f32, f32),
-) -> ScreenshotOcrRegion {
-    let x = clamp_f32_to_u32(left);
-    let y = clamp_f32_to_u32(top);
-    let right = clamp_f32_to_u32(right);
-    let bottom = clamp_f32_to_u32(bottom);
-
-    ScreenshotOcrRegion {
-        x,
-        y,
-        width: right.saturating_sub(x),
-        height: bottom.saturating_sub(y),
-    }
-}
-
-#[cfg(target_os = "windows")]
-fn clamp_f32_to_u32(value: f32) -> u32 {
-    if value.is_finite() && value > 0.0 {
-        value.round().min(u32::MAX as f32) as u32
-    } else {
-        0
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn render_screenshot_for_export(
-    instance: WindowScreenshotEditorInstance,
-) -> Result, String> {
-    render_screenshot_png(&instance).await
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn render_screenshot_project_for_export(
-    app: AppHandle,
-    path: PathBuf,
-) -> Result {
-    let instance = ScreenshotEditorInstances::create_standalone_instance(&app, path, false).await?;
-    let config = instance.config_tx.borrow().config.clone();
-    let image_width = instance.image_width;
-    let image_height = instance.image_height;
-
-    let result =
-        render_screenshot_png(&instance)
-            .await
-            .map(|image_bytes| ScreenshotProjectExport {
-                image_bytes,
-                config,
-                image_width,
-                image_height,
-            });
-    instance.dispose().await;
-    result
-}
-
-pub async fn render_screenshot_png(instance: &ScreenshotEditorInstance) -> Result, String> {
-    let path = instance.path.clone();
-    let config = std::sync::Arc::new(instance.config_tx.borrow().config.clone());
-    let width = instance.image_width;
-    let height = instance.image_height;
-
-    if width > MAX_DIMENSION || height > MAX_DIMENSION {
-        return Err(format!("Image dimensions exceed maximum: {width}x{height}"));
-    }
-
-    let data = instance.source_rgba.as_ref().clone();
-
-    let cap_dir = if path.extension().and_then(|s| s.to_str()) == Some("cap") {
-        Some(path.clone())
-    } else if let Some(parent) = path.parent() {
-        if parent.extension().and_then(|s| s.to_str()) == Some("cap") {
-            Some(parent.to_path_buf())
-        } else {
-            None
-        }
-    } else {
-        None
-    };
-
-    let recording_meta = if let Some(cap_dir) = &cap_dir {
-        RecordingMeta::load_for_project(cap_dir).map_err(|e| e.to_string())?
-    } else {
-        let filename = path
-            .file_name()
-            .ok_or_else(|| "Invalid path".to_string())?
-            .to_string_lossy();
-        let relative_path = RelativePathBuf::from(filename.as_ref());
-        let video_meta = VideoMeta {
-            path: relative_path.clone(),
-            fps: 30,
-            start_time: Some(0.0),
-            device_id: None,
-        };
-        let segment = SingleSegment {
-            display: video_meta.clone(),
-            camera: None,
-            audio: None,
-            cursor: None,
-        };
-        let studio_meta = StudioRecordingMeta::SingleSegment { segment };
-        RecordingMeta {
-            platform: None,
-            project_path: path.parent().unwrap_or(&path).to_path_buf(),
-            pretty_name: "Screenshot".to_string(),
-            sharing: None,
-            inner: RecordingMetaInner::Studio(Box::new(studio_meta)),
-            upload: None,
-        }
-    };
-
-    let (shared, background_cache) = if let Some(gpu) = gpu_context::get_shared_gpu().await {
-        (
-            cap_rendering::SharedWgpuDevice {
-                instance: (*gpu.instance).clone(),
-                adapter: (*gpu.adapter).clone(),
-                device: (*gpu.device).clone(),
-                queue: (*gpu.queue).clone(),
-                is_software_adapter: gpu.is_software_adapter,
-            },
-            gpu.background_cache.clone(),
-        )
-    } else {
-        let instance = cap_rendering::create_wgpu_instance().await;
-        let force_software_adapter = cap_rendering::force_software_wgpu_adapter();
-        let hardware_adapter = if force_software_adapter {
-            None
-        } else {
-            instance
-                .request_adapter(&wgpu::RequestAdapterOptions {
-                    power_preference: wgpu::PowerPreference::HighPerformance,
-                    force_fallback_adapter: false,
-                    compatible_surface: None,
-                })
-                .await
-                .ok()
-        };
-        let adapter = match hardware_adapter {
-            Some(adapter) => adapter,
-            None => instance
-                .request_adapter(&wgpu::RequestAdapterOptions {
-                    power_preference: wgpu::PowerPreference::LowPower,
-                    force_fallback_adapter: true,
-                    compatible_surface: None,
-                })
-                .await
-                .map_err(|_| "No GPU adapter found".to_string())?,
-        };
-        let adapter_info = adapter.get_info();
-        let is_software_adapter = cap_rendering::is_software_wgpu_adapter(&adapter_info);
-        let (device, queue) = adapter
-            .request_device(&wgpu::DeviceDescriptor {
-                label: Some("cap-rendering-device"),
-                required_features: wgpu::Features::empty(),
-                ..Default::default()
-            })
-            .await
-            .map_err(|e| e.to_string())?;
-        (
-            cap_rendering::SharedWgpuDevice {
-                instance,
-                adapter,
-                device,
-                queue,
-                is_software_adapter,
-            },
-            Arc::new(cap_rendering::BackgroundTextureCache::default()),
-        )
-    };
-
-    let options = cap_rendering::RenderOptions {
-        screen_size: cap_project::XY::new(width, height),
-        camera_size: None,
-        preserve_screen_alpha: true,
-    };
-
-    let studio_meta = match &recording_meta.inner {
-        RecordingMetaInner::Studio(meta) => meta.clone(),
-        _ => return Err("Invalid recording meta for screenshot".to_string()),
-    };
-
-    let constants = RenderVideoConstants::from_shared_device(
-        shared,
-        options,
-        *studio_meta,
-        recording_meta.clone(),
-        background_cache,
-    );
-
-    let (base_width, base_height) = ProjectUniforms::get_base_size(&constants.options, &config);
-    let display_size = ProjectUniforms::display_size(
-        &constants.options,
-        &config,
-        cap_project::XY::new(base_width, base_height),
-    )
-    .coord;
-    let crop = ProjectUniforms::get_crop(&constants.options, &config);
-    let export_scale = f64::max(
-        f64::max(
-            crop.size.x as f64 / f64::max(display_size.x, 1.0),
-            crop.size.y as f64 / f64::max(display_size.y, 1.0),
-        ),
-        1.0,
-    );
-
-    let resolution_base = cap_project::XY::new(
-        (((base_width as f64 * export_scale).ceil() as u32) + 3) & !3,
-        (((base_height as f64 * export_scale).ceil() as u32) + 1) & !1,
-    );
-
-    if resolution_base.x > MAX_DIMENSION || resolution_base.y > MAX_DIMENSION {
-        return Err(format!(
-            "Export dimensions exceed maximum: {}x{}",
-            resolution_base.x, resolution_base.y
-        ));
-    }
-
-    let mut frame_renderer = FrameRenderer::new(&constants);
-    let mut layers = RendererLayers::new_with_options(
-        &constants.device,
-        &constants.queue,
-        constants.is_software_adapter,
-    );
-    let decoded_frame = DecodedFrame::new(data, width, height);
-    let segment_frames = DecodedSegmentFrames {
-        screen_size: cap_project::XY::new(width, height),
-        screen_frame: Some(DecodedFrame::new(
-            decoded_frame.data().to_vec(),
-            decoded_frame.width(),
-            decoded_frame.height(),
-        )),
-        camera_frame: None,
-        segment_time: 0.0,
-        recording_time: 0.0,
-        segment_has_camera: false,
-    };
-    let cursor_events = cap_project::CursorEvents::default();
-    let mut zoom_timeline = ZoomTransformTimeline::from_project(
-        &config,
-        &cursor_events,
-        0.0,
-        constants.options.screen_size,
-    );
-    zoom_timeline.ensure_precomputed_until(1.0 / 30.0);
-    let uniforms = ProjectUniforms::new(
-        &constants,
-        &config,
-        0,
-        30,
-        resolution_base,
-        &cursor_events,
-        &segment_frames,
-        0.0,
-        &zoom_timeline,
-    );
-    let rendered_frame = frame_renderer
-        .render_immediate(
-            segment_frames,
-            uniforms,
-            &cap_project::CursorEvents::default(),
-            true,
-            &mut layers,
-        )
-        .await
-        .map_err(|e| format!("Failed to render screenshot export: {e}"))?;
-
-    let width_usize =
-        usize::try_from(rendered_frame.width).map_err(|_| "Invalid export width".to_string())?;
-    let height_usize =
-        usize::try_from(rendered_frame.height).map_err(|_| "Invalid export height".to_string())?;
-    let unpadded_bytes_per_row = width_usize
-        .checked_mul(4)
-        .ok_or_else(|| "Export row size overflow".to_string())?;
-    let padded_bytes_per_row = usize::try_from(rendered_frame.padded_bytes_per_row)
-        .map_err(|_| "Invalid export stride".to_string())?;
-
-    if padded_bytes_per_row < unpadded_bytes_per_row {
-        return Err(format!(
-            "Invalid export stride: {} for {}x{} image",
-            rendered_frame.padded_bytes_per_row, rendered_frame.width, rendered_frame.height
-        ));
-    }
-
-    let expected_padded_len = padded_bytes_per_row
-        .checked_mul(height_usize)
-        .ok_or_else(|| "Export buffer size overflow".to_string())?;
-    if rendered_frame.data.len() < expected_padded_len {
-        return Err(format!(
-            "Invalid export buffer length: expected at least {} got {} for {}x{} image",
-            expected_padded_len,
-            rendered_frame.data.len(),
-            rendered_frame.width,
-            rendered_frame.height
-        ));
-    }
-
-    let rgba_data: Vec = rendered_frame
-        .data
-        .chunks(padded_bytes_per_row)
-        .take(height_usize)
-        .flat_map(|row| row[..unpadded_bytes_per_row].iter().copied())
-        .collect();
-
-    let mut png_data = Cursor::new(Vec::new());
-    let encoder = PngEncoder::new(&mut png_data);
-    encoder
-        .write_image(
-            &rgba_data,
-            rendered_frame.width,
-            rendered_frame.height,
-            image::ExtendedColorType::Rgba8,
-        )
-        .map_err(|e| format!("Failed to encode screenshot export: {e}"))?;
-
-    Ok(png_data.into_inner())
-}
diff --git a/apps/desktop/src-tauri/src/startup.rs b/apps/desktop/src-tauri/src/startup.rs
deleted file mode 100644
index 36347e3b659..00000000000
--- a/apps/desktop/src-tauri/src/startup.rs
+++ /dev/null
@@ -1,104 +0,0 @@
-use std::{
-    path::Path,
-    time::{Duration, Instant, SystemTime},
-};
-use tauri::{AppHandle, Manager};
-use tokio::sync::watch;
-
-pub(crate) struct Startup {
-    started: Instant,
-    started_at: SystemTime,
-    ready: watch::Sender,
-}
-
-impl Default for Startup {
-    fn default() -> Self {
-        Self {
-            started: Instant::now(),
-            started_at: SystemTime::now(),
-            ready: watch::channel(false).0,
-        }
-    }
-}
-
-impl Startup {
-    pub(crate) fn predates_launch(&self, path: &Path) -> bool {
-        let created = path.metadata().and_then(|metadata| metadata.created()).ok();
-        let modified = path
-            .join("recording-meta.json")
-            .metadata()
-            .and_then(|metadata| metadata.modified())
-            .ok();
-        created.is_none_or(|created| created <= self.started_at)
-            && modified.is_none_or(|modified| modified <= self.started_at)
-    }
-
-    pub(crate) fn mark_ready(&self) {
-        if !self.ready.send_replace(true) {
-            tracing::info!(
-                elapsed_ms = self.started.elapsed().as_millis(),
-                "Startup frontend ready"
-            );
-        }
-    }
-
-    async fn wait(&self) {
-        let mut ready = self.ready.subscribe();
-        let remaining = Duration::from_secs(5).saturating_sub(self.started.elapsed());
-        let _ = tokio::time::timeout(remaining, ready.wait_for(|ready| *ready)).await;
-    }
-}
-
-pub(crate) async fn wait_for_window(app: &AppHandle) -> bool {
-    app.state::().wait().await;
-    !crate::app_is_exiting(app)
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn delayed_reconciliation_does_not_mark_this_sessions_recordings_crashed() {
-        let project = tempfile::tempdir().unwrap();
-        let path = project.path().join("recording-meta.json");
-        std::fs::write(&path, b"{}").unwrap();
-        let metadata_time = path.metadata().unwrap().modified().unwrap();
-        let before_recording = Startup {
-            started_at: metadata_time.checked_sub(Duration::from_secs(1)).unwrap(),
-            ..Startup::default()
-        };
-        assert!(!before_recording.predates_launch(project.path()));
-        let after_recording = Startup {
-            started_at: SystemTime::now() + Duration::from_secs(1),
-            ..Startup::default()
-        };
-        assert!(after_recording.predates_launch(project.path()));
-    }
-
-    #[tokio::test]
-    async fn readiness_releases_both_existing_and_late_waiters() {
-        let startup = Startup::default();
-        assert!(
-            tokio::time::timeout(Duration::from_millis(10), startup.wait())
-                .await
-                .is_err()
-        );
-        startup.mark_ready();
-        startup.mark_ready();
-        tokio::time::timeout(Duration::from_millis(100), startup.wait())
-            .await
-            .unwrap();
-    }
-
-    #[tokio::test]
-    async fn a_failed_frontend_does_not_disable_recovery() {
-        let startup = Startup {
-            started: Instant::now().checked_sub(Duration::from_secs(6)).unwrap(),
-            ..Startup::default()
-        };
-        tokio::time::timeout(Duration::from_millis(100), startup.wait())
-            .await
-            .unwrap();
-    }
-}
diff --git a/apps/desktop/src-tauri/src/stop-editor-benchmark.js b/apps/desktop/src-tauri/src/stop-editor-benchmark.js
deleted file mode 100644
index 7f991f5f853..00000000000
--- a/apps/desktop/src-tauri/src/stop-editor-benchmark.js
+++ /dev/null
@@ -1,30 +0,0 @@
-(() => {
-	let reported = false;
-	const report = () => {
-		if (reported) return;
-		reported = true;
-		requestAnimationFrame(() => {
-			requestAnimationFrame(() => {
-				void window.__TAURI_INTERNALS__.invoke("plugin:event|emit", {
-					event: "cap-stop-benchmark-frame",
-					payload: {},
-				});
-			});
-		});
-	};
-	const deadline = performance.now() + 180_000;
-	const observe = () => {
-		const canvas = document.getElementById("canvas");
-		const stats = window.__capFpsStats?.();
-		if (
-			stats?.renderCount > 0 &&
-			canvas?.width > 0 &&
-			getComputedStyle(canvas).visibility === "visible"
-		) {
-			report();
-		} else if (performance.now() < deadline) {
-			requestAnimationFrame(observe);
-		}
-	};
-	requestAnimationFrame(observe);
-})();
diff --git a/apps/desktop/src-tauri/src/stop-editor-parity-dom.js b/apps/desktop/src-tauri/src/stop-editor-parity-dom.js
deleted file mode 100644
index 3900ad50144..00000000000
--- a/apps/desktop/src-tauri/src/stop-editor-parity-dom.js
+++ /dev/null
@@ -1,214 +0,0 @@
-(() => {
-	const ids = new WeakMap();
-	let nextId = 1;
-	let sequence = 0;
-	let lastState = "";
-	let previousPreparingIds = [];
-	let firstOrdinaryVisibleAt;
-	const started = performance.now();
-	const deadline = started + 180_000;
-	const idFor = (element) => {
-		if (!ids.has(element)) ids.set(element, nextId++);
-		return ids.get(element);
-	};
-	const describe = (canvas) => {
-		const rect = canvas.getBoundingClientRect();
-		let ancestorsVisible = true;
-		for (let element = canvas; element; element = element.parentElement) {
-			const style = getComputedStyle(element);
-			if (
-				style.display === "none" ||
-				style.visibility !== "visible" ||
-				Number(style.opacity) === 0
-			) {
-				ancestorsVisible = false;
-				break;
-			}
-		}
-		return {
-			id: idFor(canvas),
-			connected: canvas.isConnected,
-			width: canvas.width,
-			height: canvas.height,
-			bounds: {
-				x: rect.x,
-				y: rect.y,
-				width: rect.width,
-				height: rect.height,
-			},
-			visible:
-				ancestorsVisible &&
-				canvas.width > 0 &&
-				canvas.height > 0 &&
-				rect.width > 0 &&
-				rect.height > 0 &&
-				rect.bottom > 0 &&
-				rect.right > 0 &&
-				rect.top < innerHeight &&
-				rect.left < innerWidth,
-		};
-	};
-	const geometry = (element) => {
-		if (!element) return null;
-		const rect = element.getBoundingClientRect();
-		const style = getComputedStyle(element);
-		return {
-			id: idFor(element),
-			connected: element.isConnected,
-			bounds: {
-				x: rect.x,
-				y: rect.y,
-				width: rect.width,
-				height: rect.height,
-			},
-			inline: {
-				width: element.style.width,
-				height: element.style.height,
-				minHeight: element.style.minHeight,
-			},
-			computed: {
-				width: style.width,
-				height: style.height,
-				minHeight: style.minHeight,
-				maxHeight: style.maxHeight,
-				display: style.display,
-				visibility: style.visibility,
-				flex: style.flex,
-				flexDirection: style.flexDirection,
-				gap: style.gap,
-				paddingTop: style.paddingTop,
-				paddingBottom: style.paddingBottom,
-			},
-		};
-	};
-	const ordinaryLayout = (canvas) => {
-		if (!canvas) return null;
-		const ancestors = [];
-		for (
-			let element = canvas.parentElement;
-			element && ancestors.length < 10;
-			element = element.parentElement
-		) {
-			ancestors.push(element);
-		}
-		const [wrapper, visibilityLayer, container, player, card, row, layout] =
-			ancestors;
-		const timelineSeparator = document.querySelector(
-			'[role="separator"][aria-label="Resize timeline height"]',
-		);
-		const timeline = timelineSeparator?.parentElement;
-		const sourceStructureMatches = Boolean(
-			container?.parentElement === player &&
-				player?.children.length === 3 &&
-				player?.children[1] === container &&
-				timeline?.parentElement === layout &&
-				row?.nextElementSibling === timeline,
-		);
-		return {
-			sourceStructureMatches,
-			canvas: geometry(canvas),
-			ancestors: ancestors.map(geometry),
-			roles: sourceStructureMatches
-				? {
-						wrapper: idFor(wrapper),
-						visibilityLayer: idFor(visibilityLayer),
-						container: idFor(container),
-						player: idFor(player),
-						card: idFor(card),
-						row: idFor(row),
-						layout: idFor(layout),
-					}
-				: null,
-			topToolbar: sourceStructureMatches
-				? geometry(container.previousElementSibling)
-				: null,
-			bottomToolbar: sourceStructureMatches
-				? geometry(container.nextElementSibling)
-				: null,
-			timeline: geometry(timeline),
-		};
-	};
-	const emit = (value) => {
-		void window.__TAURI_INTERNALS__
-			.invoke("plugin:event|emit", {
-				event: "cap-stop-benchmark-dom",
-				payload: value,
-			})
-			.catch(() => {});
-	};
-	const sample = () => {
-		const now = performance.now();
-		const preparing = Array.from(
-			document.querySelectorAll(
-				'canvas[aria-label="Recording preview while the editor prepares"]',
-			),
-		).map((canvas) => {
-			const siblings = Array.from(canvas.parentElement.children).filter(
-				(element) => element.tagName === "CANVAS",
-			);
-			return {
-				...describe(canvas),
-				role: siblings.indexOf(canvas) === 1 ? "retained" : "live",
-			};
-		});
-		const ordinaryCanvas = document.getElementById("canvas");
-		const ordinary = ordinaryCanvas ? describe(ordinaryCanvas) : null;
-		const stats = window.__capFpsStats?.();
-		const ordinaryRenderedVisible = Boolean(
-			ordinary?.visible && stats?.renderCount > 0,
-		);
-		if (ordinaryRenderedVisible && firstOrdinaryVisibleAt === undefined) {
-			firstOrdinaryVisibleAt = now;
-		}
-		const state = {
-			preparing,
-			ordinary,
-			ordinaryLayout: ordinaryLayout(ordinaryCanvas),
-			ordinaryRenderedVisible,
-			documentVisibility: document.visibilityState,
-			viewport: {
-				width: innerWidth,
-				height: innerHeight,
-				dpr: devicePixelRatio,
-			},
-		};
-		const serialized = JSON.stringify(state);
-		if (serialized !== lastState) {
-			const currentIds = preparing.map((canvas) => canvas.id);
-			emit({
-				sequence: sequence++,
-				timeOriginMs: performance.timeOrigin,
-				elapsedMs: now - started,
-				observation: "canvas_state",
-				preparingSubtreesDetached: previousPreparingIds.filter(
-					(id) => !currentIds.includes(id),
-				),
-				state,
-			});
-			previousPreparingIds = currentIds;
-			lastState = serialized;
-		}
-		if (
-			now < deadline &&
-			sequence < 512 &&
-			(firstOrdinaryVisibleAt === undefined ||
-				now - firstOrdinaryVisibleAt < 1000)
-		) {
-			requestAnimationFrame(sample);
-		} else {
-			emit({
-				sequence: sequence++,
-				timeOriginMs: performance.timeOrigin,
-				elapsedMs: now - started,
-				observation: "complete",
-				reason:
-					firstOrdinaryVisibleAt !== undefined
-						? "ordinary_visible_settled"
-						: now >= deadline
-							? "deadline"
-							: "observation_limit",
-			});
-		}
-	};
-	requestAnimationFrame(sample);
-})();
diff --git a/apps/desktop/src-tauri/src/stop_editor_benchmark.rs b/apps/desktop/src-tauri/src/stop_editor_benchmark.rs
deleted file mode 100644
index 43f3ea1c831..00000000000
--- a/apps/desktop/src-tauri/src/stop_editor_benchmark.rs
+++ /dev/null
@@ -1,822 +0,0 @@
-use std::{
-    ffi::OsString,
-    path::{Path, PathBuf},
-    sync::{
-        Arc, Mutex, OnceLock,
-        atomic::{AtomicBool, Ordering},
-    },
-    time::{Duration, Instant},
-};
-
-use tauri::{Listener, Manager};
-use tokio::sync::RwLock;
-
-pub const SCRIPT: &str = include_str!("stop-editor-benchmark.js");
-pub const DOM_SCRIPT: &str = include_str!("stop-editor-parity-dom.js");
-static FRAME_CAPTURE: OnceLock> = OnceLock::new();
-static STARTED: AtomicBool = AtomicBool::new(false);
-static CONFIG: OnceLock, String>> = OnceLock::new();
-static APP_ADMITTED: AtomicBool = AtomicBool::new(false);
-
-struct BenchmarkConfig {
-    output: PathBuf,
-    log_directory: PathBuf,
-    seconds: u64,
-    microphone: Option,
-    system_audio: bool,
-    fixture_window: bool,
-    frame_directory: Option,
-    dom_capture: bool,
-}
-
-fn parse_config(
-    arguments: impl IntoIterator,
-    mut environment: impl FnMut(&'static str) -> Option,
-) -> Result, String> {
-    let arguments: Vec<_> = arguments.into_iter().collect();
-    let benchmark = arguments
-        .iter()
-        .filter(|arg| *arg == "--stop-editor-benchmark")
-        .count();
-    let recording = arguments
-        .iter()
-        .filter(|arg| *arg == "--allow-real-recording")
-        .count();
-    if benchmark == 0 && recording == 0 {
-        return Ok(None);
-    }
-    if arguments.len() != 2 || benchmark != 1 || recording != 1 {
-        return Err(
-            "Benchmark invocation requires exactly --stop-editor-benchmark --allow-real-recording"
-                .into(),
-        );
-    }
-    let output = environment("CAP_STOP_EDITOR_BENCHMARK_OUTPUT")
-        .filter(|value| !value.is_empty())
-        .ok_or("Benchmark invocation requires CAP_STOP_EDITOR_BENCHMARK_OUTPUT")?;
-    let log_directory = environment("CAP_STOP_BENCH_LOG_DIR")
-        .filter(|value| !value.is_empty())
-        .ok_or("Benchmark invocation requires CAP_STOP_BENCH_LOG_DIR")?;
-    let seconds = environment("CAP_STOP_BENCH_SECONDS")
-        .map(|value| {
-            value
-                .into_string()
-                .map_err(|_| "Benchmark duration must be valid UTF-8".to_string())?
-                .parse::()
-                .map_err(|_| "Benchmark duration must be a whole number of seconds".to_string())
-        })
-        .transpose()?
-        .unwrap_or(15);
-    if !(1..=86_400).contains(&seconds) {
-        return Err("Benchmark duration must be between 1 and 86400 seconds".into());
-    }
-    let microphone = environment("CAP_STOP_BENCH_MIC")
-        .map(|value| {
-            value
-                .into_string()
-                .map_err(|_| "Benchmark microphone must be valid UTF-8".to_string())
-                .and_then(|value| {
-                    if value.is_empty() {
-                        Err("Benchmark microphone must not be empty".into())
-                    } else {
-                        Ok(value)
-                    }
-                })
-        })
-        .transpose()?;
-    Ok(Some(BenchmarkConfig {
-        output: PathBuf::from(output),
-        log_directory: PathBuf::from(log_directory),
-        seconds,
-        microphone,
-        system_audio: environment("CAP_STOP_BENCH_SYSTEM_AUDIO").is_some(),
-        fixture_window: environment("CAP_STOP_BENCH_FIXTURE_WINDOW").is_some(),
-        frame_directory: environment("CAP_STOP_BENCH_FRAME_DIR").map(PathBuf::from),
-        dom_capture: environment("CAP_STOP_BENCH_DOM_CAPTURE").is_some(),
-    }))
-}
-
-fn validate_frame_directory(config: &BenchmarkConfig) -> Result<(), String> {
-    let Some(directory) = config.frame_directory.as_ref() else {
-        return Ok(());
-    };
-    if !directory.is_absolute()
-        || directory == &config.output
-        || directory == &config.log_directory
-        || directory.components().any(|component| {
-            !matches!(
-                component,
-                std::path::Component::Prefix(_)
-                    | std::path::Component::RootDir
-                    | std::path::Component::Normal(_)
-            )
-        })
-    {
-        return Err(
-            "Benchmark frame directory must be a distinct absolute path without traversal".into(),
-        );
-    }
-    let parent = directory
-        .parent()
-        .ok_or("Benchmark frame directory has no parent")?;
-    if parent.canonicalize().map_err(|error| error.to_string())? != parent || !parent.is_dir() {
-        return Err("Benchmark frame directory requires an existing canonical parent".into());
-    }
-    match std::fs::symlink_metadata(directory) {
-        Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(()),
-        Err(error) => Err(error.to_string()),
-        Ok(_) => Err("Benchmark frame directory must be new".into()),
-    }
-}
-
-fn prepare_config(
-    config: Option,
-    create_log_directory: impl FnOnce(&Path, &Path) -> std::io::Result,
-) -> Result, String> {
-    if let Some(config) = config.as_ref() {
-        validate_frame_directory(config)?;
-        create_log_directory(&config.output, &config.log_directory)
-            .map_err(|error| error.to_string())?;
-    }
-    Ok(config)
-}
-
-pub fn initialize(
-    create_log_directory: impl FnOnce(&Path, &Path) -> std::io::Result,
-) -> Result, String> {
-    match CONFIG.get_or_init(|| {
-        let config = parse_config(std::env::args_os().skip(1), std::env::var_os)?;
-        prepare_config(config, create_log_directory)
-    }) {
-        Ok(config) => Ok(config.as_ref().map(|config| config.log_directory.clone())),
-        Err(error) => Err(error.clone()),
-    }
-}
-
-fn config() -> Option<&'static BenchmarkConfig> {
-    CONFIG.get()?.as_ref().ok()?.as_ref()
-}
-
-fn admit_identifier(requested: bool, identifier: &str) -> Result {
-    if !requested {
-        return Ok(false);
-    }
-    if identifier
-        .strip_prefix("so.cap.desktop.stop-editor-benchmark.")
-        .is_some_and(|suffix| !suffix.is_empty())
-    {
-        Ok(true)
-    } else {
-        Err("Benchmark invocation requires a private benchmark app identifier".into())
-    }
-}
-
-pub fn validate_app_identifier(identifier: &str) -> Result<(), String> {
-    let admitted = admit_identifier(config().is_some(), identifier)?;
-    APP_ADMITTED.store(admitted, Ordering::SeqCst);
-    Ok(())
-}
-
-pub fn enabled() -> bool {
-    APP_ADMITTED.load(Ordering::SeqCst) && config().is_some()
-}
-
-pub fn run(app: tauri::AppHandle) {
-    if !enabled() {
-        return;
-    }
-    let Some(config) = config() else {
-        return;
-    };
-    if STARTED.swap(true, Ordering::SeqCst) {
-        return;
-    }
-    tokio::spawn(async move {
-        let result = measure(&app, config).await;
-        let mut value = match result {
-            Ok(value) => value,
-            Err(error) => serde_json::json!({ "error": error }),
-        };
-        match finish_frame_capture() {
-            Ok(Some(capture)) => value["frameCapture"] = capture,
-            Ok(None) => {}
-            Err(error) => {
-                value["frameCapture"] =
-                    serde_json::json!({ "status": "incomplete", "error": error })
-            }
-        }
-        if let Err(error) = std::fs::write(&config.output, value.to_string()) {
-            tracing::error!(%error, "Could not write Stop benchmark results");
-        }
-    });
-}
-
-async fn measure(
-    app: &tauri::AppHandle,
-    config: &BenchmarkConfig,
-) -> Result {
-    tokio::time::sleep(Duration::from_secs(3)).await;
-    let state = app.state::>>();
-    crate::set_mic_input(app.clone(), state.clone(), config.microphone.clone()).await?;
-    let capture_target = benchmark_capture_target(config.fixture_window)?;
-    let action = crate::recording::start_recording(
-        app.clone(),
-        state.clone(),
-        crate::recording::StartRecordingInputs {
-            capture_target,
-            capture_system_audio: config.system_audio,
-            mode: cap_recording::RecordingMode::Studio,
-            organization_id: None,
-        },
-    )
-    .await?;
-    if !matches!(action, crate::recording::RecordingAction::Started) {
-        return Err("Benchmark recording did not start".into());
-    }
-    let seconds = config.seconds;
-    tokio::time::sleep(Duration::from_secs(seconds)).await;
-    let project = state
-        .read()
-        .await
-        .current_recording()
-        .map(|recording| recording.recording_dir().clone());
-    if let Err(error) = arm_frame_capture(app, project.as_deref()) {
-        let cleanup = crate::recording::stop_recording(app.clone(), state.clone()).await;
-        return Err(match cleanup {
-            Ok(()) => error,
-            Err(cleanup_error) => format!("{error}; recording stop also failed: {cleanup_error}"),
-        });
-    }
-    let dom_capture = DomCapture::start(app);
-    let (sender, mut receiver) = tokio::sync::mpsc::unbounded_channel();
-    let listener = app.listen_any("cap-stop-benchmark-frame", move |_| {
-        let _ = sender.send(Instant::now());
-    });
-    let started = Instant::now();
-    tracing::info!("Stop editor benchmark stop requested");
-    let stopped = crate::recording::stop_recording(app.clone(), state).await;
-    let stop_ms = started.elapsed().as_secs_f64() * 1000.0;
-    if let Err(error) = stopped {
-        app.unlisten(listener);
-        return Err(error);
-    }
-    let frame = tokio::time::timeout(Duration::from_secs(180), receiver.recv()).await;
-    app.unlisten(listener);
-    let frame = frame
-        .map_err(|error| error.to_string())?
-        .ok_or("Editor frame channel closed")?;
-    let mut result = serde_json::json!({
-        "project": project,
-        "recordingSeconds": seconds,
-        "stopCommandMs": stop_ms,
-        "editorFrameMs": frame.saturating_duration_since(started).as_secs_f64() * 1000.0,
-    });
-    if let Some(dom_capture) = dom_capture {
-        result["domObservations"] = dom_capture.finish().await;
-    }
-    Ok(result)
-}
-
-fn benchmark_capture_target(
-    fixture_window: bool,
-) -> Result {
-    use cap_recording::screen_capture::ScreenCaptureTarget;
-    if !fixture_window {
-        return Ok(ScreenCaptureTarget::Display {
-            id: scap_targets::Display::primary().id(),
-        });
-    }
-    let window = select_exact_fixture(
-        scap_targets::Window::list()
-            .into_iter()
-            .map(|window| (window, window.name())),
-    )?;
-    Ok(ScreenCaptureTarget::Window { id: window.id() })
-}
-
-fn select_exact_fixture(
-    windows: impl Iterator)>,
-) -> Result {
-    let mut matching =
-        windows.filter(|(_, name)| name.as_deref() == Some("Cap Stop benchmark fixture"));
-    let window = matching
-        .next()
-        .ok_or("Exact benchmark fixture window is absent")?
-        .0;
-    if matching.next().is_some() {
-        return Err("Exact benchmark fixture window is ambiguous".into());
-    }
-    Ok(window)
-}
-
-pub fn frame_capture_requested() -> bool {
-    enabled() && config().is_some_and(|config| config.frame_directory.is_some())
-}
-
-pub fn dom_capture_requested() -> bool {
-    enabled() && config().is_some_and(|config| config.dom_capture)
-}
-
-#[derive(Clone, Copy)]
-pub enum CaptureKind {
-    Preparing,
-    Ordinary,
-}
-
-struct CapturedFrame {
-    data: Arc>,
-    width: u32,
-    height: u32,
-    stride: u32,
-    frame_number: u32,
-    target_time_ns: u64,
-}
-
-struct FrameCapture {
-    directory: PathBuf,
-    project: PathBuf,
-    preparing: Option,
-    ordinary: Option,
-    closed: bool,
-}
-
-impl FrameCapture {
-    fn record(&mut self, kind: CaptureKind, project: &Path, frame: CapturedFrame) {
-        if self.closed || self.project != project {
-            return;
-        }
-        let slot = match kind {
-            CaptureKind::Preparing => &mut self.preparing,
-            CaptureKind::Ordinary => &mut self.ordinary,
-        };
-        if slot.is_none() {
-            *slot = Some(frame);
-        }
-    }
-}
-
-fn arm_frame_capture(app: &tauri::AppHandle, project: Option<&Path>) -> Result<(), String> {
-    let Some(directory) = config().and_then(|config| config.frame_directory.as_ref()) else {
-        return Ok(());
-    };
-    if !app
-        .config()
-        .identifier
-        .starts_with("so.cap.desktop.stop-editor-benchmark.")
-    {
-        return Err("Frame capture requires a private benchmark app identifier".into());
-    }
-    let directory = directory.clone();
-    if !directory.is_absolute() {
-        return Err("Frame capture directory must be absolute".into());
-    }
-    let project = project
-        .ok_or("Frame capture has no active recording project")?
-        .to_path_buf();
-    std::fs::create_dir(&directory).map_err(|error| error.to_string())?;
-    FRAME_CAPTURE
-        .set(Mutex::new(FrameCapture {
-            directory,
-            project,
-            preparing: None,
-            ordinary: None,
-            closed: false,
-        }))
-        .map_err(|_| "Frame capture was already armed".to_string())
-}
-
-pub fn capture_output(kind: CaptureKind, project: &Path, output: &cap_editor::EditorFrameOutput) {
-    let Some(capture) = FRAME_CAPTURE.get() else {
-        return;
-    };
-    let cap_editor::EditorFrameOutput::Rgba(frame) = output else {
-        return;
-    };
-    capture
-        .lock()
-        .unwrap_or_else(std::sync::PoisonError::into_inner)
-        .record(
-            kind,
-            project,
-            CapturedFrame {
-                data: frame.data.clone(),
-                width: frame.width,
-                height: frame.height,
-                stride: frame.padded_bytes_per_row,
-                frame_number: frame.frame_number,
-                target_time_ns: frame.target_time_ns,
-            },
-        );
-}
-
-pub fn capture_ws_frame(kind: CaptureKind, project: &Path, frame: &crate::frame_ws::WSFrame) {
-    let Some(capture) = FRAME_CAPTURE.get() else {
-        return;
-    };
-    if frame.format != crate::frame_ws::WSFrameFormat::Rgba {
-        return;
-    }
-    capture
-        .lock()
-        .unwrap_or_else(std::sync::PoisonError::into_inner)
-        .record(
-            kind,
-            project,
-            CapturedFrame {
-                data: match &frame.data {
-                    crate::frame_ws::WSFrameData::Raw(data) => data.clone(),
-                    crate::frame_ws::WSFrameData::Packed(data) => {
-                        Arc::new(data[..data.len() - 24].to_vec())
-                    }
-                },
-                width: frame.width,
-                height: frame.height,
-                stride: frame.stride,
-                frame_number: frame.frame_number,
-                target_time_ns: frame.target_time_ns,
-            },
-        );
-}
-
-fn write_captured_frame(
-    directory: &Path,
-    name: &str,
-    frame: CapturedFrame,
-) -> Result {
-    let row_bytes = frame
-        .width
-        .checked_mul(4)
-        .ok_or("Captured frame row overflow")?;
-    let expected_bytes = (frame.stride as usize)
-        .checked_mul(frame.height as usize)
-        .ok_or("Captured frame length overflow")?;
-    if frame.width == 0
-        || frame.height == 0
-        || frame.stride < row_bytes
-        || frame.data.len() != expected_bytes
-    {
-        return Err("Captured frame has an incomplete RGBA buffer".into());
-    }
-    let file = directory.join(format!("{name}.rgba"));
-    std::fs::write(&file, frame.data.as_slice()).map_err(|error| error.to_string())?;
-    Ok(serde_json::json!({
-        "file": file,
-        "format": "rgba",
-        "width": frame.width,
-        "height": frame.height,
-        "stride": frame.stride,
-        "frameNumber": frame.frame_number,
-        "targetTimeNs": frame.target_time_ns,
-        "bytes": expected_bytes,
-    }))
-}
-
-fn finish_frame_capture() -> Result, String> {
-    let Some(capture) = FRAME_CAPTURE.get() else {
-        return Ok(None);
-    };
-    let (directory, project, preparing, ordinary) = {
-        let mut capture = capture
-            .lock()
-            .unwrap_or_else(std::sync::PoisonError::into_inner);
-        capture.closed = true;
-        (
-            capture.directory.clone(),
-            capture.project.clone(),
-            capture.preparing.take(),
-            capture.ordinary.take(),
-        )
-    };
-    let mut frames = serde_json::Map::new();
-    for (name, frame) in [("preparing", preparing), ("ordinary", ordinary)] {
-        if let Some(frame) = frame {
-            let _ = frames.insert(
-                name.to_string(),
-                write_captured_frame(&directory, name, frame)?,
-            );
-        }
-    }
-    let value = serde_json::json!({
-        "status": if frames.len() == 2 { "captured_uncompared" } else { "incomplete" },
-        "project": project,
-        "frames": frames,
-        "timingQualification": "Separate untimed parity capture; renderer callback bytes are not external compositor proof",
-    });
-    std::fs::write(directory.join("frames.json"), value.to_string())
-        .map_err(|error| error.to_string())?;
-    Ok(Some(value))
-}
-
-struct DomCapture {
-    app: tauri::AppHandle,
-    listener: tauri::EventId,
-    observations: Arc>>,
-}
-
-impl DomCapture {
-    fn start(app: &tauri::AppHandle) -> Option {
-        if !dom_capture_requested() {
-            return None;
-        }
-        let observations = Arc::new(Mutex::new(Vec::new()));
-        let captured = observations.clone();
-        let listener = app.listen_any("cap-stop-benchmark-dom", move |event| {
-            if let Ok(value) = serde_json::from_str(event.payload()) {
-                let mut observations = captured
-                    .lock()
-                    .unwrap_or_else(std::sync::PoisonError::into_inner);
-                if observations.len() < 1024 {
-                    observations.push(value);
-                }
-            }
-        });
-        Some(Self {
-            app: app.clone(),
-            listener,
-            observations,
-        })
-    }
-
-    async fn finish(self) -> serde_json::Value {
-        tokio::time::sleep(Duration::from_secs(2)).await;
-        let observations = self
-            .observations
-            .lock()
-            .unwrap_or_else(std::sync::PoisonError::into_inner)
-            .clone();
-        serde_json::json!(observations)
-    }
-}
-
-impl Drop for DomCapture {
-    fn drop(&mut self) {
-        self.app.unlisten(self.listener);
-    }
-}
-
-#[cfg(test)]
-mod invocation_tests {
-    use super::*;
-
-    fn request(settings: &[(&str, &str)]) -> Result, String> {
-        parse_config(
-            ["--stop-editor-benchmark", "--allow-real-recording"].map(OsString::from),
-            |name| {
-                settings
-                    .iter()
-                    .find(|(key, _)| *key == name)
-                    .map(|(_, value)| OsString::from(*value))
-            },
-        )
-    }
-
-    fn settings() -> [(&'static str, &'static str); 2] {
-        [
-            ("CAP_STOP_EDITOR_BENCHMARK_OUTPUT", "/benchmark/result.json"),
-            ("CAP_STOP_BENCH_LOG_DIR", "/benchmark/logs"),
-        ]
-    }
-
-    #[test]
-    fn ordinary_arguments_never_read_benchmark_environment_or_create_logs() {
-        for arguments in [
-            vec![],
-            vec!["recording.cap"],
-            vec!["--stop-editor-benchmark=true"],
-            vec!["https://example.invalid/--allow-real-recording"],
-        ] {
-            let config = parse_config(arguments.into_iter().map(OsString::from), |_| {
-                panic!("Ordinary startup must not read benchmark environment")
-            })
-            .unwrap();
-            assert!(
-                prepare_config(config, |_, _| {
-                    panic!("Ordinary startup must not create benchmark logs")
-                })
-                .unwrap()
-                .is_none()
-            );
-        }
-    }
-
-    #[test]
-    fn incomplete_or_mixed_invocations_fail_before_reading_settings() {
-        for arguments in [
-            vec!["--stop-editor-benchmark"],
-            vec!["--allow-real-recording"],
-            vec![
-                "--stop-editor-benchmark",
-                "--stop-editor-benchmark",
-                "--allow-real-recording",
-            ],
-            vec![
-                "--stop-editor-benchmark",
-                "--allow-real-recording",
-                "recording.cap",
-            ],
-            vec!["--", "--stop-editor-benchmark", "--allow-real-recording"],
-        ] {
-            assert!(
-                parse_config(arguments.into_iter().map(OsString::from), |_| {
-                    panic!("Malformed invocation must fail before reading settings")
-                })
-                .is_err()
-            );
-        }
-    }
-
-    #[test]
-    fn explicit_invocation_requires_both_private_paths() {
-        assert!(request(&[]).is_err());
-        assert!(request(&settings()[..1]).is_err());
-        assert!(request(&settings()[1..]).is_err());
-        for missing in ["CAP_STOP_EDITOR_BENCHMARK_OUTPUT", "CAP_STOP_BENCH_LOG_DIR"] {
-            let mut settings = settings();
-            for (name, value) in &mut settings {
-                if *name == missing {
-                    *value = "";
-                }
-            }
-            assert!(request(&settings).is_err());
-        }
-    }
-
-    #[test]
-    fn explicit_invocation_retains_default_duration_and_capture_options() {
-        let config = request(&settings()).unwrap().unwrap();
-        assert_eq!(config.seconds, 15);
-        assert_eq!(config.output, Path::new("/benchmark/result.json"));
-        assert_eq!(config.log_directory, Path::new("/benchmark/logs"));
-        assert!(config.microphone.is_none());
-        assert!(!config.system_audio);
-        assert!(!config.fixture_window);
-        assert!(config.frame_directory.is_none());
-        assert!(!config.dom_capture);
-    }
-
-    #[test]
-    fn explicit_invocation_freezes_all_capture_settings() {
-        let mut settings = settings().to_vec();
-        settings.extend([
-            ("CAP_STOP_BENCH_SECONDS", "7200"),
-            ("CAP_STOP_BENCH_MIC", "Test microphone"),
-            ("CAP_STOP_BENCH_SYSTEM_AUDIO", "1"),
-            ("CAP_STOP_BENCH_FIXTURE_WINDOW", "1"),
-            ("CAP_STOP_BENCH_FRAME_DIR", "/benchmark/frames"),
-            ("CAP_STOP_BENCH_DOM_CAPTURE", "1"),
-        ]);
-        let config = request(&settings).unwrap().unwrap();
-        assert_eq!(config.seconds, 7200);
-        assert_eq!(config.microphone.as_deref(), Some("Test microphone"));
-        assert!(config.system_audio);
-        assert!(config.fixture_window);
-        assert_eq!(
-            config.frame_directory.as_deref(),
-            Some(Path::new("/benchmark/frames"))
-        );
-        assert!(config.dom_capture);
-    }
-
-    #[test]
-    fn invalid_duration_or_microphone_is_not_replaced_with_a_recording_default() {
-        for value in [
-            "",
-            "invalid",
-            "-1",
-            "1.5",
-            "0",
-            "86401",
-            "18446744073709551616",
-        ] {
-            let mut settings = settings().to_vec();
-            settings.push(("CAP_STOP_BENCH_SECONDS", value));
-            assert!(request(&settings).is_err());
-        }
-        let mut settings = settings().to_vec();
-        settings.push(("CAP_STOP_BENCH_MIC", ""));
-        assert!(request(&settings).is_err());
-    }
-
-    #[test]
-    fn configured_invocation_must_pass_the_private_log_validator() {
-        let config = request(&settings()).unwrap();
-        let mut calls = 0;
-        let prepared = prepare_config(config, |output, directory| {
-            calls += 1;
-            assert_eq!(output, Path::new("/benchmark/result.json"));
-            assert_eq!(directory, Path::new("/benchmark/logs"));
-            Ok(directory.to_path_buf())
-        })
-        .unwrap();
-        assert_eq!(calls, 1);
-        assert!(prepared.is_some());
-        assert!(
-            prepare_config(request(&settings()).unwrap(), |_, _| {
-                Err(std::io::Error::new(
-                    std::io::ErrorKind::AlreadyExists,
-                    "retained evidence",
-                ))
-            })
-            .is_err()
-        );
-    }
-
-    #[test]
-    fn app_admission_rejects_normal_and_empty_private_identifiers() {
-        for identifier in [
-            "so.cap.desktop",
-            "so.cap.desktop.dev",
-            "so.cap.desktop.stop-editor-benchmark.",
-            "other.so.cap.desktop.stop-editor-benchmark.test",
-        ] {
-            assert!(!admit_identifier(false, identifier).unwrap());
-            assert!(admit_identifier(true, identifier).is_err());
-        }
-        let private = "so.cap.desktop.stop-editor-benchmark.test";
-        assert!(!admit_identifier(false, private).unwrap());
-        assert!(admit_identifier(true, private).unwrap());
-    }
-}
-
-#[cfg(test)]
-mod parity_capture_tests {
-    use super::*;
-
-    fn frame(value: u8) -> CapturedFrame {
-        CapturedFrame {
-            data: Arc::new(vec![value; 8]),
-            width: 2,
-            height: 1,
-            stride: 8,
-            frame_number: 0,
-            target_time_ns: 0,
-        }
-    }
-
-    #[test]
-    fn exact_fixture_selection_rejects_missing_and_ambiguous_titles() {
-        assert!(select_exact_fixture(std::iter::empty::<(u8, Option)>()).is_err());
-        assert_eq!(
-            select_exact_fixture(
-                [
-                    (1, Some("Cap Stop benchmark fixture".into())),
-                    (2, Some("Cap Stop benchmark fixture extra".into()))
-                ]
-                .into_iter()
-            )
-            .unwrap(),
-            1
-        );
-        assert!(
-            select_exact_fixture(
-                [
-                    (1, Some("Cap Stop benchmark fixture".into())),
-                    (2, Some("Cap Stop benchmark fixture".into()))
-                ]
-                .into_iter()
-            )
-            .is_err()
-        );
-    }
-
-    #[test]
-    fn first_frames_are_bound_to_project_and_capture_closure() {
-        let project = PathBuf::from("owned.cap");
-        let mut capture = FrameCapture {
-            directory: PathBuf::new(),
-            project: project.clone(),
-            preparing: None,
-            ordinary: None,
-            closed: false,
-        };
-        capture.record(CaptureKind::Preparing, Path::new("other.cap"), frame(1));
-        assert!(capture.preparing.is_none());
-        capture.record(CaptureKind::Preparing, &project, frame(2));
-        capture.record(CaptureKind::Preparing, &project, frame(3));
-        capture.record(CaptureKind::Ordinary, &project, frame(4));
-        assert_eq!(capture.preparing.as_ref().unwrap().data.as_slice(), &[2; 8]);
-        assert_eq!(capture.ordinary.as_ref().unwrap().data.as_slice(), &[4; 8]);
-        capture.closed = true;
-        capture.ordinary = None;
-        capture.record(CaptureKind::Ordinary, &project, frame(5));
-        assert!(capture.ordinary.is_none());
-    }
-
-    #[test]
-    fn rgba_capture_rejects_truncation_and_preserves_full_padded_rows() {
-        let directory = tempfile::tempdir().unwrap();
-        let mut truncated = frame(1);
-        truncated.data = Arc::new(vec![1; 7]);
-        assert!(write_captured_frame(directory.path(), "truncated", truncated).is_err());
-        assert!(!directory.path().join("truncated.rgba").exists());
-        let mut padded = frame(2);
-        padded.stride = 12;
-        padded.data = Arc::new(vec![2; 12]);
-        let metadata = write_captured_frame(directory.path(), "padded", padded).unwrap();
-        assert_eq!(metadata["bytes"], 12);
-        assert_eq!(
-            std::fs::read(directory.path().join("padded.rgba")).unwrap(),
-            vec![2; 12]
-        );
-    }
-}
diff --git a/apps/desktop/src-tauri/src/target_select_overlay.rs b/apps/desktop/src-tauri/src/target_select_overlay.rs
deleted file mode 100644
index 70a90cf59a5..00000000000
--- a/apps/desktop/src-tauri/src/target_select_overlay.rs
+++ /dev/null
@@ -1,1054 +0,0 @@
-use std::{
-    collections::{HashMap, HashSet},
-    str::FromStr,
-    sync::{Mutex, PoisonError},
-    time::{Duration, Instant},
-};
-
-use base64::prelude::*;
-use cap_recording::screen_capture::ScreenCaptureTarget;
-
-use crate::exit_shutdown::{abort_join_handles, read_target_under_cursor};
-use crate::{
-    App, ArcLock, general_settings,
-    recording_settings::RecordingTargetMode,
-    window_exclusion::WindowExclusion,
-    windows::{CapWindowId, ShowCapWindow, hide_overlay},
-};
-use scap_targets::{
-    Display, DisplayId, Window, WindowId,
-    bounds::{LogicalBounds, LogicalSize, PhysicalSize},
-};
-use serde::Serialize;
-use specta::Type;
-use tauri::{AppHandle, Manager, WebviewWindow};
-use tauri_plugin_global_shortcut::{GlobalShortcut, GlobalShortcutExt};
-use tauri_specta::Event;
-use tokio::task::JoinHandle;
-use tracing::{debug, error, instrument};
-
-mod lifecycle;
-
-#[derive(tauri_specta::Event, Serialize, Type, Clone)]
-pub struct TargetUnderCursor {
-    display_id: Option,
-    window: Option,
-}
-
-#[derive(Serialize, Type, Clone)]
-pub struct WindowUnderCursor {
-    id: WindowId,
-    app_name: String,
-    bounds: LogicalBounds,
-}
-
-#[derive(Serialize, Type, Clone)]
-pub struct DisplayInformation {
-    name: Option,
-    physical_size: Option,
-    logical_size: Option,
-    logical_bounds: Option,
-    refresh_rate: String,
-}
-
-#[specta::specta]
-#[tauri::command]
-#[instrument(skip(app, state))]
-pub async fn open_target_select_overlays(
-    app: AppHandle,
-    state: tauri::State<'_, WindowFocusManager>,
-    focused_target: Option,
-    specific_display_id: Option,
-    target_mode: Option,
-) -> Result<(), String> {
-    let session = open_target_select_overlays_for_session(
-        app,
-        state.inner(),
-        focused_target,
-        specific_display_id,
-        target_mode,
-    )
-    .await?;
-    if state.picker_is_current(session) {
-        Ok(())
-    } else {
-        Err("Target selection cancelled".into())
-    }
-}
-
-pub(crate) async fn open_target_select_overlays_for_session(
-    app: AppHandle,
-    state: &WindowFocusManager,
-    focused_target: Option,
-    specific_display_id: Option,
-    target_mode: Option,
-) -> Result {
-    if crate::clean_capture::phase(&app).is_some() {
-        return Err(
-            "Close or finish clean Studio recording before opening the target picker".into(),
-        );
-    }
-    let start = Instant::now();
-    let picker_session = state.begin_picker();
-    state.register_escape(app.global_shortcut());
-
-    let resolved_specific_display_id = specific_display_id.as_ref().map(|id_str| {
-        id_str
-            .parse::()
-            .unwrap_or_else(|_| Display::primary().id())
-    });
-
-    let display_ids = if let Some(display_id) = resolved_specific_display_id.clone() {
-        vec![display_id]
-    } else if let Some(display) = focused_target.as_ref().and_then(|t| t.display()) {
-        vec![display.id()]
-    } else {
-        let displays = Display::list();
-        if displays.is_empty() {
-            vec![Display::primary().id()]
-        } else {
-            displays.into_iter().map(|display| display.id()).collect()
-        }
-    };
-
-    let focus_display_id = resolved_specific_display_id
-        .or_else(|| {
-            focused_target
-                .as_ref()
-                .and_then(|t| t.display())
-                .map(|d| d.id())
-        })
-        .or_else(|| Display::get_containing_cursor().map(|d| d.id()))
-        .unwrap_or_else(|| Display::primary().id());
-
-    for (id, window) in app.webview_windows() {
-        if let Ok(CapWindowId::TargetSelectOverlay {
-            display_id: existing_id,
-        }) = CapWindowId::from_str(&id)
-            && !display_ids
-                .iter()
-                .any(|display_id| display_id == &existing_id)
-        {
-            hide_overlay(&window);
-            state.destroy(&existing_id, app.global_shortcut());
-        }
-    }
-
-    for display_id in &display_ids {
-        if !state.picker_is_current(picker_session) {
-            return Ok(picker_session);
-        }
-        let should_focus = display_id == &focus_display_id;
-
-        let existing_window = CapWindowId::TargetSelectOverlay {
-            display_id: display_id.clone(),
-        }
-        .get(&app);
-
-        if let Some(window) = existing_window {
-            request_overlay_reveal(&window, picker_session, should_focus);
-
-            if should_focus {
-                focus_target_select_overlay(&window, picker_session);
-            }
-
-            state.spawn(display_id, window.clone(), picker_session);
-        } else if start.elapsed() < Duration::from_secs(1) {
-            if let Ok(window) = (ShowCapWindow::TargetSelectOverlay {
-                display_id: display_id.clone(),
-                target_mode,
-            })
-            .show_for_picker(&app, picker_session)
-            .await
-            {
-                finish_created_target_select_overlay(&window, should_focus, picker_session);
-            }
-        } else {
-            let app_clone = app.clone();
-            let display_id_clone = display_id.clone();
-            tokio::spawn(async move {
-                if let Ok(window) = (ShowCapWindow::TargetSelectOverlay {
-                    display_id: display_id_clone,
-                    target_mode,
-                })
-                .show_for_picker(&app_clone, picker_session)
-                .await
-                {
-                    finish_created_target_select_overlay(&window, should_focus, picker_session);
-                }
-            });
-        }
-    }
-
-    let focus_window = CapWindowId::TargetSelectOverlay {
-        display_id: focus_display_id,
-    }
-    .get(&app);
-
-    if let Some(window) = focus_window {
-        focus_target_select_overlay(&window, picker_session);
-    }
-
-    let window_exclusions = general_settings::GeneralSettingsStore::get(&app)
-        .ok()
-        .flatten()
-        .map_or_else(general_settings::default_excluded_windows, |settings| {
-            settings.excluded_windows
-        });
-
-    let handle = tokio::spawn({
-        let app = app.clone();
-
-        async move {
-            while let Some((display, window)) = read_target_under_cursor(
-                || {
-                    crate::app_is_exiting(&app)
-                        || !app
-                            .state::()
-                            .picker_is_current(picker_session)
-                },
-                || {
-                    focused_target
-                        .as_ref()
-                        .map(|v| v.display())
-                        .unwrap_or_else(scap_targets::Display::get_containing_cursor)
-                },
-                || {
-                    focused_target
-                        .as_ref()
-                        .map(|v| {
-                            v.window()
-                                .and_then(|id| scap_targets::Window::from_id(&id))
-                                .and_then(|window| {
-                                    describe_selectable_window(window, &window_exclusions)
-                                })
-                        })
-                        .unwrap_or_else(|| target_window_under_cursor(&window_exclusions))
-                },
-            ) {
-                let _ = TargetUnderCursor {
-                    display_id: display.map(|d| d.id()),
-                    window,
-                }
-                .emit(&app);
-
-                tokio::time::sleep(Duration::from_millis(50)).await;
-            }
-        }
-    });
-
-    let lifecycle = state
-        .lifecycle
-        .lock()
-        .unwrap_or_else(PoisonError::into_inner);
-    if !lifecycle.is_current(picker_session) {
-        handle.abort();
-        return Ok(picker_session);
-    }
-    if let Some(task) = state
-        .task
-        .lock()
-        .unwrap_or_else(PoisonError::into_inner)
-        .replace(handle)
-    {
-        task.abort();
-    }
-    drop(lifecycle);
-
-    Ok(picker_session)
-}
-
-fn describe_selectable_window(
-    window: Window,
-    exclusions: &[WindowExclusion],
-) -> Option {
-    if should_skip_window(&window, exclusions) {
-        return None;
-    }
-    Some(WindowUnderCursor {
-        id: window.id(),
-        bounds: window.display_relative_logical_bounds()?,
-        app_name: window.owner_name()?,
-    })
-}
-
-fn target_window_under_cursor(exclusions: &[WindowExclusion]) -> Option {
-    #[cfg(target_os = "linux")]
-    {
-        let own_pid = std::process::id();
-        let candidates = Window::list_containing_cursor()
-            .into_iter()
-            .filter_map(|window| {
-                let metadata = window.raw_handle().selection_metadata()?;
-                let title = if metadata.owner_pid == Some(own_pid) {
-                    window.name()
-                } else {
-                    None
-                };
-                Some(LinuxPickerCandidate {
-                    window,
-                    is_viewable: metadata.is_viewable,
-                    owner_pid: metadata.owner_pid,
-                    title,
-                })
-            });
-        first_linux_picker_target(candidates, own_pid, |window| {
-            describe_selectable_window(window, exclusions)
-        })
-    }
-
-    #[cfg(not(target_os = "linux"))]
-    Window::get_topmost_at_cursor()
-        .and_then(|window| describe_selectable_window(window, exclusions))
-}
-
-#[cfg(any(target_os = "linux", test))]
-struct LinuxPickerCandidate {
-    window: T,
-    is_viewable: bool,
-    owner_pid: Option,
-    title: Option,
-}
-
-#[cfg(any(target_os = "linux", test))]
-fn first_linux_picker_target(
-    candidates: impl IntoIterator>,
-    own_pid: u32,
-    mut describe: impl FnMut(T) -> Option,
-) -> Option {
-    candidates.into_iter().find_map(|candidate| {
-        if !candidate.is_viewable
-            || (candidate.owner_pid == Some(own_pid)
-                && candidate.title.as_deref() == Some("Cap Target Select"))
-        {
-            return None;
-        }
-        describe(candidate.window)
-    })
-}
-
-fn finish_created_target_select_overlay(
-    window: &WebviewWindow,
-    should_focus: bool,
-    picker_session: u32,
-) {
-    request_overlay_focus(window, picker_session, should_focus);
-}
-
-fn focus_target_select_overlay(window: &WebviewWindow, picker_session: u32) {
-    #[cfg(target_os = "macos")]
-    let _ = (window, picker_session);
-
-    #[cfg(not(target_os = "macos"))]
-    request_overlay_focus(window, picker_session, true);
-}
-
-pub(crate) fn request_overlay_reveal(window: &WebviewWindow, session: u32, focus: bool) {
-    let reveal = window
-        .app_handle()
-        .state::()
-        .lifecycle
-        .lock()
-        .unwrap_or_else(PoisonError::into_inner)
-        .request(window.label(), session, focus);
-    if let Some(reveal) = reveal {
-        schedule_ready_overlay(window, reveal);
-    }
-}
-
-pub(crate) fn restore_overlay_reveal(window: &WebviewWindow, session: u32) {
-    let reveal = window
-        .app_handle()
-        .state::()
-        .lifecycle
-        .lock()
-        .unwrap_or_else(PoisonError::into_inner)
-        .restore(window.label(), session, false);
-    if let Some(reveal) = reveal {
-        schedule_ready_overlay(window, reveal);
-    }
-}
-
-fn request_overlay_focus(window: &WebviewWindow, session: u32, focus: bool) {
-    let reveal = window
-        .app_handle()
-        .state::()
-        .lifecycle
-        .lock()
-        .unwrap_or_else(PoisonError::into_inner)
-        .focus(window.label(), session, focus);
-    if let Some(reveal) = reveal {
-        schedule_ready_overlay(window, reveal);
-    }
-}
-
-fn schedule_ready_overlay(window: &WebviewWindow, reveal: lifecycle::Reveal) {
-    let handle = window.clone();
-    let generation = crate::clean_capture::generation(window.app_handle());
-    let _ = window.run_on_main_thread(move || {
-        let focus = handle
-            .app_handle()
-            .state::()
-            .lifecycle
-            .lock()
-            .unwrap_or_else(PoisonError::into_inner)
-            .may_reveal(handle.label(), reveal);
-        let Some(focus) = focus else {
-            return;
-        };
-        if !matches!(
-            crate::clean_capture::reveal_now(&handle, generation),
-            Ok(true)
-        ) {
-            return;
-        }
-        if let Err(error) = handle.set_ignore_cursor_events(false) {
-            error!(%error, "Failed to enable target picker interaction");
-            hide_overlay(&handle);
-            return;
-        }
-        #[cfg(not(target_os = "macos"))]
-        if focus {
-            let _ = handle.set_focus();
-        }
-        #[cfg(target_os = "macos")]
-        if focus {
-            use tauri_nspanel::WebviewWindowExt;
-            if let Ok(panel) = handle.to_panel() {
-                panel.show();
-            }
-        }
-    });
-}
-
-pub(crate) fn mark_overlay_native_ready(window: &WebviewWindow, instance: u32) {
-    mark_overlay_ready(window, instance, false);
-}
-
-fn mark_overlay_ready(window: &WebviewWindow, instance: u32, frontend: bool) {
-    let reveal = window
-        .app_handle()
-        .state::()
-        .lifecycle
-        .lock()
-        .unwrap_or_else(PoisonError::into_inner)
-        .ready(window.label(), instance, frontend);
-    if let Some(reveal) = reveal {
-        schedule_ready_overlay(window, reveal);
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-pub fn target_select_overlay_ready(window: WebviewWindow, instance: u32) {
-    mark_overlay_ready(&window, instance, true);
-}
-
-fn should_skip_window(window: &Window, exclusions: &[WindowExclusion]) -> bool {
-    if exclusions.is_empty() {
-        return false;
-    }
-
-    let owner_name = window.owner_name();
-    let window_title = window.name();
-
-    #[cfg(target_os = "macos")]
-    let bundle_identifier = window.raw_handle().bundle_identifier();
-
-    #[cfg(not(target_os = "macos"))]
-    let bundle_identifier = None::;
-
-    exclusions.iter().any(|entry| {
-        entry.matches(
-            bundle_identifier.as_deref(),
-            owner_name.as_deref(),
-            window_title.as_deref(),
-        )
-    })
-}
-
-#[specta::specta]
-#[tauri::command]
-#[instrument(skip(app))]
-pub async fn update_camera_overlay_bounds(
-    app: AppHandle,
-    x: f64,
-    y: f64,
-    width: f64,
-    height: f64,
-) -> Result<(), String> {
-    let window = CapWindowId::Camera
-        .get(&app)
-        .ok_or("Camera window not found")?;
-
-    let width_u32 = width as u32;
-    let height_u32 = height as u32;
-
-    window
-        .set_size(tauri::Size::Physical(tauri::PhysicalSize {
-            width: width_u32,
-            height: height_u32,
-        }))
-        .map_err(|e| e.to_string())?;
-    window
-        .set_position(tauri::Position::Physical(tauri::PhysicalPosition {
-            x: x as i32,
-            y: y as i32,
-        }))
-        .map_err(|e| e.to_string())?;
-
-    let scale_factor = window.scale_factor().unwrap_or(1.0);
-    let logical_width = (width / scale_factor) as u32;
-    let logical_height = (height / scale_factor) as u32;
-
-    let state = app.state::>();
-    let app_state = state.read().await;
-    app_state
-        .camera_preview
-        .notify_window_resized(logical_width, logical_height);
-
-    Ok(())
-}
-
-#[specta::specta]
-#[tauri::command]
-#[instrument(skip(app, _state))]
-pub async fn close_target_select_overlays(
-    app: AppHandle,
-    _state: tauri::State<'_, WindowFocusManager>,
-) -> Result<(), String> {
-    close_target_select_overlay_windows(&app);
-
-    Ok(())
-}
-
-#[specta::specta]
-#[tauri::command]
-pub fn suspend_target_select_overlays(app: AppHandle) {
-    let state = app.state::();
-    state.shutdown(&app);
-    state.clear_overlay_restore_labels();
-    for (label, window) in app.webview_windows() {
-        if matches!(
-            CapWindowId::from_str(&label),
-            Ok(CapWindowId::TargetSelectOverlay { .. })
-        ) {
-            hide_overlay(&window);
-        }
-    }
-}
-
-pub fn close_target_select_overlay_windows(app: &AppHandle) {
-    let state = app.try_state::();
-    let mut saw_overlay = false;
-
-    if let Some(state) = state.as_ref() {
-        state.cancel_picker();
-        state.clear_overlay_restore_labels();
-    }
-
-    for (id, window) in app.webview_windows() {
-        if let Ok(CapWindowId::TargetSelectOverlay { display_id }) = CapWindowId::from_str(&id) {
-            saw_overlay = true;
-            // On Windows, hide() leaves the DirectComposition transparency surface composited on
-            // screen (ghost overlay). Closing the window fully releases the surface.
-            hide_overlay(&window);
-            #[cfg(windows)]
-            let _ = window.close();
-            if let Some(state) = state.as_ref() {
-                state.destroy(&display_id, app.global_shortcut());
-            }
-        }
-    }
-
-    if !saw_overlay && let Some(state) = state {
-        state.shutdown(app);
-    }
-}
-
-pub(crate) fn dismiss_picker_from_escape(app: &AppHandle) {
-    let Some(session) = app.state::().picker_session() else {
-        return;
-    };
-    let owner = CapWindowId::Main.get(app);
-    close_target_select_overlay_windows(app);
-    if let Some(owner) = owner {
-        let app = app.clone();
-        let generation = crate::clean_capture::generation(&app);
-        let _ = owner.clone().run_on_main_thread(move || {
-            let cancelled = app
-                .state::()
-                .lifecycle
-                .lock()
-                .unwrap_or_else(PoisonError::into_inner)
-                .is_cancelled(session);
-            let idle = app
-                .state::>()
-                .try_read()
-                .is_ok_and(|state| !state.is_recording_active_or_pending());
-            if cancelled
-                && idle
-                && matches!(
-                    crate::clean_capture::reveal_now(&owner, generation),
-                    Ok(true)
-                )
-            {
-                let _ = owner.set_focus();
-            }
-        });
-    }
-}
-
-#[specta::specta]
-#[tauri::command]
-#[instrument]
-pub async fn get_window_icon(window_id: &str) -> Result, String> {
-    let window_id = window_id
-        .parse::()
-        .map_err(|err| format!("Invalid window ID: {err}"))?;
-
-    Ok(Window::from_id(&window_id)
-        .ok_or("Window not found")?
-        .app_icon()
-        .map(|bytes| format!("data:image/png;base64,{}", BASE64_STANDARD.encode(&bytes))))
-}
-
-#[specta::specta]
-#[tauri::command]
-#[instrument]
-pub async fn display_information(display_id: &str) -> Result {
-    let display_id = display_id
-        .parse::()
-        .map_err(|err| format!("Invalid display ID: {err}"))?;
-    let display = Display::from_id(&display_id).ok_or("Display not found")?;
-
-    Ok(DisplayInformation {
-        name: display.name(),
-        physical_size: display.physical_size(),
-        logical_size: display.logical_size(),
-        logical_bounds: display.raw_handle().logical_bounds(),
-        refresh_rate: display.refresh_rate().to_string(),
-    })
-}
-
-#[specta::specta]
-#[tauri::command]
-#[instrument]
-pub async fn focus_window(window_id: WindowId) -> Result<(), String> {
-    #[cfg(any(target_os = "macos", target_os = "windows"))]
-    let window = Window::from_id(&window_id).ok_or("Window not found")?;
-    #[cfg(not(any(target_os = "macos", target_os = "windows")))]
-    Window::from_id(&window_id).ok_or("Window not found")?;
-
-    #[cfg(target_os = "macos")]
-    {
-        use objc2_app_kit::{NSApplicationActivationOptions, NSRunningApplication};
-
-        let pid = window
-            .raw_handle()
-            .owner_pid()
-            .ok_or("Could not get window owner PID")?;
-
-        if let Some(app) =
-            unsafe { NSRunningApplication::runningApplicationWithProcessIdentifier(pid) }
-        {
-            unsafe {
-                app.activateWithOptions(NSApplicationActivationOptions::ActivateIgnoringOtherApps);
-            }
-        }
-    }
-
-    #[cfg(target_os = "windows")]
-    {
-        use windows::Win32::UI::WindowsAndMessaging::{
-            GetWindowPlacement, IsIconic, SW_RESTORE, SetForegroundWindow, SetWindowPlacement,
-            ShowWindow, WINDOWPLACEMENT,
-        };
-
-        let hwnd = window.raw_handle().inner();
-
-        unsafe {
-            // Only restore if the window is actually minimized
-            if IsIconic(hwnd).as_bool() {
-                // Get current window placement to preserve size/position
-                let mut wp = WINDOWPLACEMENT {
-                    length: std::mem::size_of::() as u32,
-                    ..Default::default()
-                };
-
-                if GetWindowPlacement(hwnd, &mut wp).is_ok() {
-                    // Restore using the previous placement to avoid resizing
-                    wp.showCmd = SW_RESTORE.0 as u32;
-                    let _ = SetWindowPlacement(hwnd, &wp);
-                } else {
-                    // Fallback to simple restore if placement fails
-                    let _ = ShowWindow(hwnd, SW_RESTORE);
-                }
-            }
-
-            // Always try to bring to foreground
-            let _ = SetForegroundWindow(hwnd);
-        }
-    }
-
-    Ok(())
-}
-
-#[derive(Default)]
-pub struct WindowFocusManager {
-    lifecycle: Mutex,
-    pub(crate) creation: tokio::sync::Mutex<()>,
-    task: Mutex>>,
-    tasks: Mutex>>,
-    escape_registered: Mutex,
-    restore_overlay_labels: Mutex>,
-}
-
-impl WindowFocusManager {
-    pub(crate) fn begin_picker(&self) -> u32 {
-        self.lifecycle
-            .lock()
-            .unwrap_or_else(PoisonError::into_inner)
-            .begin()
-    }
-
-    pub(crate) fn picker_session(&self) -> Option {
-        self.lifecycle
-            .lock()
-            .unwrap_or_else(PoisonError::into_inner)
-            .current()
-    }
-
-    pub(crate) fn picker_is_current(&self, session: u32) -> bool {
-        self.lifecycle
-            .lock()
-            .unwrap_or_else(PoisonError::into_inner)
-            .is_current(session)
-    }
-
-    pub(crate) fn cancel_picker(&self) -> bool {
-        self.lifecycle
-            .lock()
-            .unwrap_or_else(PoisonError::into_inner)
-            .cancel()
-    }
-
-    pub(crate) fn register_overlay(&self, label: &str, session: u32) -> Option {
-        self.lifecycle
-            .lock()
-            .unwrap_or_else(PoisonError::into_inner)
-            .register(label, session)
-    }
-
-    pub(crate) fn suspend_overlay(&self, label: &str) {
-        self.lifecycle
-            .lock()
-            .unwrap_or_else(PoisonError::into_inner)
-            .suspend(label);
-    }
-
-    pub(crate) fn suspend_all_overlays(&self) {
-        self.lifecycle
-            .lock()
-            .unwrap_or_else(PoisonError::into_inner)
-            .suspend_all();
-    }
-
-    fn abort_all_tasks(&self) {
-        let tasks = {
-            let mut tasks = self.tasks.lock().unwrap_or_else(PoisonError::into_inner);
-            tasks.drain().map(|(_, task)| task).collect::>()
-        };
-        let task = self
-            .task
-            .lock()
-            .unwrap_or_else(PoisonError::into_inner)
-            .take();
-        abort_join_handles(tasks, task);
-    }
-
-    pub fn spawn(&self, id: &DisplayId, window: WebviewWindow, picker_session: u32) {
-        let display_id = id.clone();
-        let task_id = id.to_string();
-        let handle = tokio::spawn(async move {
-            let app = window.app_handle();
-            let mut main_window_was_seen = false;
-
-            loop {
-                if crate::app_is_exiting(app)
-                    || !app
-                        .state::()
-                        .picker_is_current(picker_session)
-                {
-                    break;
-                }
-
-                let cap_main = CapWindowId::Main.get(app);
-                let cap_settings = CapWindowId::Settings.get(app);
-
-                let main_window_available = cap_main.is_some();
-                let settings_window_available = cap_settings.is_some();
-
-                if main_window_available || settings_window_available {
-                    main_window_was_seen = true;
-                }
-
-                if main_window_was_seen && !main_window_available && !settings_window_available {
-                    hide_overlay(&window);
-                    app.state::()
-                        .finish(&display_id, app.global_shortcut());
-                    break;
-                }
-
-                #[cfg(windows)]
-                if window.is_visible().unwrap_or(false)
-                    && let Some(cap_main) = cap_main
-                {
-                    // Every overlay window (one per display) runs this loop. Checking only
-                    // `window`/main focus made each inactive overlay steal focus from the
-                    // overlay the user is interacting with on multi-monitor setups, firing a
-                    // `blur` that cancelled the in-progress crop drag. Focus held by any
-                    // overlay is fine, so only refocus when nothing of ours is focused.
-                    let overlay_focused = app.webview_windows().iter().any(|(label, other)| {
-                        matches!(
-                            CapWindowId::from_str(label),
-                            Ok(CapWindowId::TargetSelectOverlay { .. })
-                        ) && other.is_focused().unwrap_or(false)
-                    });
-
-                    let should_refocus =
-                        overlay_focused || cap_main.is_focused().ok().unwrap_or_default();
-
-                    if !should_refocus {
-                        request_overlay_focus(&window, picker_session, true);
-                    }
-                }
-
-                tokio::time::sleep(std::time::Duration::from_millis(400)).await;
-            }
-        });
-
-        let lifecycle = self
-            .lifecycle
-            .lock()
-            .unwrap_or_else(PoisonError::into_inner);
-        if !lifecycle.is_current(picker_session) {
-            handle.abort();
-            return;
-        }
-        let mut tasks = self.tasks.lock().unwrap_or_else(PoisonError::into_inner);
-        if let Some(task) = tasks.insert(task_id, handle) {
-            task.abort();
-        }
-    }
-
-    pub fn remember_overlay_for_restore(&self, label: String) {
-        let mut labels = self
-            .restore_overlay_labels
-            .lock()
-            .unwrap_or_else(PoisonError::into_inner);
-        labels.insert(label);
-    }
-
-    pub fn take_overlay_restore_labels(&self) -> HashSet {
-        let mut labels = self
-            .restore_overlay_labels
-            .lock()
-            .unwrap_or_else(PoisonError::into_inner);
-        std::mem::take(&mut *labels)
-    }
-
-    pub fn clear_overlay_restore_labels(&self) {
-        let mut labels = self
-            .restore_overlay_labels
-            .lock()
-            .unwrap_or_else(PoisonError::into_inner);
-        labels.clear();
-    }
-
-    fn finish(&self, id: &DisplayId, global_shortcut: &GlobalShortcut) {
-        let mut tasks = self.tasks.lock().unwrap_or_else(PoisonError::into_inner);
-        tasks.remove(&id.to_string());
-        drop(tasks);
-
-        self.finish_if_idle(global_shortcut);
-    }
-
-    fn finish_if_idle(&self, global_shortcut: &GlobalShortcut) {
-        let idle = self
-            .tasks
-            .lock()
-            .unwrap_or_else(PoisonError::into_inner)
-            .is_empty();
-        if idle && self.picker_session().is_none() {
-            self.unregister_escape(global_shortcut);
-
-            if let Some(task) = self
-                .task
-                .lock()
-                .unwrap_or_else(PoisonError::into_inner)
-                .take()
-            {
-                task.abort();
-            }
-        }
-    }
-
-    /// Called when a specific overlay window is destroyed to cleanup it's resources
-    pub fn destroy(&self, id: &DisplayId, global_shortcut: &GlobalShortcut) {
-        let mut tasks = self.tasks.lock().unwrap_or_else(PoisonError::into_inner);
-        if let Some(task) = tasks.remove(&id.to_string()) {
-            task.abort();
-        }
-        drop(tasks);
-
-        self.finish_if_idle(global_shortcut);
-    }
-
-    pub fn shutdown(&self, app: &AppHandle) {
-        self.cancel_picker();
-        self.abort_all_tasks();
-
-        self.unregister_escape(app.global_shortcut());
-    }
-
-    fn register_escape(&self, global_shortcut: &GlobalShortcut) {
-        let mut registered = self
-            .escape_registered
-            .lock()
-            .unwrap_or_else(PoisonError::into_inner);
-        if *registered {
-            return;
-        }
-
-        match global_shortcut.register("Escape") {
-            Ok(()) => *registered = true,
-            Err(err) => error!("Error registering global keyboard shortcut for Escape: {err}"),
-        }
-    }
-
-    fn unregister_escape(&self, global_shortcut: &GlobalShortcut) {
-        {
-            let mut registered = self
-                .escape_registered
-                .lock()
-                .unwrap_or_else(PoisonError::into_inner);
-            if !*registered {
-                return;
-            }
-            *registered = false;
-        }
-
-        if let Err(err) = global_shortcut.unregister("Escape") {
-            debug!("Error unregistering global keyboard shortcut for Escape: {err}");
-        }
-    }
-}
-
-#[cfg(test)]
-mod linux_picker_tests {
-    use super::{LinuxPickerCandidate, WindowExclusion, first_linux_picker_target};
-
-    fn candidate(
-        title: &'static str,
-        owner_pid: Option,
-        is_viewable: bool,
-    ) -> LinuxPickerCandidate<&'static str> {
-        LinuxPickerCandidate {
-            window: title,
-            is_viewable,
-            owner_pid,
-            title: Some(title.into()),
-        }
-    }
-
-    #[test]
-    fn selects_underlying_window_after_picker_and_configured_exclusion() {
-        let exclusion = WindowExclusion {
-            bundle_identifier: None,
-            owner_name: Some("Cap".into()),
-            window_title: Some("Cap Camera".into()),
-        };
-        let candidates = [
-            candidate("Cap Target Select", Some(42), true),
-            candidate("Cap Camera", Some(42), true),
-            candidate("Moving fixture", Some(100), true),
-            candidate("Lower window", Some(101), true),
-        ];
-        let mut described = Vec::new();
-
-        let selected = first_linux_picker_target(candidates, 42, |title| {
-            described.push(title);
-            (!exclusion.matches(None, Some("Cap"), Some(title))).then_some(title)
-        });
-
-        assert_eq!(selected, Some("Moving fixture"));
-        assert_eq!(described, ["Cap Camera", "Moving fixture"]);
-    }
-
-    #[test]
-    fn skips_own_picker_when_no_windows_are_configured_for_exclusion() {
-        let candidates = [
-            candidate("Cap Target Select", Some(42), true),
-            candidate("Cap Camera", Some(42), true),
-            candidate("Moving fixture", Some(100), true),
-        ];
-
-        assert_eq!(
-            first_linux_picker_target(candidates, 42, Some),
-            Some("Cap Camera")
-        );
-    }
-
-    #[test]
-    fn does_not_exclude_foreign_or_unknown_owner_by_picker_title() {
-        for owner_pid in [Some(100), None] {
-            let candidates = [
-                candidate("Cap Target Select", owner_pid, true),
-                candidate("Moving fixture", Some(101), true),
-            ];
-
-            assert_eq!(
-                first_linux_picker_target(candidates, 42, Some),
-                Some("Cap Target Select")
-            );
-        }
-    }
-
-    #[test]
-    fn bypasses_unmapped_and_undescribable_windows_without_reordering() {
-        let candidates = [
-            candidate("Hidden window", Some(100), false),
-            candidate("Destroyed window", Some(101), true),
-            candidate("Moving fixture", Some(102), true),
-            candidate("Lower window", Some(103), true),
-        ];
-        let mut described = Vec::new();
-
-        let selected = first_linux_picker_target(candidates, 42, |title| {
-            described.push(title);
-            (title != "Destroyed window").then_some(title)
-        });
-
-        assert_eq!(selected, Some("Moving fixture"));
-        assert_eq!(described, ["Destroyed window", "Moving fixture"]);
-    }
-
-    #[test]
-    fn returns_no_target_when_every_candidate_is_ineligible() {
-        let candidates = [
-            candidate("Cap Target Select", Some(42), true),
-            candidate("Hidden window", Some(100), false),
-            candidate("Excluded window", Some(101), true),
-        ];
-        let mut described = Vec::new();
-
-        let selected = first_linux_picker_target(candidates, 42, |title| {
-            described.push(title);
-            None::<&str>
-        });
-
-        assert!(selected.is_none());
-        assert_eq!(described, ["Excluded window"]);
-    }
-}
diff --git a/apps/desktop/src-tauri/src/target_select_overlay/lifecycle.rs b/apps/desktop/src-tauri/src/target_select_overlay/lifecycle.rs
deleted file mode 100644
index cd5bfa336c7..00000000000
--- a/apps/desktop/src-tauri/src/target_select_overlay/lifecycle.rs
+++ /dev/null
@@ -1,262 +0,0 @@
-use std::collections::HashMap;
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub(super) struct Reveal {
-    pub session: u32,
-    pub instance: u32,
-}
-
-#[derive(Default)]
-struct Window {
-    instance: u32,
-    requested: bool,
-    frontend_ready: bool,
-    native_ready: bool,
-    focus: bool,
-}
-
-#[derive(Default)]
-pub(super) struct Lifecycle {
-    session: u32,
-    next_instance: u32,
-    active: bool,
-    accepting_requests: bool,
-    windows: HashMap,
-}
-
-impl Lifecycle {
-    pub fn begin(&mut self) -> u32 {
-        self.session = self.session.wrapping_add(1);
-        self.active = true;
-        self.accepting_requests = true;
-        for window in self.windows.values_mut() {
-            window.requested = false;
-        }
-        self.session
-    }
-
-    pub fn current(&self) -> Option {
-        self.active.then_some(self.session)
-    }
-
-    pub fn is_current(&self, session: u32) -> bool {
-        self.current() == Some(session)
-    }
-
-    pub fn is_cancelled(&self, session: u32) -> bool {
-        !self.active && self.session == session
-    }
-
-    pub fn cancel(&mut self) -> bool {
-        let active = self.active;
-        self.active = false;
-        for window in self.windows.values_mut() {
-            window.requested = false;
-        }
-        active
-    }
-
-    pub fn register(&mut self, label: &str, session: u32) -> Option {
-        if !self.is_current(session) {
-            return None;
-        }
-        self.next_instance = self.next_instance.checked_add(1)?;
-        self.windows.insert(
-            label.to_string(),
-            Window {
-                instance: self.next_instance,
-                requested: self.accepting_requests,
-                ..Default::default()
-            },
-        );
-        Some(self.next_instance)
-    }
-
-    pub fn request(&mut self, label: &str, session: u32, focus: bool) -> Option {
-        if !self.accepting_requests {
-            return None;
-        }
-        self.restore(label, session, focus)
-    }
-
-    pub fn suspend_all(&mut self) {
-        self.accepting_requests = false;
-        for window in self.windows.values_mut() {
-            window.requested = false;
-        }
-    }
-
-    pub fn restore(&mut self, label: &str, session: u32, focus: bool) -> Option {
-        if !self.is_current(session) {
-            return None;
-        }
-        let window = self.windows.get_mut(label)?;
-        window.requested = true;
-        window.focus = focus;
-        Some(Reveal {
-            session,
-            instance: window.instance,
-        })
-    }
-
-    pub fn focus(&mut self, label: &str, session: u32, focus: bool) -> Option {
-        if !self.is_current(session) {
-            return None;
-        }
-        let window = self.windows.get_mut(label)?;
-        if !window.requested {
-            return None;
-        }
-        window.focus = focus;
-        Some(Reveal {
-            session,
-            instance: window.instance,
-        })
-    }
-
-    pub fn suspend(&mut self, label: &str) {
-        if let Some(window) = self.windows.get_mut(label) {
-            window.requested = false;
-        }
-    }
-
-    pub fn ready(&mut self, label: &str, instance: u32, frontend: bool) -> Option {
-        let window = self.windows.get_mut(label)?;
-        if window.instance != instance {
-            return None;
-        }
-        if frontend {
-            window.frontend_ready = true;
-        } else {
-            window.native_ready = true;
-        }
-        Some(Reveal {
-            session: self.session,
-            instance,
-        })
-    }
-
-    pub fn may_reveal(&self, label: &str, reveal: Reveal) -> Option {
-        if !self.is_current(reveal.session) {
-            return None;
-        }
-        self.windows.get(label).and_then(|window| {
-            (window.instance == reveal.instance
-                && window.requested
-                && window.frontend_ready
-                && window.native_ready)
-                .then_some(window.focus)
-        })
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    fn prepared(lifecycle: &mut Lifecycle, label: &str, session: u32) -> Reveal {
-        let instance = lifecycle.register(label, session).unwrap();
-        lifecycle.ready(label, instance, true).unwrap();
-        lifecycle.ready(label, instance, false).unwrap()
-    }
-
-    #[test]
-    fn both_native_and_frontend_readiness_are_required_in_either_order() {
-        for first in [true, false] {
-            let mut lifecycle = Lifecycle::default();
-            let session = lifecycle.begin();
-            let instance = lifecycle.register("overlay", session).unwrap();
-            let reveal = lifecycle.request("overlay", session, true).unwrap();
-            assert_eq!(lifecycle.may_reveal("overlay", reveal), None);
-            lifecycle.ready("overlay", instance, first).unwrap();
-            assert_eq!(lifecycle.may_reveal("overlay", reveal), None);
-            lifecycle.ready("overlay", instance, !first).unwrap();
-            assert_eq!(lifecycle.may_reveal("overlay", reveal), Some(true));
-        }
-    }
-
-    #[test]
-    fn cancel_rejects_late_creation_readiness_and_queued_reveals() {
-        let mut lifecycle = Lifecycle::default();
-        let session = lifecycle.begin();
-        let reveal = prepared(&mut lifecycle, "first", session);
-        assert!(lifecycle.cancel());
-        assert!(!lifecycle.cancel());
-        assert!(lifecycle.register("late", session).is_none());
-        lifecycle.ready("first", reveal.instance, true).unwrap();
-        assert_eq!(lifecycle.may_reveal("first", reveal), None);
-        assert!(lifecycle.request("first", session, true).is_none());
-    }
-
-    #[test]
-    fn new_session_reuses_ready_windows_without_accepting_old_callbacks() {
-        let mut lifecycle = Lifecycle::default();
-        let first = lifecycle.begin();
-        let stale = prepared(&mut lifecycle, "overlay", first);
-        lifecycle.cancel();
-        let second = lifecycle.begin();
-        let current = lifecycle.request("overlay", second, false).unwrap();
-        assert_eq!(lifecycle.may_reveal("overlay", stale), None);
-        assert_eq!(lifecycle.may_reveal("overlay", current), Some(false));
-        assert!(lifecycle.request("overlay", first, true).is_none());
-    }
-
-    #[test]
-    fn replaced_window_cannot_be_revealed_by_destroyed_frontend() {
-        let mut lifecycle = Lifecycle::default();
-        let session = lifecycle.begin();
-        let old = prepared(&mut lifecycle, "overlay", session);
-        let replacement = lifecycle.register("overlay", session).unwrap();
-        let reveal = lifecycle.ready("overlay", replacement, false).unwrap();
-        assert!(lifecycle.ready("overlay", old.instance, true).is_none());
-        assert_eq!(lifecycle.may_reveal("overlay", old), None);
-        assert_eq!(lifecycle.may_reveal("overlay", reveal), None);
-        lifecycle.ready("overlay", replacement, true).unwrap();
-        assert_eq!(lifecycle.may_reveal("overlay", reveal), Some(false));
-    }
-
-    #[test]
-    fn modal_hiding_cannot_be_undone_by_readiness_or_a_queued_reveal() {
-        let mut lifecycle = Lifecycle::default();
-        let session = lifecycle.begin();
-        let reveal = prepared(&mut lifecycle, "overlay", session);
-        lifecycle.suspend("overlay");
-        lifecycle.ready("overlay", reveal.instance, true).unwrap();
-        assert_eq!(lifecycle.may_reveal("overlay", reveal), None);
-        assert!(lifecycle.focus("overlay", session, true).is_none());
-        let restored = lifecycle.request("overlay", session, true).unwrap();
-        assert_eq!(lifecycle.may_reveal("overlay", restored), Some(true));
-    }
-
-    #[test]
-    fn modal_suspends_pending_displays_until_explicit_restore_or_a_new_session() {
-        let mut lifecycle = Lifecycle::default();
-        let session = lifecycle.begin();
-        let first = prepared(&mut lifecycle, "one", session);
-        lifecycle.suspend_all();
-        let late = prepared(&mut lifecycle, "late", session);
-        assert_eq!(lifecycle.may_reveal("one", first), None);
-        assert_eq!(lifecycle.may_reveal("late", late), None);
-        assert!(lifecycle.request("one", session, true).is_none());
-        let restored = lifecycle.restore("one", session, true).unwrap();
-        assert_eq!(lifecycle.may_reveal("one", restored), Some(true));
-        assert_eq!(lifecycle.may_reveal("late", late), None);
-        let next = lifecycle.begin();
-        let reopened = lifecycle.request("late", next, true).unwrap();
-        assert_eq!(lifecycle.may_reveal("late", reopened), Some(true));
-    }
-
-    #[test]
-    fn displays_are_independent_and_cancelled_sessions_do_not_restore() {
-        let mut lifecycle = Lifecycle::default();
-        let session = lifecycle.begin();
-        let first = prepared(&mut lifecycle, "one", session);
-        let second = prepared(&mut lifecycle, "two", session);
-        lifecycle.suspend("one");
-        assert_eq!(lifecycle.may_reveal("one", first), None);
-        assert_eq!(lifecycle.may_reveal("two", second), Some(false));
-        lifecycle.cancel();
-        assert!(lifecycle.request("one", session, false).is_none());
-        assert_eq!(lifecycle.may_reveal("two", second), None);
-    }
-}
diff --git a/apps/desktop/src-tauri/src/telemetry.rs b/apps/desktop/src-tauri/src/telemetry.rs
deleted file mode 100644
index 10d1d908667..00000000000
--- a/apps/desktop/src-tauri/src/telemetry.rs
+++ /dev/null
@@ -1,468 +0,0 @@
-use serde::Serialize;
-use serde_json::{Map, Value};
-use std::{
-    sync::{
-        OnceLock, PoisonError, RwLock,
-        atomic::{AtomicBool, Ordering},
-    },
-    time::Duration,
-};
-use tauri::AppHandle;
-use tracing::debug;
-
-use crate::auth::AuthStore;
-
-/// Baked in at compile time so self-built binaries send nothing.
-const CLIENT_ID: Option<&str> = option_env!("VITE_OPENPANEL_CLIENT_ID");
-/// `/track` accepts origin-allowlisted requests without a client secret — the
-/// same auth path the webview SDK uses — so no credential ships in the binary.
-/// Must stay on the OpenPanel client's CORS allowlist alongside the webview
-/// origins.
-const ORIGIN: &str = "tauri://localhost";
-const API_URL: Option<&str> = option_env!("VITE_OPENPANEL_API_URL");
-const DEFAULT_API_URL: &str = "https://api.openpanel.dev";
-
-#[derive(Debug)]
-pub enum AnalyticsEvent {
-    MultipartUploadComplete {
-        duration: Duration,
-        length: Duration,
-        size: u64,
-    },
-    MultipartUploadFailed {
-        duration: Duration,
-        error: String,
-    },
-    RecordingStarted {
-        mode: &'static str,
-        target_kind: &'static str,
-        has_camera: bool,
-        has_mic: bool,
-        has_system_audio: bool,
-        target_fps: u32,
-        target_width: u32,
-        target_height: u32,
-        fragmented: bool,
-        custom_cursor_capture: bool,
-    },
-    RecordingCompleted {
-        mode: &'static str,
-        status: &'static str,
-        duration_secs: u64,
-        segment_count: u32,
-        track_failure_count: u32,
-        error_class: Option,
-        video_frames_captured: u64,
-        video_frames_dropped: u64,
-        drop_rate_pct: f64,
-        capture_stalls_count: u64,
-        capture_stalls_max_ms: u64,
-        mixer_stalls_count: u64,
-        mixer_stalls_max_ms: u64,
-        audio_gaps_count: u64,
-        audio_gaps_total_ms: u64,
-        frame_drop_rate_high_count: u64,
-        source_restarts_count: u64,
-        muxer_crash_count: u64,
-        audio_degraded_count: u64,
-        dropped_mic_messages: u64,
-    },
-    RecordingMuxerCrashed {
-        mode: &'static str,
-        reason: String,
-        seconds_into_recording: f64,
-    },
-    RecordingAudioDegraded {
-        mode: &'static str,
-        reason: String,
-        seconds_into_recording: f64,
-    },
-    RecordingRecovered {
-        trigger: &'static str,
-        recovered_duration_secs: u64,
-        segments_recovered: u32,
-        validation_took_ms: u64,
-    },
-    RecordingRecoveryFailed {
-        trigger: &'static str,
-        reason: String,
-    },
-    RecordingDiskSpaceLow {
-        mode: &'static str,
-        bytes_remaining: u64,
-    },
-    RecordingDiskSpaceExhausted {
-        mode: &'static str,
-        bytes_remaining: u64,
-    },
-    RecordingDeviceLost {
-        mode: &'static str,
-        subsystem: String,
-    },
-    RecordingEncoderRebuilt {
-        mode: &'static str,
-        backend: String,
-        attempt: u32,
-    },
-    RecordingSourceAudioReset {
-        mode: &'static str,
-        source: String,
-        starvation_ms: u64,
-    },
-    RecordingCaptureTargetLost {
-        mode: &'static str,
-        target: String,
-    },
-}
-
-fn truncate_reason(mut s: String) -> String {
-    const MAX_LEN: usize = 240;
-    if s.len() > MAX_LEN {
-        // Reasons carry NSError debug strings whose localized text is
-        // multi-byte; String::truncate panics off a char boundary.
-        let end = (0..=MAX_LEN)
-            .rev()
-            .find(|&i| s.is_char_boundary(i))
-            .unwrap_or(0);
-        s.truncate(end);
-        s.push('…');
-    }
-    s
-}
-
-fn analytics_event(event: AnalyticsEvent) -> (&'static str, Map) {
-    fn set(props: &mut Map, key: &str, value: impl Into) {
-        props.insert(key.to_string(), value.into());
-    }
-
-    let mut props = Map::new();
-
-    match event {
-        AnalyticsEvent::MultipartUploadComplete {
-            duration,
-            length,
-            size,
-        } => {
-            set(&mut props, "duration", duration.as_secs());
-            set(&mut props, "length", length.as_secs());
-            set(&mut props, "size", size);
-            ("multipart_upload_complete", props)
-        }
-        AnalyticsEvent::MultipartUploadFailed { duration, error } => {
-            set(&mut props, "duration", duration.as_secs());
-            set(&mut props, "error", truncate_reason(error));
-            ("multipart_upload_failed", props)
-        }
-        AnalyticsEvent::RecordingStarted {
-            mode,
-            target_kind,
-            has_camera,
-            has_mic,
-            has_system_audio,
-            target_fps,
-            target_width,
-            target_height,
-            fragmented,
-            custom_cursor_capture,
-        } => {
-            set(&mut props, "mode", mode);
-            set(&mut props, "target_kind", target_kind);
-            set(&mut props, "has_camera", has_camera);
-            set(&mut props, "has_mic", has_mic);
-            set(&mut props, "has_system_audio", has_system_audio);
-            set(&mut props, "target_fps", target_fps);
-            set(&mut props, "target_width", target_width);
-            set(&mut props, "target_height", target_height);
-            set(&mut props, "fragmented", fragmented);
-            set(&mut props, "custom_cursor_capture", custom_cursor_capture);
-            ("recording_started", props)
-        }
-        AnalyticsEvent::RecordingCompleted {
-            mode,
-            status,
-            duration_secs,
-            segment_count,
-            track_failure_count,
-            error_class,
-            video_frames_captured,
-            video_frames_dropped,
-            drop_rate_pct,
-            capture_stalls_count,
-            capture_stalls_max_ms,
-            mixer_stalls_count,
-            mixer_stalls_max_ms,
-            audio_gaps_count,
-            audio_gaps_total_ms,
-            frame_drop_rate_high_count,
-            source_restarts_count,
-            muxer_crash_count,
-            audio_degraded_count,
-            dropped_mic_messages,
-        } => {
-            set(&mut props, "mode", mode);
-            set(&mut props, "status", status);
-            set(&mut props, "duration_secs", duration_secs);
-            set(&mut props, "segment_count", segment_count);
-            set(&mut props, "track_failure_count", track_failure_count);
-            if let Some(ec) = error_class {
-                set(&mut props, "error_class", truncate_reason(ec));
-            }
-            set(&mut props, "video_frames_captured", video_frames_captured);
-            set(&mut props, "video_frames_dropped", video_frames_dropped);
-            set(
-                &mut props,
-                "drop_rate_pct",
-                (drop_rate_pct * 100.0).round() / 100.0,
-            );
-            set(&mut props, "capture_stalls_count", capture_stalls_count);
-            set(&mut props, "capture_stalls_max_ms", capture_stalls_max_ms);
-            set(&mut props, "mixer_stalls_count", mixer_stalls_count);
-            set(&mut props, "mixer_stalls_max_ms", mixer_stalls_max_ms);
-            set(&mut props, "audio_gaps_count", audio_gaps_count);
-            set(&mut props, "audio_gaps_total_ms", audio_gaps_total_ms);
-            set(
-                &mut props,
-                "frame_drop_rate_high_count",
-                frame_drop_rate_high_count,
-            );
-            set(&mut props, "source_restarts_count", source_restarts_count);
-            set(&mut props, "muxer_crash_count", muxer_crash_count);
-            set(&mut props, "audio_degraded_count", audio_degraded_count);
-            set(&mut props, "dropped_mic_messages", dropped_mic_messages);
-            ("recording_completed", props)
-        }
-        AnalyticsEvent::RecordingMuxerCrashed {
-            mode,
-            reason,
-            seconds_into_recording,
-        } => {
-            set(&mut props, "mode", mode);
-            set(&mut props, "reason", truncate_reason(reason));
-            set(
-                &mut props,
-                "seconds_into_recording",
-                (seconds_into_recording * 1000.0).round() / 1000.0,
-            );
-            ("recording_muxer_crashed", props)
-        }
-        AnalyticsEvent::RecordingAudioDegraded {
-            mode,
-            reason,
-            seconds_into_recording,
-        } => {
-            set(&mut props, "mode", mode);
-            set(&mut props, "reason", truncate_reason(reason));
-            set(
-                &mut props,
-                "seconds_into_recording",
-                (seconds_into_recording * 1000.0).round() / 1000.0,
-            );
-            ("recording_audio_degraded", props)
-        }
-        AnalyticsEvent::RecordingRecovered {
-            trigger,
-            recovered_duration_secs,
-            segments_recovered,
-            validation_took_ms,
-        } => {
-            set(&mut props, "trigger", trigger);
-            set(
-                &mut props,
-                "recovered_duration_secs",
-                recovered_duration_secs,
-            );
-            set(&mut props, "segments_recovered", segments_recovered);
-            set(&mut props, "validation_took_ms", validation_took_ms);
-            ("recording_recovered", props)
-        }
-        AnalyticsEvent::RecordingRecoveryFailed { trigger, reason } => {
-            set(&mut props, "trigger", trigger);
-            set(&mut props, "reason", truncate_reason(reason));
-            ("recording_recovery_failed", props)
-        }
-        AnalyticsEvent::RecordingDiskSpaceLow {
-            mode,
-            bytes_remaining,
-        } => {
-            set(&mut props, "mode", mode);
-            set(&mut props, "bytes_remaining", bytes_remaining);
-            ("recording_disk_space_low", props)
-        }
-        AnalyticsEvent::RecordingDiskSpaceExhausted {
-            mode,
-            bytes_remaining,
-        } => {
-            set(&mut props, "mode", mode);
-            set(&mut props, "bytes_remaining", bytes_remaining);
-            ("recording_disk_space_exhausted", props)
-        }
-        AnalyticsEvent::RecordingDeviceLost { mode, subsystem } => {
-            set(&mut props, "mode", mode);
-            set(&mut props, "subsystem", subsystem);
-            ("recording_device_lost", props)
-        }
-        AnalyticsEvent::RecordingEncoderRebuilt {
-            mode,
-            backend,
-            attempt,
-        } => {
-            set(&mut props, "mode", mode);
-            set(&mut props, "backend", backend);
-            set(&mut props, "attempt", attempt);
-            ("recording_encoder_rebuilt", props)
-        }
-        AnalyticsEvent::RecordingSourceAudioReset {
-            mode,
-            source,
-            starvation_ms,
-        } => {
-            set(&mut props, "mode", mode);
-            set(&mut props, "source", source);
-            set(&mut props, "starvation_ms", starvation_ms);
-            ("recording_source_audio_reset", props)
-        }
-        AnalyticsEvent::RecordingCaptureTargetLost { mode, target } => {
-            set(&mut props, "mode", mode);
-            set(&mut props, "target", target);
-            ("recording_capture_target_lost", props)
-        }
-    }
-}
-
-#[derive(Serialize)]
-struct TrackPayload {
-    name: &'static str,
-    properties: Map,
-    /// Omitted entirely when signed out, so OpenPanel records an anonymous
-    /// device event instead of attributing it to a profile.
-    #[serde(rename = "profileId", skip_serializing_if = "Option::is_none")]
-    profile_id: Option,
-}
-
-#[derive(Serialize)]
-struct TrackBody {
-    #[serde(rename = "type")]
-    kind: &'static str,
-    payload: TrackPayload,
-}
-
-static HTTP_CLIENT: OnceLock = OnceLock::new();
-
-fn http_client() -> &'static reqwest::Client {
-    HTTP_CLIENT.get_or_init(|| {
-        // OpenPanel derives device/OS breakdowns from the user agent.
-        let user_agent = format!(
-            "Cap/{} ({}; {})",
-            env!("CARGO_PKG_VERSION"),
-            std::env::consts::OS,
-            std::env::consts::ARCH
-        );
-        reqwest::Client::builder()
-            .user_agent(user_agent)
-            .timeout(Duration::from_secs(10))
-            .build()
-            .unwrap_or_default()
-    })
-}
-
-fn track_url() -> String {
-    let base = API_URL.unwrap_or(DEFAULT_API_URL).trim_end_matches('/');
-    format!("{base}/track")
-}
-
-pub fn init() {
-    if CLIENT_ID.is_none() {
-        return;
-    }
-
-    // Building the client loads the platform root certificates, so do it off
-    // the startup path rather than on the first event.
-    tokio::spawn(async {
-        http_client();
-    });
-}
-
-pub fn set_server_url(url: &str) {
-    *API_SERVER_IS_CAP_CLOUD
-        .get_or_init(Default::default)
-        .write()
-        .unwrap_or_else(PoisonError::into_inner) = Some(url == "https://cap.so");
-}
-
-static API_SERVER_IS_CAP_CLOUD: OnceLock>> = OnceLock::new();
-
-static TELEMETRY_ENABLED: AtomicBool = AtomicBool::new(true);
-
-pub fn set_telemetry_enabled(enabled: bool) {
-    TELEMETRY_ENABLED.store(enabled, Ordering::Release);
-}
-
-pub fn telemetry_enabled() -> bool {
-    TELEMETRY_ENABLED.load(Ordering::Acquire)
-}
-
-pub fn async_capture_event(app: &AppHandle, event: AnalyticsEvent) {
-    let Some(client_id) = CLIENT_ID else {
-        return;
-    };
-
-    let live_enabled = crate::general_settings::GeneralSettingsStore::get(app)
-        .ok()
-        .flatten()
-        .map(|s| s.enable_telemetry)
-        .unwrap_or_else(telemetry_enabled);
-    TELEMETRY_ENABLED.store(live_enabled, Ordering::Release);
-    if !live_enabled {
-        return;
-    }
-
-    let profile_id = AuthStore::get(app)
-        .ok()
-        .flatten()
-        .and_then(|auth| auth.user_id);
-
-    tokio::spawn(async move {
-        let (name, mut properties) = analytics_event(event);
-
-        properties.insert("cap_version".into(), env!("CARGO_PKG_VERSION").into());
-        properties.insert(
-            "cap_backend".into(),
-            match *API_SERVER_IS_CAP_CLOUD
-                .get_or_init(Default::default)
-                .read()
-                .unwrap_or_else(PoisonError::into_inner)
-            {
-                Some(true) => "cloud",
-                Some(false) => "self_hosted",
-                None => "unknown",
-            }
-            .into(),
-        );
-        properties.insert("os".into(), std::env::consts::OS.into());
-        properties.insert("arch".into(), std::env::consts::ARCH.into());
-
-        let body = TrackBody {
-            kind: "track",
-            payload: TrackPayload {
-                name,
-                properties,
-                profile_id,
-            },
-        };
-
-        let req = http_client()
-            .post(track_url())
-            .header("openpanel-client-id", client_id)
-            .header("origin", ORIGIN);
-
-        // Events are best-effort: log and drop, never retry.
-        match req.json(&body).send().await {
-            Ok(res) if res.status().is_success() => {}
-            Ok(res) => debug!(
-                "OpenPanel rejected event {name}: HTTP {}",
-                res.status().as_u16()
-            ),
-            Err(err) => debug!("Error sending event {name} to OpenPanel: {err:?}"),
-        }
-    });
-}
diff --git a/apps/desktop/src-tauri/src/thumbnails/linux.rs b/apps/desktop/src-tauri/src/thumbnails/linux.rs
deleted file mode 100644
index f163cce7bad..00000000000
--- a/apps/desktop/src-tauri/src/thumbnails/linux.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-use cap_recording::screenshot::capture_screenshot;
-use cap_recording::sources::screen_capture::ScreenCaptureTarget;
-use image::{ImageEncoder, codecs::png::PngEncoder};
-use std::io::Cursor;
-
-use super::*;
-
-pub async fn capture_display_thumbnail(display: &scap_targets::Display) -> Option {
-    capture_target_thumbnail(ScreenCaptureTarget::Display { id: display.id() }).await
-}
-
-pub async fn capture_window_thumbnail(window: &scap_targets::Window) -> Option {
-    capture_target_thumbnail(ScreenCaptureTarget::Window { id: window.id() }).await
-}
-
-async fn capture_target_thumbnail(target: ScreenCaptureTarget) -> Option {
-    if cap_recording::screenshot::uses_wayland_portal() {
-        return None;
-    }
-
-    let image = match capture_screenshot(target).await {
-        Ok(image) => image,
-        Err(error) => {
-            warn!(error = %error, "Failed to capture thumbnail on Linux");
-            return None;
-        }
-    };
-
-    let rgba = image.to_rgba8();
-    if rgba.width() == 0 || rgba.height() == 0 {
-        return None;
-    }
-
-    let thumbnail = normalize_thumbnail_dimensions(&rgba);
-    let mut png_data = Cursor::new(Vec::new());
-    let encoder = PngEncoder::new(&mut png_data);
-    if let Err(error) = encoder.write_image(
-        thumbnail.as_raw(),
-        thumbnail.width(),
-        thumbnail.height(),
-        image::ColorType::Rgba8.into(),
-    ) {
-        warn!(error = %error, "Failed to encode Linux thumbnail as PNG");
-        return None;
-    }
-
-    Some(base64::Engine::encode(
-        &base64::engine::general_purpose::STANDARD,
-        png_data.into_inner(),
-    ))
-}
diff --git a/apps/desktop/src-tauri/src/thumbnails/mac.rs b/apps/desktop/src-tauri/src/thumbnails/mac.rs
deleted file mode 100644
index a6367973824..00000000000
--- a/apps/desktop/src-tauri/src/thumbnails/mac.rs
+++ /dev/null
@@ -1,377 +0,0 @@
-use cidre::{arc, sc};
-
-use crate::platform::get_shareable_content;
-
-use super::*;
-
-pub async fn capture_display_thumbnail(display: &scap_targets::Display) -> Option {
-    let content = get_shareable_content().await.ok()??;
-
-    let filter = display.raw_handle().as_content_filter(content)?;
-    capture_thumbnail_from_filter(filter).await
-}
-
-pub async fn capture_window_thumbnail(window: &scap_targets::Window) -> Option {
-    let content = get_shareable_content().await.ok()??;
-
-    let sc_window = window.raw_handle().as_sc(content)?;
-    let filter = cidre::sc::ContentFilter::with_desktop_independent_window(&sc_window);
-    capture_thumbnail_from_filter(filter).await
-}
-
-async fn capture_thumbnail_from_filter(filter: arc::R) -> Option {
-    use cidre::{cv, sc};
-    use image::{ImageEncoder, RgbaImage, codecs::png::PngEncoder};
-    use std::io::Cursor;
-
-    let mut config = sc::StreamCfg::new();
-    config.set_width(THUMBNAIL_WIDTH as usize);
-    config.set_height(THUMBNAIL_HEIGHT as usize);
-    config.set_shows_cursor(false);
-
-    let sample_buf = match unsafe {
-        sc::ScreenshotManager::capture_sample_buf(filter.as_ref(), &config)
-    }
-    .await
-    {
-        Ok(buf) => buf,
-        Err(err) => {
-            warn!(error = ?err, "Failed to capture sample buffer for thumbnail");
-            return None;
-        }
-    };
-
-    let Some(image_buf) = sample_buf.image_buf() else {
-        warn!("Sample buffer missing image data");
-        return None;
-    };
-    let mut image_buf = image_buf.retained();
-
-    let width = image_buf.width();
-    let height = image_buf.height();
-    if width == 0 || height == 0 {
-        warn!(
-            width = width,
-            height = height,
-            "Captured thumbnail had empty dimensions"
-        );
-        return None;
-    }
-
-    let pixel_format = image_buf.pixel_format();
-
-    let lock =
-        match PixelBufferLock::new(image_buf.as_mut(), cv::pixel_buffer::LockFlags::READ_ONLY) {
-            Ok(lock) => lock,
-            Err(err) => {
-                warn!(error = ?err, "Failed to lock pixel buffer for thumbnail");
-                return None;
-            }
-        };
-
-    let rgba_data = match pixel_format {
-        cv::PixelFormat::_32_BGRA
-        | cv::PixelFormat::_32_RGBA
-        | cv::PixelFormat::_32_ARGB
-        | cv::PixelFormat::_32_ABGR => {
-            convert_32bit_pixel_buffer(&lock, width, height, pixel_format)?
-        }
-        cv::PixelFormat::_420V => {
-            convert_nv12_pixel_buffer(&lock, width, height, Nv12Range::Video)?
-        }
-        other => {
-            warn!(?other, "Unsupported pixel format for thumbnail capture");
-            return None;
-        }
-    };
-
-    let Some(img) = RgbaImage::from_raw(width as u32, height as u32, rgba_data) else {
-        warn!("Failed to construct RGBA image for thumbnail");
-        return None;
-    };
-    let thumbnail = normalize_thumbnail_dimensions(&img);
-    let mut png_data = Cursor::new(Vec::new());
-    let encoder = PngEncoder::new(&mut png_data);
-    if let Err(err) = encoder.write_image(
-        thumbnail.as_raw(),
-        thumbnail.width(),
-        thumbnail.height(),
-        image::ColorType::Rgba8.into(),
-    ) {
-        warn!(error = ?err, "Failed to encode thumbnail as PNG");
-        return None;
-    }
-
-    Some(base64::Engine::encode(
-        &base64::engine::general_purpose::STANDARD,
-        png_data.into_inner(),
-    ))
-}
-
-fn convert_32bit_pixel_buffer(
-    lock: &PixelBufferLock<'_>,
-    width: usize,
-    height: usize,
-    pixel_format: cidre::cv::PixelFormat,
-) -> Option> {
-    let base_ptr = lock.base_address();
-    if base_ptr.is_null() {
-        warn!("Pixel buffer base address was null");
-        return None;
-    }
-
-    let bytes_per_row = lock.bytes_per_row();
-    let total_len = bytes_per_row.checked_mul(height)?;
-    let raw_data = unsafe { std::slice::from_raw_parts(base_ptr, total_len) };
-
-    let mut rgba_data = Vec::with_capacity(width * height * 4);
-    for y in 0..height {
-        let row_start = y * bytes_per_row;
-        let row_end = row_start + width * 4;
-        if row_end > raw_data.len() {
-            warn!(
-                row_start = row_start,
-                row_end = row_end,
-                raw_len = raw_data.len(),
-                "Row bounds exceeded raw data length during thumbnail capture",
-            );
-            return None;
-        }
-
-        let row = &raw_data[row_start..row_end];
-        for chunk in row.chunks_exact(4) {
-            match pixel_format {
-                cidre::cv::PixelFormat::_32_BGRA => {
-                    rgba_data.extend_from_slice(&[chunk[2], chunk[1], chunk[0], chunk[3]])
-                }
-                cidre::cv::PixelFormat::_32_RGBA => rgba_data.extend_from_slice(chunk),
-                cidre::cv::PixelFormat::_32_ARGB => {
-                    rgba_data.extend_from_slice(&[chunk[1], chunk[2], chunk[3], chunk[0]])
-                }
-                cidre::cv::PixelFormat::_32_ABGR => {
-                    rgba_data.extend_from_slice(&[chunk[3], chunk[2], chunk[1], chunk[0]])
-                }
-                _ => unreachable!(),
-            }
-        }
-    }
-
-    Some(rgba_data)
-}
-
-#[derive(Copy, Clone)]
-enum Nv12Range {
-    Video,
-    _Full,
-}
-
-fn convert_nv12_pixel_buffer(
-    lock: &PixelBufferLock<'_>,
-    width: usize,
-    height: usize,
-    range: Nv12Range,
-) -> Option> {
-    let y_base = lock.base_address_of_plane(0);
-    let uv_base = lock.base_address_of_plane(1);
-    if y_base.is_null() || uv_base.is_null() {
-        warn!("NV12 plane base address was null");
-        return None;
-    }
-
-    let y_stride = lock.bytes_per_row_of_plane(0);
-    let uv_stride = lock.bytes_per_row_of_plane(1);
-    if y_stride == 0 || uv_stride == 0 {
-        warn!(y_stride, uv_stride, "NV12 plane bytes per row was zero");
-        return None;
-    }
-
-    let y_plane_height = lock.height_of_plane(0);
-    let uv_plane_height = lock.height_of_plane(1);
-    if y_plane_height < height || uv_plane_height < height.div_ceil(2) {
-        warn!(
-            y_plane_height,
-            uv_plane_height,
-            expected_y = height,
-            expected_uv = height.div_ceil(2),
-            "NV12 plane height smaller than expected",
-        );
-        return None;
-    }
-
-    let y_plane = unsafe { std::slice::from_raw_parts(y_base, y_stride * y_plane_height) };
-    let uv_plane = unsafe { std::slice::from_raw_parts(uv_base, uv_stride * uv_plane_height) };
-
-    let mut rgba_data = vec![0u8; width * height * 4];
-
-    for y_idx in 0..height {
-        let y_row_start = y_idx * y_stride;
-        if y_row_start + width > y_plane.len() {
-            warn!(
-                y_row_start,
-                width,
-                y_plane_len = y_plane.len(),
-                "Y row exceeded plane length during conversion",
-            );
-            return None;
-        }
-        let y_row = &y_plane[y_row_start..y_row_start + width];
-
-        let uv_row_start = (y_idx / 2) * uv_stride;
-        if uv_row_start + width > uv_plane.len() {
-            warn!(
-                uv_row_start,
-                width,
-                uv_plane_len = uv_plane.len(),
-                "UV row exceeded plane length during conversion",
-            );
-            return None;
-        }
-        let uv_row = &uv_plane[uv_row_start..uv_row_start + width];
-
-        for (x, y_val) in y_row.iter().enumerate().take(width) {
-            let uv_index = (x / 2) * 2;
-            if uv_index + 1 >= uv_row.len() {
-                warn!(
-                    uv_index,
-                    uv_row_len = uv_row.len(),
-                    "UV index out of bounds during conversion",
-                );
-                return None;
-            }
-
-            let cb = uv_row[uv_index];
-            let cr = uv_row[uv_index + 1];
-            let (r, g, b) = ycbcr_to_rgb(*y_val, cb, cr, range);
-            let out = (y_idx * width + x) * 4;
-            rgba_data[out] = r;
-            rgba_data[out + 1] = g;
-            rgba_data[out + 2] = b;
-            rgba_data[out + 3] = 255;
-        }
-    }
-
-    Some(rgba_data)
-}
-
-fn ycbcr_to_rgb(y: u8, cb: u8, cr: u8, range: Nv12Range) -> (u8, u8, u8) {
-    let y = y as f32;
-    let cb = cb as f32 - 128.0;
-    let cr = cr as f32 - 128.0;
-
-    let (y_value, scale) = match range {
-        Nv12Range::Video => ((y - 16.0).max(0.0), 1.164383_f32),
-        Nv12Range::_Full => (y, 1.0_f32),
-    };
-
-    let r = scale * y_value + 1.596027_f32 * cr;
-    let g = scale * y_value - 0.391762_f32 * cb - 0.812968_f32 * cr;
-    let b = scale * y_value + 2.017232_f32 * cb;
-
-    (clamp_channel(r), clamp_channel(g), clamp_channel(b))
-}
-
-fn clamp_channel(value: f32) -> u8 {
-    value.clamp(0.0, 255.0) as u8
-}
-
-struct PixelBufferLock<'a> {
-    buffer: &'a mut cidre::cv::PixelBuf,
-    flags: cidre::cv::pixel_buffer::LockFlags,
-}
-
-impl<'a> PixelBufferLock<'a> {
-    fn new(
-        buffer: &'a mut cidre::cv::PixelBuf,
-        flags: cidre::cv::pixel_buffer::LockFlags,
-    ) -> cidre::os::Result {
-        unsafe { buffer.lock_base_addr(flags) }.result()?;
-        Ok(Self { buffer, flags })
-    }
-
-    fn base_address(&self) -> *const u8 {
-        unsafe { cv_pixel_buffer_get_base_address(self.buffer) as *const u8 }
-    }
-
-    fn bytes_per_row(&self) -> usize {
-        unsafe { cv_pixel_buffer_get_bytes_per_row(self.buffer) }
-    }
-
-    fn base_address_of_plane(&self, plane_index: usize) -> *const u8 {
-        unsafe { cv_pixel_buffer_get_base_address_of_plane(self.buffer, plane_index) as *const u8 }
-    }
-
-    fn bytes_per_row_of_plane(&self, plane_index: usize) -> usize {
-        unsafe { cv_pixel_buffer_get_bytes_per_row_of_plane(self.buffer, plane_index) }
-    }
-
-    fn height_of_plane(&self, plane_index: usize) -> usize {
-        unsafe { cv_pixel_buffer_get_height_of_plane(self.buffer, plane_index) }
-    }
-}
-
-impl Drop for PixelBufferLock<'_> {
-    fn drop(&mut self) {
-        unsafe {
-            let _ = self.buffer.unlock_lock_base_addr(self.flags);
-        }
-    }
-}
-
-unsafe fn cv_pixel_buffer_get_base_address(buffer: &cidre::cv::PixelBuf) -> *mut std::ffi::c_void {
-    unsafe extern "C" {
-        fn CVPixelBufferGetBaseAddress(pixel_buffer: &cidre::cv::PixelBuf)
-        -> *mut std::ffi::c_void;
-    }
-
-    unsafe { CVPixelBufferGetBaseAddress(buffer) }
-}
-
-unsafe fn cv_pixel_buffer_get_bytes_per_row(buffer: &cidre::cv::PixelBuf) -> usize {
-    unsafe extern "C" {
-        fn CVPixelBufferGetBytesPerRow(pixel_buffer: &cidre::cv::PixelBuf) -> usize;
-    }
-
-    unsafe { CVPixelBufferGetBytesPerRow(buffer) }
-}
-
-unsafe fn cv_pixel_buffer_get_base_address_of_plane(
-    buffer: &cidre::cv::PixelBuf,
-    plane_index: usize,
-) -> *mut std::ffi::c_void {
-    unsafe extern "C" {
-        fn CVPixelBufferGetBaseAddressOfPlane(
-            pixel_buffer: &cidre::cv::PixelBuf,
-            plane_index: usize,
-        ) -> *mut std::ffi::c_void;
-    }
-
-    unsafe { CVPixelBufferGetBaseAddressOfPlane(buffer, plane_index) }
-}
-
-unsafe fn cv_pixel_buffer_get_bytes_per_row_of_plane(
-    buffer: &cidre::cv::PixelBuf,
-    plane_index: usize,
-) -> usize {
-    unsafe extern "C" {
-        fn CVPixelBufferGetBytesPerRowOfPlane(
-            pixel_buffer: &cidre::cv::PixelBuf,
-            plane_index: usize,
-        ) -> usize;
-    }
-
-    unsafe { CVPixelBufferGetBytesPerRowOfPlane(buffer, plane_index) }
-}
-
-unsafe fn cv_pixel_buffer_get_height_of_plane(
-    buffer: &cidre::cv::PixelBuf,
-    plane_index: usize,
-) -> usize {
-    unsafe extern "C" {
-        fn CVPixelBufferGetHeightOfPlane(
-            pixel_buffer: &cidre::cv::PixelBuf,
-            plane_index: usize,
-        ) -> usize;
-    }
-
-    unsafe { CVPixelBufferGetHeightOfPlane(buffer, plane_index) }
-}
diff --git a/apps/desktop/src-tauri/src/thumbnails/mod.rs b/apps/desktop/src-tauri/src/thumbnails/mod.rs
deleted file mode 100644
index 085ed5e2509..00000000000
--- a/apps/desktop/src-tauri/src/thumbnails/mod.rs
+++ /dev/null
@@ -1,137 +0,0 @@
-use cap_recording::sources::screen_capture::{list_displays, list_windows};
-use serde::{Deserialize, Serialize};
-use specta::Type;
-use tracing::*;
-
-#[cfg(windows)]
-mod windows;
-#[cfg(windows)]
-pub use windows::*;
-
-#[cfg(target_os = "macos")]
-mod mac;
-#[cfg(target_os = "macos")]
-pub use mac::*;
-
-#[cfg(target_os = "linux")]
-mod linux;
-#[cfg(target_os = "linux")]
-pub use linux::*;
-
-const THUMBNAIL_WIDTH: u32 = 320;
-const THUMBNAIL_HEIGHT: u32 = 180;
-
-#[derive(Debug, Clone, Serialize, Deserialize, Type)]
-pub struct CaptureDisplayWithThumbnail {
-    pub id: scap_targets::DisplayId,
-    pub name: String,
-    pub refresh_rate: u32,
-    pub thumbnail: Option,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, Type)]
-pub struct CaptureWindowWithThumbnail {
-    pub id: scap_targets::WindowId,
-    pub owner_name: String,
-    pub name: String,
-    pub bounds: scap_targets::bounds::LogicalBounds,
-    pub refresh_rate: u32,
-    pub thumbnail: Option,
-    pub app_icon: Option,
-    pub bundle_identifier: Option,
-}
-
-pub fn normalize_thumbnail_dimensions(image: &image::RgbaImage) -> image::RgbaImage {
-    let width = image.width();
-    let height = image.height();
-
-    if width == THUMBNAIL_WIDTH && height == THUMBNAIL_HEIGHT {
-        return image.clone();
-    }
-
-    if width == 0 || height == 0 {
-        return image::RgbaImage::from_pixel(
-            THUMBNAIL_WIDTH,
-            THUMBNAIL_HEIGHT,
-            image::Rgba([0, 0, 0, 0]),
-        );
-    }
-
-    let scale = (THUMBNAIL_WIDTH as f32 / width as f32)
-        .min(THUMBNAIL_HEIGHT as f32 / height as f32)
-        .max(f32::MIN_POSITIVE);
-
-    let scaled_width = (width as f32 * scale)
-        .round()
-        .clamp(1.0, THUMBNAIL_WIDTH as f32) as u32;
-    let scaled_height = (height as f32 * scale)
-        .round()
-        .clamp(1.0, THUMBNAIL_HEIGHT as f32) as u32;
-
-    let resized = image::imageops::resize(
-        image,
-        scaled_width.max(1),
-        scaled_height.max(1),
-        image::imageops::FilterType::Lanczos3,
-    );
-
-    let mut canvas =
-        image::RgbaImage::from_pixel(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, image::Rgba([0, 0, 0, 0]));
-
-    let offset_x = (THUMBNAIL_WIDTH - scaled_width) / 2;
-    let offset_y = (THUMBNAIL_HEIGHT - scaled_height) / 2;
-
-    image::imageops::overlay(&mut canvas, &resized, offset_x as i64, offset_y as i64);
-
-    canvas
-}
-
-pub async fn collect_displays_with_thumbnails() -> Result, String>
-{
-    let displays = list_displays();
-
-    let mut results = Vec::new();
-    for (capture_display, display) in displays {
-        let thumbnail = capture_display_thumbnail(&display).await;
-        results.push(CaptureDisplayWithThumbnail {
-            id: capture_display.id,
-            name: capture_display.name,
-            refresh_rate: capture_display.refresh_rate,
-            thumbnail,
-        });
-    }
-
-    Ok(results)
-}
-
-pub async fn collect_windows_with_thumbnails() -> Result, String> {
-    let windows = list_windows();
-
-    let mut results = Vec::new();
-    for (capture_window, window) in windows {
-        let thumbnail = capture_window_thumbnail(&window).await;
-        let app_icon = window.app_icon().and_then(|bytes| {
-            if bytes.is_empty() {
-                None
-            } else {
-                Some(base64::Engine::encode(
-                    &base64::engine::general_purpose::STANDARD,
-                    bytes,
-                ))
-            }
-        });
-
-        results.push(CaptureWindowWithThumbnail {
-            id: capture_window.id,
-            name: capture_window.name,
-            owner_name: capture_window.owner_name,
-            bounds: capture_window.bounds,
-            refresh_rate: capture_window.refresh_rate,
-            thumbnail,
-            app_icon,
-            bundle_identifier: capture_window.bundle_identifier,
-        });
-    }
-
-    Ok(results)
-}
diff --git a/apps/desktop/src-tauri/src/thumbnails/windows.rs b/apps/desktop/src-tauri/src/thumbnails/windows.rs
deleted file mode 100644
index dde0fae69aa..00000000000
--- a/apps/desktop/src-tauri/src/thumbnails/windows.rs
+++ /dev/null
@@ -1,287 +0,0 @@
-use super::*;
-
-pub async fn capture_display_thumbnail(display: &scap_targets::Display) -> Option {
-    use image::{ColorType, ImageEncoder, codecs::png::PngEncoder};
-    use scap_direct3d::{Capturer, Settings};
-    use std::io::Cursor;
-
-    let item = display.raw_handle().try_as_capture_item().ok()?;
-
-    let (tx, rx) = std::sync::mpsc::channel();
-
-    let mut settings = Settings {
-        is_cursor_capture_enabled: Some(false),
-        pixel_format: scap_direct3d::PixelFormat::R8G8B8A8Unorm,
-        ..Default::default()
-    };
-
-    if let Ok(true) = Settings::can_is_border_required() {
-        settings.is_border_required = Some(false);
-    }
-
-    let mut capturer = Capturer::new(
-        item,
-        settings.clone(),
-        move |frame| {
-            let _ = tx.send(frame);
-            Ok(())
-        },
-        || Ok(()),
-        None,
-    )
-    .ok()?;
-
-    capturer.start().ok()?;
-
-    let frame = rx.recv_timeout(std::time::Duration::from_secs(2)).ok()?;
-    let _ = capturer.stop();
-
-    let width = frame.width();
-    let height = frame.height();
-
-    if width == 0 || height == 0 {
-        return None;
-    }
-
-    let frame_buffer = frame.as_buffer().ok()?;
-    let data = frame_buffer.data();
-    let stride = frame_buffer.stride() as usize;
-
-    let width_usize = width as usize;
-    let height_usize = height as usize;
-
-    let Some(row_bytes) = width_usize.checked_mul(4) else {
-        warn!(
-            frame_width = width,
-            "Windows display thumbnail row size overflowed"
-        );
-        return None;
-    };
-
-    if stride < row_bytes {
-        warn!(
-            frame_width = width,
-            frame_height = height,
-            stride,
-            expected_row_bytes = row_bytes,
-            "Windows display thumbnail stride smaller than row size"
-        );
-        return None;
-    }
-
-    let rows_before_last = height_usize.saturating_sub(1);
-    let Some(last_row_start) = rows_before_last.checked_mul(stride) else {
-        warn!(
-            frame_width = width,
-            frame_height = height,
-            stride,
-            "Windows display thumbnail row offset overflowed"
-        );
-        return None;
-    };
-
-    let Some(required_len) = last_row_start.checked_add(row_bytes) else {
-        warn!(
-            frame_width = width,
-            frame_height = height,
-            stride,
-            required_row_bytes = row_bytes,
-            "Windows display thumbnail required length overflowed"
-        );
-        return None;
-    };
-
-    if data.len() < required_len {
-        warn!(
-            frame_width = width,
-            frame_height = height,
-            stride,
-            frame_data_len = data.len(),
-            expected_len = required_len,
-            "Windows display thumbnail frame buffer missing pixel data"
-        );
-        return None;
-    }
-
-    let Some(rgba_capacity) = height_usize.checked_mul(row_bytes) else {
-        warn!(
-            frame_width = width,
-            frame_height = height,
-            total_row_bytes = row_bytes,
-            "Windows display thumbnail RGBA capacity overflowed"
-        );
-        return None;
-    };
-
-    let mut rgba_data = Vec::with_capacity(rgba_capacity);
-    for y in 0..height_usize {
-        let row_start = y * stride;
-        let row_end = row_start + row_bytes;
-        rgba_data.extend_from_slice(&data[row_start..row_end]);
-    }
-
-    let Some(img) = image::RgbaImage::from_raw(width, height, rgba_data) else {
-        warn!("Windows display thumbnail failed to construct RGBA image");
-        return None;
-    };
-    let thumbnail = normalize_thumbnail_dimensions(&img);
-
-    let mut png_data = Cursor::new(Vec::new());
-    let encoder = PngEncoder::new(&mut png_data);
-    encoder
-        .write_image(
-            thumbnail.as_raw(),
-            thumbnail.width(),
-            thumbnail.height(),
-            ColorType::Rgba8.into(),
-        )
-        .ok()?;
-
-    Some(base64::Engine::encode(
-        &base64::engine::general_purpose::STANDARD,
-        png_data.into_inner(),
-    ))
-}
-
-pub async fn capture_window_thumbnail(window: &scap_targets::Window) -> Option {
-    use image::{ColorType, ImageEncoder, codecs::png::PngEncoder};
-    use scap_direct3d::{Capturer, Settings};
-    use std::io::Cursor;
-
-    let item = window.raw_handle().try_as_capture_item().ok()?;
-
-    let (tx, rx) = std::sync::mpsc::channel();
-
-    let mut settings = Settings {
-        is_cursor_capture_enabled: Some(false),
-        pixel_format: scap_direct3d::PixelFormat::R8G8B8A8Unorm,
-        ..Default::default()
-    };
-
-    if let Ok(true) = Settings::can_is_border_required() {
-        settings.is_border_required = Some(false);
-    }
-
-    let mut capturer = Capturer::new(
-        item,
-        settings.clone(),
-        move |frame| {
-            let _ = tx.send(frame);
-            Ok(())
-        },
-        || Ok(()),
-        None,
-    )
-    .ok()?;
-
-    capturer.start().ok()?;
-
-    let frame = rx.recv_timeout(std::time::Duration::from_secs(2)).ok()?;
-    let _ = capturer.stop();
-
-    let width = frame.width();
-    let height = frame.height();
-
-    if width == 0 || height == 0 {
-        return None;
-    }
-
-    let frame_buffer = frame.as_buffer().ok()?;
-    let data = frame_buffer.data();
-    let stride = frame_buffer.stride() as usize;
-
-    let width_usize = width as usize;
-    let height_usize = height as usize;
-
-    let Some(row_bytes) = width_usize.checked_mul(4) else {
-        warn!(
-            frame_width = width,
-            "Windows window thumbnail row size overflowed"
-        );
-        return None;
-    };
-
-    if stride < row_bytes {
-        warn!(
-            frame_width = width,
-            frame_height = height,
-            stride,
-            expected_row_bytes = row_bytes,
-            "Windows window thumbnail stride smaller than row size"
-        );
-        return None;
-    }
-
-    let rows_before_last = height_usize.saturating_sub(1);
-    let Some(last_row_start) = rows_before_last.checked_mul(stride) else {
-        warn!(
-            frame_width = width,
-            frame_height = height,
-            stride,
-            "Windows window thumbnail row offset overflowed"
-        );
-        return None;
-    };
-
-    let Some(required_len) = last_row_start.checked_add(row_bytes) else {
-        warn!(
-            frame_width = width,
-            frame_height = height,
-            stride,
-            required_row_bytes = row_bytes,
-            "Windows window thumbnail required length overflowed"
-        );
-        return None;
-    };
-
-    if data.len() < required_len {
-        warn!(
-            frame_width = width,
-            frame_height = height,
-            stride,
-            frame_data_len = data.len(),
-            expected_len = required_len,
-            "Windows window thumbnail frame buffer missing pixel data"
-        );
-        return None;
-    }
-
-    let Some(rgba_capacity) = height_usize.checked_mul(row_bytes) else {
-        warn!(
-            frame_width = width,
-            frame_height = height,
-            total_row_bytes = row_bytes,
-            "Windows window thumbnail RGBA capacity overflowed"
-        );
-        return None;
-    };
-
-    let mut rgba_data = Vec::with_capacity(rgba_capacity);
-    for y in 0..height_usize {
-        let row_start = y * stride;
-        let row_end = row_start + row_bytes;
-        rgba_data.extend_from_slice(&data[row_start..row_end]);
-    }
-
-    let Some(img) = image::RgbaImage::from_raw(width, height, rgba_data) else {
-        warn!("Windows window thumbnail failed to construct RGBA image");
-        return None;
-    };
-    let thumbnail = normalize_thumbnail_dimensions(&img);
-
-    let mut png_data = Cursor::new(Vec::new());
-    let encoder = PngEncoder::new(&mut png_data);
-    encoder
-        .write_image(
-            thumbnail.as_raw(),
-            thumbnail.width(),
-            thumbnail.height(),
-            ColorType::Rgba8.into(),
-        )
-        .ok()?;
-
-    Some(base64::Engine::encode(
-        &base64::engine::general_purpose::STANDARD,
-        png_data.into_inner(),
-    ))
-}
diff --git a/apps/desktop/src-tauri/src/tray.rs b/apps/desktop/src-tauri/src/tray.rs
deleted file mode 100644
index 562ac852c24..00000000000
--- a/apps/desktop/src-tauri/src/tray.rs
+++ /dev/null
@@ -1,1236 +0,0 @@
-use crate::{
-    NewScreenshotAdded, NewStudioRecordingAdded, RecordingStarted, RecordingStopped,
-    RequestOpenSettings, recording,
-    recording_settings::{RecordingSettingsStore, RecordingTargetMode},
-    windows::ShowCapWindow,
-};
-use cap_recording::RecordingMode;
-
-use cap_project::{RecordingMeta, RecordingMetaInner};
-use std::sync::atomic::{AtomicBool, Ordering};
-use std::{
-    path::PathBuf,
-    sync::{Arc, Mutex},
-};
-use tauri::Manager;
-use tauri::menu::{IconMenuItem, MenuId, PredefinedMenuItem, Submenu};
-use tauri::{
-    AppHandle,
-    image::Image,
-    menu::{Menu, MenuItem},
-    tray::{TrayIcon, TrayIconBuilder},
-};
-use tauri_plugin_dialog::DialogExt;
-use tauri_plugin_opener::OpenerExt;
-use tauri_specta::Event;
-
-const PREVIOUS_ITEM_PREFIX: &str = "previous_item_";
-const MAX_PREVIOUS_ITEMS: usize = 6;
-const MAX_TITLE_LENGTH: usize = 30;
-const THUMBNAIL_SIZE: u32 = 32;
-
-#[cfg(target_os = "linux")]
-#[derive(Clone, Copy)]
-enum LinuxTrayIcon {
-    Instant,
-    Screenshot,
-    Studio,
-    Stop,
-}
-
-#[cfg(target_os = "linux")]
-impl LinuxTrayIcon {
-    fn name(self) -> &'static str {
-        match self {
-            Self::Instant => "so.cap.desktop-tray-instant-symbolic",
-            Self::Screenshot => "so.cap.desktop-tray-screenshot-symbolic",
-            Self::Studio => "so.cap.desktop-tray-studio-symbolic",
-            Self::Stop => "so.cap.desktop-tray-stop-symbolic",
-        }
-    }
-
-    fn svg(self) -> &'static str {
-        match self {
-            Self::Instant => {
-                include_str!("../icons/linux/so.cap.desktop-tray-instant-symbolic.svg")
-            }
-            Self::Screenshot => {
-                include_str!("../icons/linux/so.cap.desktop-tray-screenshot-symbolic.svg")
-            }
-            Self::Studio => include_str!("../icons/linux/so.cap.desktop-tray-studio-symbolic.svg"),
-            Self::Stop => include_str!("../icons/linux/so.cap.desktop-tray-stop-symbolic.svg"),
-        }
-    }
-}
-
-#[derive(Debug)]
-pub enum TrayItem {
-    OpenCap,
-    RecordDisplay,
-    RecordWindow,
-    RecordArea,
-    TakeScreenshot,
-    ImportVideo,
-    ViewAllRecordings,
-    ViewAllScreenshots,
-    OpenSettings,
-    UploadLogs,
-    Quit,
-    PreviousItem(String),
-    ModeStudio,
-    ModeInstant,
-    ModeScreenshot,
-    RequestPermissions,
-}
-
-impl From for MenuId {
-    fn from(value: TrayItem) -> Self {
-        match value {
-            TrayItem::OpenCap => "open_cap",
-            TrayItem::RecordDisplay => "record_display",
-            TrayItem::RecordWindow => "record_window",
-            TrayItem::RecordArea => "record_area",
-            TrayItem::TakeScreenshot => "take_screenshot",
-            TrayItem::ImportVideo => "import_video",
-            TrayItem::ViewAllRecordings => "view_all_recordings",
-            TrayItem::ViewAllScreenshots => "view_all_screenshots",
-            TrayItem::OpenSettings => "open_settings",
-            TrayItem::UploadLogs => "upload_logs",
-            TrayItem::Quit => "quit",
-            TrayItem::PreviousItem(id) => {
-                return format!("{PREVIOUS_ITEM_PREFIX}{id}").into();
-            }
-            TrayItem::ModeStudio => "mode_studio",
-            TrayItem::ModeInstant => "mode_instant",
-            TrayItem::ModeScreenshot => "mode_screenshot",
-            TrayItem::RequestPermissions => "request_permissions",
-        }
-        .into()
-    }
-}
-
-impl TryFrom for TrayItem {
-    type Error = String;
-
-    fn try_from(value: MenuId) -> Result {
-        let id_str = value.0.as_str();
-
-        if let Some(path) = id_str.strip_prefix(PREVIOUS_ITEM_PREFIX) {
-            return Ok(TrayItem::PreviousItem(path.to_string()));
-        }
-
-        match id_str {
-            "open_cap" => Ok(TrayItem::OpenCap),
-            "record_display" => Ok(TrayItem::RecordDisplay),
-            "record_window" => Ok(TrayItem::RecordWindow),
-            "record_area" => Ok(TrayItem::RecordArea),
-            "take_screenshot" => Ok(TrayItem::TakeScreenshot),
-            "import_video" => Ok(TrayItem::ImportVideo),
-            "view_all_recordings" => Ok(TrayItem::ViewAllRecordings),
-            "view_all_screenshots" => Ok(TrayItem::ViewAllScreenshots),
-            "open_settings" => Ok(TrayItem::OpenSettings),
-            "upload_logs" => Ok(TrayItem::UploadLogs),
-            "quit" => Ok(TrayItem::Quit),
-            "mode_studio" => Ok(TrayItem::ModeStudio),
-            "mode_instant" => Ok(TrayItem::ModeInstant),
-            "mode_screenshot" => Ok(TrayItem::ModeScreenshot),
-            "request_permissions" => Ok(TrayItem::RequestPermissions),
-            value => Err(format!("Invalid tray item id {value}")),
-        }
-    }
-}
-
-#[derive(Debug, Clone)]
-enum PreviousItemType {
-    StudioRecording,
-    InstantRecording {
-        #[allow(dead_code)]
-        link: Option,
-    },
-    Screenshot,
-}
-
-#[derive(Clone)]
-struct CachedPreviousItem {
-    path: PathBuf,
-    pretty_name: String,
-    thumbnail: Option>,
-    thumbnail_width: u32,
-    thumbnail_height: u32,
-    item_type: PreviousItemType,
-}
-
-#[derive(Default)]
-struct PreviousItemsCache {
-    items: Vec,
-    revision: u64,
-    loaded: bool,
-}
-
-impl PreviousItemsCache {
-    fn invalidate(&mut self) {
-        self.revision = self.revision.wrapping_add(1);
-    }
-
-    fn finish_loading(&mut self, revision: u64, items: Vec) -> bool {
-        if self.revision != revision {
-            return false;
-        }
-        self.items = items;
-        self.loaded = true;
-        self.invalidate();
-        true
-    }
-}
-
-fn screenshots_path(app: &AppHandle) -> PathBuf {
-    let path = app.path().app_data_dir().unwrap().join("screenshots");
-    std::fs::create_dir_all(&path).unwrap_or_default();
-    path
-}
-
-fn truncate_title(title: &str) -> String {
-    if title.chars().count() <= MAX_TITLE_LENGTH {
-        title.to_string()
-    } else {
-        let truncate_at = MAX_TITLE_LENGTH - 1;
-        let byte_index = title
-            .char_indices()
-            .nth(truncate_at)
-            .map(|(i, _)| i)
-            .unwrap_or(title.len());
-        format!("{}…", &title[..byte_index])
-    }
-}
-
-fn load_thumbnail_data(path: &PathBuf) -> Option<(Vec, u32, u32)> {
-    use image::imageops::FilterType;
-    use image::{GenericImageView, RgbaImage};
-
-    let image_data = std::fs::read(path).ok()?;
-    let img = image::load_from_memory(&image_data).ok()?;
-
-    let (orig_w, orig_h) = img.dimensions();
-    let size = THUMBNAIL_SIZE;
-
-    let scale = (size as f32 / orig_w as f32).max(size as f32 / orig_h as f32);
-    let scaled_w = (orig_w as f32 * scale).round() as u32;
-    let scaled_h = (orig_h as f32 * scale).round() as u32;
-
-    let scaled = img.resize_exact(scaled_w, scaled_h, FilterType::Triangle);
-
-    let x_offset = (scaled_w.saturating_sub(size)) / 2;
-    let y_offset = (scaled_h.saturating_sub(size)) / 2;
-
-    let mut result = RgbaImage::new(size, size);
-    for y in 0..size {
-        for x in 0..size {
-            let src_x = x + x_offset;
-            let src_y = y + y_offset;
-            if src_x < scaled_w && src_y < scaled_h {
-                result.put_pixel(x, y, scaled.get_pixel(src_x, src_y));
-            }
-        }
-    }
-
-    Some((result.into_raw(), size, size))
-}
-
-fn load_single_item(
-    path: &PathBuf,
-    screenshots_dir: &PathBuf,
-    load_thumbnail: bool,
-) -> Option {
-    if !path.is_dir() {
-        return None;
-    }
-
-    let meta = RecordingMeta::load_for_project(path).ok()?;
-    let is_screenshot = path.extension().and_then(|s| s.to_str()) == Some("cap")
-        && path.parent().map(|p| p == screenshots_dir).unwrap_or(false);
-
-    let (thumbnail_path, item_type) = if is_screenshot {
-        let png_path = std::fs::read_dir(path).ok().and_then(|dir| {
-            dir.flatten()
-                .find(|e| e.path().extension().and_then(|s| s.to_str()) == Some("png"))
-                .map(|e| e.path())
-        });
-        (png_path, PreviousItemType::Screenshot)
-    } else {
-        let thumb = path.join("screenshots/display.jpg");
-        let thumb_path = if thumb.exists() { Some(thumb) } else { None };
-        let item_type = match &meta.inner {
-            RecordingMetaInner::Studio(_) => PreviousItemType::StudioRecording,
-            RecordingMetaInner::Instant(_) => PreviousItemType::InstantRecording {
-                link: meta.sharing.as_ref().map(|s| s.link.clone()),
-            },
-        };
-        (thumb_path, item_type)
-    };
-
-    let (thumbnail, thumbnail_width, thumbnail_height) = if load_thumbnail {
-        thumbnail_path
-            .as_ref()
-            .and_then(load_thumbnail_data)
-            .map(|(data, w, h)| (Some(data), w, h))
-            .unwrap_or((None, 0, 0))
-    } else {
-        (None, 0, 0)
-    };
-
-    Some(CachedPreviousItem {
-        path: path.clone(),
-        pretty_name: meta.pretty_name,
-        thumbnail,
-        thumbnail_width,
-        thumbnail_height,
-        item_type,
-    })
-}
-
-fn load_all_previous_items(app: &AppHandle, load_thumbnails: bool) -> Vec {
-    let mut paths = Vec::new();
-    let screenshots_dir = screenshots_path(app);
-
-    for recordings_dir in crate::recordings_locations::known_recordings_dirs(app) {
-        let Ok(entries) = std::fs::read_dir(&recordings_dir) else {
-            continue;
-        };
-        for entry in entries.flatten() {
-            paths.push(entry.path());
-        }
-    }
-
-    if screenshots_dir.exists()
-        && let Ok(entries) = std::fs::read_dir(&screenshots_dir)
-    {
-        for entry in entries.flatten() {
-            let path = entry.path();
-            if path.extension().and_then(|s| s.to_str()) == Some("cap") {
-                paths.push(path);
-            }
-        }
-    }
-
-    newest_valid_items(paths, MAX_PREVIOUS_ITEMS, |path| {
-        load_single_item(path, &screenshots_dir, load_thumbnails)
-    })
-}
-
-fn newest_valid_items(
-    paths: Vec,
-    limit: usize,
-    mut load: impl FnMut(&PathBuf) -> Option,
-) -> Vec {
-    let mut candidates = paths
-        .into_iter()
-        .filter_map(|path| {
-            let metadata = path.metadata().ok()?;
-            metadata.is_dir().then(|| {
-                let created = metadata
-                    .created()
-                    .unwrap_or_else(|_| std::time::SystemTime::now());
-                (path, created)
-            })
-        })
-        .collect::>();
-    candidates.sort_by_key(|(_, created)| std::cmp::Reverse(*created));
-    candidates
-        .into_iter()
-        .filter_map(|(path, _)| load(&path))
-        .take(limit)
-        .collect()
-}
-
-fn load_previous_items_in_background(app: AppHandle, cache: Arc>) {
-    tokio::spawn(async move {
-        if !crate::startup::wait_for_window(&app).await {
-            return;
-        }
-        let worker_app = app.clone();
-        let worker_cache = cache.clone();
-        let result = tokio::task::spawn_blocking(move || {
-            while !crate::app_is_exiting(&worker_app) {
-                let revision = worker_cache.lock().unwrap().revision;
-                let items = load_all_previous_items(&worker_app, true);
-                if worker_cache.lock().unwrap().finish_loading(revision, items) {
-                    return;
-                }
-            }
-        })
-        .await;
-        if let Err(error) = result {
-            tracing::warn!(%error, "Failed to load tray history");
-        }
-        if !crate::app_is_exiting(&app) {
-            refresh_tray_menu(&app, &cache);
-        }
-    });
-}
-
-fn create_previous_submenu(
-    app: &AppHandle,
-    cache: &PreviousItemsCache,
-) -> tauri::Result> {
-    if cache.items.is_empty() {
-        let submenu = Submenu::with_id(app, "previous", "Previous", false)?;
-        submenu.append(&MenuItem::with_id(
-            app,
-            "previous_empty",
-            if cache.loaded {
-                "No recent items"
-            } else {
-                "Loading recent items…"
-            },
-            false,
-            None::<&str>,
-        )?)?;
-        return Ok(submenu);
-    }
-
-    let submenu = Submenu::with_id(app, "previous", "Previous", true)?;
-
-    for item in &cache.items {
-        let id = TrayItem::PreviousItem(item.path.to_string_lossy().to_string());
-        let title = truncate_title(&item.pretty_name);
-
-        let type_indicator = match &item.item_type {
-            PreviousItemType::StudioRecording => "🎬 ",
-            PreviousItemType::InstantRecording { .. } => "⚡ ",
-            PreviousItemType::Screenshot => "📷 ",
-        };
-        let display_title = format!("{type_indicator}{title}");
-
-        let icon = item.thumbnail.as_ref().map(|data| {
-            Image::new_owned(data.clone(), item.thumbnail_width, item.thumbnail_height)
-        });
-
-        let menu_item = IconMenuItem::with_id(app, id, display_title, true, icon, None::<&str>)?;
-        submenu.append(&menu_item)?;
-    }
-
-    Ok(submenu)
-}
-
-fn get_current_mode(app: &AppHandle) -> RecordingMode {
-    RecordingSettingsStore::get(app)
-        .ok()
-        .flatten()
-        .and_then(|s| s.mode)
-        .unwrap_or_default()
-}
-
-fn should_use_minimal_onboarding_tray_menu(app: &AppHandle) -> bool {
-    if !app.webview_windows().contains_key("onboarding") {
-        return false;
-    }
-    !crate::permissions::do_permissions_check(false).necessary_granted()
-}
-
-pub(crate) struct TrayMenuCache {
-    cache: Arc>,
-}
-
-pub(crate) fn refresh_tray_menu_for_app(app: &AppHandle) {
-    let Some(state) = app.try_state::() else {
-        return;
-    };
-    refresh_tray_menu(app, &state.cache);
-}
-
-fn create_mode_submenu(app: &AppHandle) -> tauri::Result> {
-    let current_mode = get_current_mode(app);
-
-    let submenu = Submenu::with_id(app, "select_mode", "Select Mode", true)?;
-
-    let modes = [
-        (TrayItem::ModeStudio, RecordingMode::Studio, "Studio"),
-        (TrayItem::ModeInstant, RecordingMode::Instant, "Instant"),
-        (
-            TrayItem::ModeScreenshot,
-            RecordingMode::Screenshot,
-            "Screenshot",
-        ),
-    ];
-
-    for (tray_item, mode, label) in modes {
-        let is_selected = current_mode == mode;
-        let display_label = if is_selected {
-            format!("✓ {label}")
-        } else {
-            format!("   {label}")
-        };
-
-        let menu_item = MenuItem::with_id(app, tray_item, display_label, true, None::<&str>)?;
-        submenu.append(&menu_item)?;
-    }
-
-    Ok(submenu)
-}
-
-fn build_tray_menu(app: &AppHandle, cache: &PreviousItemsCache) -> tauri::Result> {
-    if should_use_minimal_onboarding_tray_menu(app) {
-        return Menu::with_items(
-            app,
-            &[
-                &MenuItem::with_id(
-                    app,
-                    TrayItem::RequestPermissions,
-                    "Request Permissions",
-                    true,
-                    None::<&str>,
-                )?,
-                &PredefinedMenuItem::separator(app)?,
-                &MenuItem::with_id(
-                    app,
-                    "version",
-                    format!("Cap v{}", env!("CARGO_PKG_VERSION")),
-                    false,
-                    None::<&str>,
-                )?,
-                &MenuItem::with_id(app, TrayItem::Quit, "Quit Cap", true, None::<&str>)?,
-            ],
-        );
-    }
-
-    let previous_submenu = create_previous_submenu(app, cache)?;
-    let mode_submenu = create_mode_submenu(app)?;
-    let current_mode = get_current_mode(app);
-    let is_screenshot_mode = current_mode == RecordingMode::Screenshot;
-
-    let menu = Menu::new(app)?;
-
-    menu.append(&MenuItem::with_id(
-        app,
-        TrayItem::OpenCap,
-        "Open Main Window",
-        true,
-        None::<&str>,
-    )?)?;
-
-    if is_screenshot_mode {
-        menu.append(&MenuItem::with_id(
-            app,
-            TrayItem::RecordDisplay,
-            "Screenshot Display",
-            true,
-            None::<&str>,
-        )?)?;
-        menu.append(&MenuItem::with_id(
-            app,
-            TrayItem::RecordWindow,
-            "Screenshot Window",
-            true,
-            None::<&str>,
-        )?)?;
-        menu.append(&MenuItem::with_id(
-            app,
-            TrayItem::RecordArea,
-            "Screenshot Area",
-            true,
-            None::<&str>,
-        )?)?;
-    } else {
-        menu.append(&MenuItem::with_id(
-            app,
-            TrayItem::RecordDisplay,
-            "Record Display",
-            true,
-            None::<&str>,
-        )?)?;
-        menu.append(&MenuItem::with_id(
-            app,
-            TrayItem::RecordWindow,
-            "Record Window",
-            true,
-            None::<&str>,
-        )?)?;
-        menu.append(&MenuItem::with_id(
-            app,
-            TrayItem::RecordArea,
-            "Record Area",
-            true,
-            None::<&str>,
-        )?)?;
-        menu.append(&MenuItem::with_id(
-            app,
-            TrayItem::TakeScreenshot,
-            "Take a Screenshot",
-            true,
-            None::<&str>,
-        )?)?;
-    }
-
-    menu.append(&MenuItem::with_id(
-        app,
-        TrayItem::ImportVideo,
-        "Import Media...",
-        true,
-        None::<&str>,
-    )?)?;
-
-    menu.append(&PredefinedMenuItem::separator(app)?)?;
-    menu.append(&mode_submenu)?;
-    menu.append(&previous_submenu)?;
-    menu.append(&PredefinedMenuItem::separator(app)?)?;
-
-    menu.append(&MenuItem::with_id(
-        app,
-        TrayItem::ViewAllRecordings,
-        "View all recordings",
-        true,
-        None::<&str>,
-    )?)?;
-    menu.append(&MenuItem::with_id(
-        app,
-        TrayItem::ViewAllScreenshots,
-        "View all screenshots",
-        true,
-        None::<&str>,
-    )?)?;
-    menu.append(&MenuItem::with_id(
-        app,
-        TrayItem::OpenSettings,
-        "Settings",
-        true,
-        None::<&str>,
-    )?)?;
-
-    menu.append(&PredefinedMenuItem::separator(app)?)?;
-    menu.append(&MenuItem::with_id(
-        app,
-        TrayItem::UploadLogs,
-        "Upload Logs",
-        true,
-        None::<&str>,
-    )?)?;
-    menu.append(&MenuItem::with_id(
-        app,
-        "version",
-        format!("Cap v{}", env!("CARGO_PKG_VERSION")),
-        false,
-        None::<&str>,
-    )?)?;
-    menu.append(&MenuItem::with_id(
-        app,
-        TrayItem::Quit,
-        "Quit Cap",
-        true,
-        None::<&str>,
-    )?)?;
-
-    Ok(menu)
-}
-
-fn add_new_item_to_cache(cache: &Arc>, app: &AppHandle, path: PathBuf) {
-    let screenshots_dir = screenshots_path(app);
-
-    let Some(new_item) = load_single_item(&path, &screenshots_dir, true) else {
-        return;
-    };
-
-    let mut cache_guard = cache.lock().unwrap();
-
-    cache_guard.items.retain(|item| item.path != path);
-
-    cache_guard.items.insert(0, new_item);
-
-    cache_guard.items.truncate(MAX_PREVIOUS_ITEMS);
-    cache_guard.invalidate();
-}
-
-fn refresh_tray_menu(app: &AppHandle, cache: &Arc>) {
-    let app_clone = app.clone();
-    let cache_clone = cache.clone();
-
-    let _ = app.run_on_main_thread(move || {
-        let Some(tray) = app_clone.tray_by_id("tray") else {
-            return;
-        };
-
-        let cache_guard = cache_clone.lock().unwrap();
-        if let Ok(menu) = build_tray_menu(&app_clone, &cache_guard) {
-            let _ = tray.set_menu(Some(menu));
-        }
-    });
-}
-
-fn handle_previous_item_click(app: &AppHandle, path_str: &str) {
-    let path = PathBuf::from(path_str);
-
-    let screenshots_dir = screenshots_path(app);
-    let is_screenshot = path.extension().and_then(|s| s.to_str()) == Some("cap")
-        && path.parent().map(|p| p == screenshots_dir).unwrap_or(false);
-
-    if is_screenshot {
-        let app = app.clone();
-        let screenshot_path = path;
-        tokio::spawn(async move {
-            let _ = ShowCapWindow::ScreenshotEditor {
-                path: screenshot_path,
-            }
-            .show(&app)
-            .await;
-        });
-        return;
-    }
-
-    let meta = match RecordingMeta::load_for_project(&path) {
-        Ok(m) => m,
-        Err(e) => {
-            tracing::error!("Failed to load recording meta for previous item: {e}");
-            return;
-        }
-    };
-
-    match &meta.inner {
-        RecordingMetaInner::Studio(_) => {
-            let app = app.clone();
-            let project_path = path.clone();
-            tokio::spawn(async move {
-                let _ = ShowCapWindow::Editor { project_path }.show(&app).await;
-            });
-        }
-        RecordingMetaInner::Instant(_) => {
-            if let Some(sharing) = &meta.sharing {
-                let _ = app.opener().open_url(&sharing.link, None::);
-            } else {
-                let mp4_path = path.join("content/output.mp4");
-                if mp4_path.exists() {
-                    let _ = app
-                        .opener()
-                        .open_path(mp4_path.to_str().unwrap_or_default(), None::);
-                }
-            }
-        }
-    }
-}
-
-pub fn get_tray_icon() -> &'static [u8] {
-    include_bytes!("../icons/tray-default-icon.png")
-}
-
-pub fn get_mode_icon(mode: RecordingMode) -> &'static [u8] {
-    if cfg!(target_os = "windows") {
-        return get_tray_icon();
-    }
-    match mode {
-        RecordingMode::Studio => include_bytes!("../icons/tray-default-icon-studio.png"),
-        RecordingMode::Instant => include_bytes!("../icons/tray-default-icon-instant.png"),
-        RecordingMode::Screenshot => include_bytes!("../icons/tray-default-icon-screenshot.png"),
-    }
-}
-
-#[cfg(target_os = "linux")]
-fn linux_tray_icon_for_mode(mode: RecordingMode) -> LinuxTrayIcon {
-    match mode {
-        RecordingMode::Studio => LinuxTrayIcon::Studio,
-        RecordingMode::Instant => LinuxTrayIcon::Instant,
-        RecordingMode::Screenshot => LinuxTrayIcon::Screenshot,
-    }
-}
-
-#[cfg(target_os = "linux")]
-fn write_linux_tray_symbolic_icon(icon: LinuxTrayIcon) -> std::io::Result {
-    let dir = dirs::runtime_dir()
-        .unwrap_or_else(std::env::temp_dir)
-        .join("cap-tray-icons");
-    std::fs::create_dir_all(&dir)?;
-
-    let path = dir.join(format!("{}.svg", icon.name()));
-    let svg = icon.svg().as_bytes();
-    if std::fs::read(&path).ok().as_deref() != Some(svg) {
-        std::fs::write(path, svg)?;
-    }
-
-    Ok(dir)
-}
-
-#[cfg(target_os = "linux")]
-fn set_linux_tray_icon(tray: &TrayIcon, icon: LinuxTrayIcon) -> tauri::Result<()> {
-    let icon_dir = write_linux_tray_symbolic_icon(icon).map_err(tauri::Error::Io)?;
-    let icon_name = icon.name().to_string();
-
-    tray.with_inner_tray_icon(move |inner| unsafe {
-        let indicator = inner.app_indicator() as *mut libappindicator::AppIndicator;
-        if let Some(indicator) = indicator.as_mut() {
-            indicator.set_icon_theme_path(&icon_dir.to_string_lossy());
-            indicator.set_icon_full(&icon_name, "Cap tray icon");
-        }
-    })?;
-
-    Ok(())
-}
-
-#[cfg(target_os = "linux")]
-fn set_tray_icon_for_mode(tray: &TrayIcon, mode: RecordingMode) -> tauri::Result<()> {
-    set_linux_tray_icon(tray, linux_tray_icon_for_mode(mode))
-}
-
-#[cfg(not(target_os = "linux"))]
-fn set_tray_icon_for_mode(tray: &TrayIcon, mode: RecordingMode) -> tauri::Result<()> {
-    let icon = Image::from_bytes(get_mode_icon(mode))?;
-    tray.set_icon(Some(icon))?;
-    tray.set_icon_as_template(true)?;
-    Ok(())
-}
-
-#[cfg(target_os = "linux")]
-fn set_tray_stop_icon(tray: &TrayIcon) -> tauri::Result<()> {
-    set_linux_tray_icon(tray, LinuxTrayIcon::Stop)
-}
-
-#[cfg(not(target_os = "linux"))]
-fn set_tray_stop_icon(tray: &TrayIcon) -> tauri::Result<()> {
-    let icon = Image::from_bytes(include_bytes!("../icons/tray-stop-icon.png"))?;
-    tray.set_icon(Some(icon))?;
-    tray.set_icon_as_template(true)?;
-    Ok(())
-}
-
-pub fn update_tray_icon_for_mode(app: &AppHandle, mode: RecordingMode) {
-    if cfg!(target_os = "windows") {
-        return;
-    }
-
-    let Some(tray) = app.tray_by_id("tray") else {
-        return;
-    };
-
-    if let Err(error) = set_tray_icon_for_mode(&tray, mode) {
-        tracing::warn!("Failed to update tray icon: {error}");
-    }
-}
-
-fn handle_mode_selection(
-    app: &AppHandle,
-    mode: RecordingMode,
-    cache: &Arc>,
-) {
-    if let Err(e) = RecordingSettingsStore::set_mode(app, mode) {
-        tracing::error!("Failed to set recording mode: {e}");
-        return;
-    }
-
-    update_tray_icon_for_mode(app, mode);
-    refresh_tray_menu(app, cache);
-}
-
-pub fn create_tray(app: &AppHandle) -> tauri::Result<()> {
-    let cache = Arc::new(Mutex::new(PreviousItemsCache::default()));
-
-    app.manage(TrayMenuCache {
-        cache: cache.clone(),
-    });
-
-    let menu = {
-        let cache_guard = cache.lock().unwrap();
-        build_tray_menu(app, &cache_guard)?
-    };
-    let app = app.clone();
-    let is_recording = Arc::new(AtomicBool::new(false));
-
-    let current_mode = get_current_mode(&app);
-    let initial_icon = Image::from_bytes(get_mode_icon(current_mode))?;
-
-    let _ = TrayIconBuilder::with_id("tray")
-        .icon(initial_icon)
-        .icon_as_template(cfg!(target_os = "macos"))
-        .menu(&menu)
-        .show_menu_on_left_click(true)
-        .on_menu_event({
-            let app_handle = app.clone();
-            let cache = cache.clone();
-            move |app: &AppHandle, event| match TrayItem::try_from(event.id) {
-                Ok(TrayItem::OpenCap) => {
-                    let app = app.clone();
-                    tauri::async_runtime::spawn(async move {
-                        let _ = ShowCapWindow::Main {
-                            init_target_mode: None,
-                        }
-                        .show(&app)
-                        .await;
-                    });
-                }
-                Ok(TrayItem::RecordDisplay) => {
-                    let app = app.clone();
-                    tokio::spawn(async move {
-                        crate::open_target_picker(&app, RecordingTargetMode::Display).await;
-                    });
-                }
-                Ok(TrayItem::RecordWindow) => {
-                    let app = app.clone();
-                    tokio::spawn(async move {
-                        crate::open_target_picker(&app, RecordingTargetMode::Window).await;
-                    });
-                }
-                Ok(TrayItem::RecordArea) => {
-                    let app = app.clone();
-                    tokio::spawn(async move {
-                        crate::open_target_picker(&app, RecordingTargetMode::Area).await;
-                    });
-                }
-                Ok(TrayItem::TakeScreenshot) => {
-                    let app = app.clone();
-                    tokio::spawn(async move {
-                        use cap_recording::screen_capture::ScreenCaptureTarget;
-                        use scap_targets::Display;
-
-                        let display =
-                            Display::get_containing_cursor().unwrap_or_else(Display::primary);
-                        let target = ScreenCaptureTarget::Display { id: display.id() };
-
-                        match recording::take_screenshot(app.clone(), target.clone()).await {
-                            Ok(path) => {
-                                if crate::automation::should_open_screenshot_editor(&app, &target) {
-                                    let _ =
-                                        ShowCapWindow::ScreenshotEditor { path }.show(&app).await;
-                                }
-                            }
-                            Err(e) => {
-                                tracing::error!("Failed to take screenshot: {e}");
-                            }
-                        }
-                    });
-                }
-                Ok(TrayItem::ImportVideo) => {
-                    let app = app.clone();
-                    tokio::spawn(async move {
-                        let file_path = app
-                            .dialog()
-                            .file()
-                            .add_filter(
-                                "Media Files",
-                                &[
-                                    "mp4", "mov", "avi", "mkv", "webm", "wmv", "m4v", "flv", "png",
-                                    "jpg", "jpeg", "webp", "gif", "bmp", "tif", "tiff",
-                                ],
-                            )
-                            .add_filter(
-                                "Video Files",
-                                &["mp4", "mov", "avi", "mkv", "webm", "wmv", "m4v", "flv"],
-                            )
-                            .add_filter(
-                                "Image Files",
-                                &["png", "jpg", "jpeg", "webp", "gif", "bmp", "tif", "tiff"],
-                            )
-                            .blocking_pick_file();
-
-                        if let Some(file_path) = file_path {
-                            let path = match file_path.into_path() {
-                                Ok(p) => p,
-                                Err(e) => {
-                                    tracing::error!("Invalid file path: {e}");
-                                    return;
-                                }
-                            };
-
-                            if crate::import::is_supported_video_import_path(&path) {
-                                match crate::import::start_video_import(app.clone(), path).await {
-                                    Ok(project_path) => {
-                                        let _ =
-                                            ShowCapWindow::Editor { project_path }.show(&app).await;
-                                    }
-                                    Err(e) => {
-                                        tracing::error!("Failed to import video: {e}");
-                                        app.dialog()
-                                            .message(format!("Failed to import video: {e}"))
-                                            .title("Import Error")
-                                            .kind(tauri_plugin_dialog::MessageDialogKind::Error)
-                                            .blocking_show();
-                                    }
-                                }
-                            } else if crate::import::is_supported_image_import_path(&path) {
-                                match crate::import::start_image_import(app.clone(), path).await {
-                                    Ok(path) => {
-                                        let _ = ShowCapWindow::ScreenshotEditor { path }
-                                            .show(&app)
-                                            .await;
-                                    }
-                                    Err(e) => {
-                                        tracing::error!("Failed to import image: {e}");
-                                        app.dialog()
-                                            .message(format!("Failed to import image: {e}"))
-                                            .title("Import Error")
-                                            .kind(tauri_plugin_dialog::MessageDialogKind::Error)
-                                            .blocking_show();
-                                    }
-                                }
-                            } else {
-                                tracing::error!("Unsupported media import path: {:?}", path);
-                                app.dialog()
-                                    .message("Unsupported media file.")
-                                    .title("Import Error")
-                                    .kind(tauri_plugin_dialog::MessageDialogKind::Error)
-                                    .blocking_show();
-                            }
-                        }
-                    });
-                }
-                Ok(TrayItem::ViewAllRecordings) => {
-                    let _ = RequestOpenSettings {
-                        page: "recordings".to_string(),
-                    }
-                    .emit(&app_handle);
-                }
-                Ok(TrayItem::ViewAllScreenshots) => {
-                    let _ = RequestOpenSettings {
-                        page: "screenshots".to_string(),
-                    }
-                    .emit(&app_handle);
-                }
-                Ok(TrayItem::OpenSettings) => {
-                    let app = app.clone();
-                    tokio::spawn(
-                        async move { ShowCapWindow::Settings { page: None }.show(&app).await },
-                    );
-                }
-                Ok(TrayItem::UploadLogs) => {
-                    let app = app.clone();
-                    tokio::spawn(async move {
-                        match crate::logging::upload_log_file(&app).await {
-                            Ok(_) => {
-                                tracing::info!("Successfully uploaded logs");
-                                app.dialog()
-                                    .message("Logs uploaded successfully")
-                                    .show(|_| {});
-                            }
-                            Err(e) => {
-                                tracing::error!("Failed to upload logs: {e:#}");
-                                app.dialog().message("Failed to upload logs").show(|_| {});
-                            }
-                        }
-                    });
-                }
-                Ok(TrayItem::Quit) => {
-                    let app = app.clone();
-                    tokio::spawn(async move {
-                        crate::request_app_exit(app).await;
-                    });
-                }
-                Ok(TrayItem::PreviousItem(path)) => {
-                    handle_previous_item_click(app, &path);
-                }
-                Ok(TrayItem::ModeStudio) => {
-                    handle_mode_selection(app, RecordingMode::Studio, &cache);
-                }
-                Ok(TrayItem::ModeInstant) => {
-                    handle_mode_selection(app, RecordingMode::Instant, &cache);
-                }
-                Ok(TrayItem::ModeScreenshot) => {
-                    handle_mode_selection(app, RecordingMode::Screenshot, &cache);
-                }
-                Ok(TrayItem::RequestPermissions) => {
-                    let app = app.clone();
-                    tokio::spawn(async move {
-                        let _ = ShowCapWindow::Onboarding.show(&app).await;
-                    });
-                }
-                _ => {}
-            }
-        })
-        .on_tray_icon_event({
-            let is_recording = Arc::clone(&is_recording);
-            let app_handle = app.clone();
-            move |tray, event| {
-                if let tauri::tray::TrayIconEvent::Click { button_state, .. } = event {
-                    if is_recording.load(Ordering::Relaxed) {
-                        if button_state != tauri::tray::MouseButtonState::Down {
-                            return;
-                        }
-                        let app = app_handle.clone();
-                        tokio::spawn(async move {
-                            let _ = recording::stop_recording(app.clone(), app.state()).await;
-                        });
-                    } else {
-                        let _ = tray.set_visible(true);
-                    }
-                }
-            }
-        })
-        .build(&app);
-
-    #[cfg(target_os = "linux")]
-    if let Some(tray) = app.tray_by_id("tray")
-        && let Err(error) = set_tray_icon_for_mode(&tray, current_mode)
-    {
-        tracing::warn!("Failed to initialize Linux tray icon: {error}");
-    }
-
-    RecordingStarted::listen_any(&app, {
-        let app = app.clone();
-        let is_recording = is_recording.clone();
-        move |_| {
-            is_recording.store(true, Ordering::Relaxed);
-
-            if cfg!(target_os = "windows") {
-                return;
-            }
-
-            let Some(tray) = app.tray_by_id("tray") else {
-                return;
-            };
-
-            if let Err(error) = set_tray_stop_icon(&tray) {
-                tracing::warn!("Failed to update tray icon for recording start: {error}");
-            }
-        }
-    });
-
-    RecordingStopped::listen_any(&app, {
-        let app_handle = app.clone();
-        let is_recording = is_recording.clone();
-        move |_| {
-            is_recording.store(false, Ordering::Relaxed);
-
-            if cfg!(target_os = "windows") {
-                return;
-            }
-
-            let Some(tray) = app_handle.tray_by_id("tray") else {
-                return;
-            };
-
-            let current_mode = get_current_mode(&app_handle);
-            if let Err(error) = set_tray_icon_for_mode(&tray, current_mode) {
-                tracing::warn!("Failed to update tray icon for recording stop: {error}");
-            }
-        }
-    });
-
-    NewStudioRecordingAdded::listen_any(&app, {
-        let app_handle = app.clone();
-        let cache_clone = cache.clone();
-        move |event| {
-            add_new_item_to_cache(&cache_clone, &app_handle, event.payload.path.clone());
-            refresh_tray_menu(&app_handle, &cache_clone);
-        }
-    });
-
-    NewScreenshotAdded::listen_any(&app, {
-        let app_handle = app.clone();
-        let cache_clone = cache.clone();
-        move |event| {
-            let path = if event.payload.path.extension().and_then(|s| s.to_str()) == Some("png") {
-                event.payload.path.parent().map(|p| p.to_path_buf())
-            } else {
-                Some(event.payload.path.clone())
-            };
-
-            if let Some(path) = path {
-                add_new_item_to_cache(&cache_clone, &app_handle, path);
-                refresh_tray_menu(&app_handle, &cache_clone);
-            }
-        }
-    });
-
-    crate::recordings_locations::RecordingsMigrationProgress::listen_any(&app, {
-        let app_handle = app.clone();
-        let cache_clone = cache.clone();
-        move |event| {
-            // Rebuild once when a storage-folder migration finishes: moved
-            // projects changed paths, so cached entries are stale.
-            if event.payload.done == event.payload.total {
-                cache_clone.lock().unwrap().invalidate();
-                load_previous_items_in_background(app_handle.clone(), cache_clone.clone());
-            }
-        }
-    });
-
-    crate::RecordingDeleted::listen_any(&app, {
-        let app = app.clone();
-        let cache = cache.clone();
-        move |event| {
-            {
-                let mut cache = cache.lock().unwrap();
-                cache.items.retain(|item| item.path != event.payload.path);
-                cache.invalidate();
-            }
-            refresh_tray_menu(&app, &cache);
-            load_previous_items_in_background(app.clone(), cache.clone());
-        }
-    });
-
-    load_previous_items_in_background(app.clone(), cache.clone());
-
-    Ok(())
-}
-
-#[cfg(target_os = "linux")]
-pub(crate) fn clean_stop_icon() -> Result {
-    let image = image::load_from_memory(include_bytes!("../icons/tray-stop-icon.png"))
-        .map_err(|error| error.to_string())?
-        .resize_exact(32, 32, image::imageops::FilterType::Triangle)
-        .into_rgba8();
-    cap_utils::linux_recording_stop::StopTrayIcon::from_rgba(32, 32, image.as_raw())
-}
-
-#[cfg(test)]
-mod startup_history_tests {
-    use super::*;
-
-    #[test]
-    fn history_load_reads_only_enough_valid_metadata_for_the_menu() {
-        let directory = tempfile::tempdir().unwrap();
-        let paths = (0..100)
-            .map(|index| {
-                let path = directory.path().join(format!("{index}.cap"));
-                std::fs::create_dir(&path).unwrap();
-                path
-            })
-            .collect::>();
-        let mut reads = 0;
-        let loaded = newest_valid_items(paths.clone(), 6, |_| {
-            reads += 1;
-            (reads > 2).then_some(reads)
-        });
-        assert_eq!(reads, 8);
-        assert_eq!(loaded, vec![3, 4, 5, 6, 7, 8]);
-
-        let mut reference = paths.clone();
-        reference
-            .sort_by_key(|path| std::cmp::Reverse(path.metadata().unwrap().created().unwrap()));
-        reference.truncate(6);
-        assert_eq!(
-            newest_valid_items(paths, 6, |path| Some(path.clone())),
-            reference
-        );
-    }
-
-    #[test]
-    fn a_late_history_scan_cannot_overwrite_new_items_or_moved_folders() {
-        let mut cache = PreviousItemsCache::default();
-        let old_revision = cache.revision;
-        cache.invalidate();
-        assert!(!cache.finish_loading(old_revision, Vec::new()));
-        assert!(!cache.loaded);
-        assert!(cache.finish_loading(cache.revision, Vec::new()));
-        assert!(cache.loaded);
-        assert!(!cache.finish_loading(old_revision, Vec::new()));
-    }
-}
-
-#[cfg(target_os = "linux")]
-pub(crate) async fn set_clean_stop_mode(
-    app: &AppHandle,
-    generation: u32,
-    active: bool,
-) -> Result<(), String> {
-    let (tx, rx) = tokio::sync::oneshot::channel();
-    let handle = app.clone();
-    app.run_on_main_thread(move || {
-        let result = if crate::clean_capture::wayland_generation(&handle) != Some(generation) {
-            Err("Recording tray transition was superseded".to_string())
-        } else if let Some(tray) = handle.tray_by_id("tray") {
-            tray.set_visible(!active).map_err(|error| error.to_string())
-        } else {
-            Ok(())
-        };
-        let _ = tx.send(result);
-    })
-    .map_err(|error| error.to_string())?;
-    tokio::time::timeout(std::time::Duration::from_secs(2), rx)
-        .await
-        .map_err(|_| "Recording tray transition timed out".to_string())?
-        .map_err(|_| "Recording tray transition was lost".to_string())?
-}
diff --git a/apps/desktop/src-tauri/src/update_project_names.rs b/apps/desktop/src-tauri/src/update_project_names.rs
deleted file mode 100644
index 8d008617064..00000000000
--- a/apps/desktop/src-tauri/src/update_project_names.rs
+++ /dev/null
@@ -1,325 +0,0 @@
-use std::{
-    collections::HashSet,
-    path::{Path, PathBuf},
-    sync::Arc,
-};
-
-use cap_project::RecordingMeta;
-use futures::StreamExt;
-use tauri::AppHandle;
-use tauri_plugin_store::StoreExt;
-use tokio::{fs, sync::Mutex};
-
-use crate::recordings_path;
-
-const STORE_KEY: &str = "uuid_projects_migrated";
-
-pub fn migrate_if_needed(app: &AppHandle) -> Result<(), String> {
-    let store = app
-        .store("store")
-        .map_err(|e| format!("Failed to access store: {e}"))?;
-
-    if store
-        .get(STORE_KEY)
-        .and_then(|v| v.as_bool())
-        .unwrap_or(false)
-    {
-        return Ok(());
-    }
-
-    let app_handle = app.clone();
-    tokio::spawn(async move {
-        if let Err(err) = migrate(&app_handle).await {
-            tracing::error!("Updating project names failed: {err}");
-        }
-
-        if let Ok(store) = app_handle.store("store") {
-            store.set(STORE_KEY, true);
-            if let Err(e) = store.save() {
-                tracing::error!("Failed to save store after migration: {}", e);
-            }
-        }
-    });
-
-    Ok(())
-}
-
-use std::time::Instant;
-
-/// Performs a one-time migration of all UUID-named projects to pretty name-based naming.
-pub async fn migrate(app: &AppHandle) -> Result<(), String> {
-    let recordings_dir = recordings_path(app);
-    if !fs::try_exists(&recordings_dir)
-        .await
-        .map_err(|e| format!("Failed to check recordings directory: {e}"))?
-    {
-        return Ok(());
-    }
-
-    let uuid_projects = collect_uuid_projects(&recordings_dir).await?;
-    if uuid_projects.is_empty() {
-        tracing::debug!("No UUID-named projects found to migrate");
-        return Ok(());
-    }
-
-    tracing::info!(
-        "Found {} UUID-named projects to migrate",
-        uuid_projects.len()
-    );
-
-    let total_found = uuid_projects.len();
-    let concurrency_limit = std::thread::available_parallelism()
-        .map(|n| n.get())
-        .unwrap_or(4)
-        .clamp(2, 16)
-        .min(total_found);
-    tracing::debug!("Using concurrency limit of {}", concurrency_limit);
-
-    let wall_start = Instant::now();
-    let in_flight_bases = Arc::new(Mutex::new(HashSet::new()));
-
-    // (project_name, result, duration)
-    let migration_results = futures::stream::iter(uuid_projects)
-        .map(|project_path| {
-            let in_flight = in_flight_bases.clone();
-            async move {
-                let project_name = project_path
-                    .file_name()
-                    .map(|s| s.to_string_lossy().into_owned())
-                    .unwrap_or_else(|| project_path.display().to_string());
-
-                let start = Instant::now();
-                let res = migrate_single_project(project_path, in_flight).await;
-                let dur = start.elapsed();
-
-                (project_name, res, dur)
-            }
-        })
-        .buffer_unordered(concurrency_limit)
-        .collect::>()
-        .await;
-
-    let wall_elapsed = wall_start.elapsed();
-
-    let mut migrated = 0usize;
-    let mut skipped = 0usize;
-    let mut failed = 0usize;
-
-    let mut total_ms: u128 = 0;
-    let mut per_project: Vec<(String, std::time::Duration)> =
-        Vec::with_capacity(migration_results.len());
-
-    for (name, result, dur) in migration_results.into_iter() {
-        match result {
-            Ok(ProjectMigrationResult::Migrated) => migrated += 1,
-            Ok(ProjectMigrationResult::Skipped) => skipped += 1,
-            Err(_) => failed += 1,
-        }
-        total_ms += dur.as_millis();
-        per_project.push((name, dur));
-    }
-
-    let avg_ms = if total_found > 0 {
-        (total_ms as f64) / (total_found as f64)
-    } else {
-        0.0
-    };
-
-    per_project.sort_by_key(|b| std::cmp::Reverse(b.1));
-
-    tracing::info!(
-        total_found = total_found,
-        migrated = migrated,
-        skipped = skipped,
-        failed = failed,
-        wall_ms = wall_elapsed.as_millis(),
-        avg_per_project_ms = ?avg_ms,
-        "Migration complete"
-    );
-
-    // Log top slowest N (choose 5 or less)
-    let top_n = 5.min(per_project.len());
-    if top_n > 0 {
-        tracing::info!("Top {} slowest project migrations:", top_n);
-        for (name, dur) in per_project.into_iter().take(top_n) {
-            tracing::info!(project = %name, ms = dur.as_millis());
-        }
-    }
-
-    Ok(())
-}
-
-async fn collect_uuid_projects(recordings_dir: &Path) -> Result, String> {
-    let mut uuid_projects = Vec::new();
-    let mut entries = fs::read_dir(recordings_dir)
-        .await
-        .map_err(|e| format!("Failed to read recordings directory: {e}"))?;
-
-    while let Some(entry) = entries
-        .next_entry()
-        .await
-        .map_err(|e| format!("Failed to read directory entry: {e}"))?
-    {
-        let path = entry.path();
-        if !path.is_dir() {
-            continue;
-        }
-
-        let Some(filename) = path.file_name().and_then(|s| s.to_str()) else {
-            continue;
-        };
-
-        if filename.ends_with(".cap") && fast_is_project_filename_uuid(filename) {
-            uuid_projects.push(path);
-        }
-    }
-
-    Ok(uuid_projects)
-}
-
-#[derive(Debug)]
-enum ProjectMigrationResult {
-    Migrated,
-    Skipped,
-}
-
-async fn migrate_single_project(
-    path: PathBuf,
-    in_flight_basis: Arc>>,
-) -> Result {
-    let filename = path
-        .file_name()
-        .and_then(|s| s.to_str())
-        .unwrap_or("unknown");
-
-    let meta = match RecordingMeta::load_for_project(&path) {
-        Ok(meta) => meta,
-        Err(e) => {
-            tracing::warn!("Failed to load metadata for {}: {}", filename, e);
-            return Err(format!("Failed to load metadata: {e}"));
-        }
-    };
-
-    // Lock on the base sanitized name to prevent concurrent migrations with same target
-    let base_name = sanitize_filename::sanitize(meta.pretty_name.replace(":", "."));
-    {
-        let mut in_flight = in_flight_basis.lock().await;
-        let mut wait_count = 0;
-        while !in_flight.insert(base_name.clone()) {
-            wait_count += 1;
-            if wait_count == 1 {
-                tracing::debug!(
-                    "Project {} waiting for concurrent migration of base name \"{}\"",
-                    filename,
-                    base_name
-                );
-            }
-            drop(in_flight);
-            tokio::time::sleep(std::time::Duration::from_millis(5)).await;
-            in_flight = in_flight_basis.lock().await;
-        }
-        if wait_count > 0 {
-            tracing::debug!(
-                "Project {} acquired lock for \"{}\" after {} waits",
-                filename,
-                base_name,
-                wait_count
-            );
-        }
-    }
-
-    let result = migrate_project_filename_async(&path, &meta).await;
-
-    in_flight_basis.lock().await.remove(&base_name);
-
-    match result {
-        Ok(new_path) => {
-            if new_path != path {
-                let new_name = new_path.file_name().unwrap().to_string_lossy();
-                tracing::info!("Updated name: \"{}\" -> \"{}\"", filename, new_name);
-                Ok(ProjectMigrationResult::Migrated)
-            } else {
-                Ok(ProjectMigrationResult::Skipped)
-            }
-        }
-        Err(e) => {
-            tracing::error!("Failed to migrate {}: {}", filename, e);
-            Err(e)
-        }
-    }
-}
-
-/// Migrates a project filename from UUID to sanitized pretty name
-async fn migrate_project_filename_async(
-    project_path: &Path,
-    meta: &RecordingMeta,
-) -> Result {
-    let sanitized = sanitize_filename::sanitize(meta.pretty_name.replace(":", "."));
-
-    let filename = if sanitized.ends_with(".cap") {
-        sanitized
-    } else {
-        format!("{sanitized}.cap")
-    };
-
-    let parent_dir = project_path
-        .parent()
-        .ok_or("Project path has no parent directory")?;
-
-    let unique_filename = cap_utils::ensure_unique_filename(&filename, parent_dir)
-        .map_err(|e| format!("Failed to ensure unique filename: {e}"))?;
-
-    let final_path = parent_dir.join(&unique_filename);
-
-    fs::rename(project_path, &final_path)
-        .await
-        .map_err(|e| format!("Failed to rename project directory: {e}"))?;
-
-    Ok(final_path)
-}
-
-pub fn fast_is_project_filename_uuid(filename: &str) -> bool {
-    if filename.len() != 40 || !filename.ends_with(".cap") {
-        return false;
-    }
-
-    let uuid_part = &filename[..36];
-
-    if uuid_part.as_bytes()[8] != b'-'
-        || uuid_part.as_bytes()[13] != b'-'
-        || uuid_part.as_bytes()[18] != b'-'
-        || uuid_part.as_bytes()[23] != b'-'
-    {
-        return false;
-    }
-
-    uuid_part.chars().all(|c| c.is_ascii_hexdigit() || c == '-')
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn test_is_project_filename_uuid() {
-        // Valid UUID
-        assert!(fast_is_project_filename_uuid(
-            "a1b2c3d4-e5f6-7890-abcd-ef1234567890.cap"
-        ));
-        assert!(fast_is_project_filename_uuid(
-            "00000000-0000-0000-0000-000000000000.cap"
-        ));
-
-        // Invalid cases
-        assert!(!fast_is_project_filename_uuid("my-project-name.cap"));
-        assert!(!fast_is_project_filename_uuid(
-            "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
-        ));
-        assert!(!fast_is_project_filename_uuid(
-            "a1b2c3d4-e5f6-7890-abcd-ef1234567890.txt"
-        ));
-        assert!(!fast_is_project_filename_uuid(
-            "g1b2c3d4-e5f6-7890-abcd-ef1234567890.cap"
-        ));
-    }
-}
diff --git a/apps/desktop/src-tauri/src/updates.rs b/apps/desktop/src-tauri/src/updates.rs
deleted file mode 100644
index da4ccf8d8d3..00000000000
--- a/apps/desktop/src-tauri/src/updates.rs
+++ /dev/null
@@ -1,423 +0,0 @@
-use serde::{Deserialize, Serialize};
-use specta::Type;
-use std::time::Duration;
-use tauri::{AppHandle, Manager, Url};
-use tauri_plugin_updater::{Update, UpdaterExt};
-use tauri_specta::Event;
-use tokio::sync::{Mutex, Notify};
-use tracing::{info, warn};
-
-use crate::{
-    exit_shutdown::{ExitBlocked, UpdateInstallGuard, UpdateInstallState},
-    general_settings::GeneralSettingsStore,
-};
-
-const UPDATE_ENDPOINT: &str =
-    "https://cdn.crabnebula.app/update/cap/cap/{{target}}/{{current_version}}";
-
-const FIRST_CHECK_DELAY: Duration = Duration::from_secs(60);
-const CHECK_INTERVAL: Duration = Duration::from_secs(2 * 60 * 60);
-const BUSY_RETRY_DELAY: Duration = Duration::from_secs(5 * 60);
-const UPDATE_BUSY_ERROR: &str =
-    "Finish your recording, export, or upload before updating or restarting Cap.";
-
-#[derive(Serialize, Deserialize, Type, Clone, Copy, PartialEq, Eq, Debug, Default)]
-#[serde(rename_all = "camelCase")]
-pub enum UpdateChannel {
-    #[default]
-    Stable,
-    Nightly,
-}
-
-#[derive(Serialize, Type)]
-#[serde(rename_all = "camelCase")]
-pub struct UpdateCheckResult {
-    pub version: String,
-    pub notes: Option,
-    pub channel: UpdateChannel,
-}
-
-#[derive(Serialize, Type, tauri_specta::Event, Clone, Debug)]
-pub struct UpdateDownloadProgress {
-    pub downloaded: u32,
-    pub total: Option,
-}
-
-#[derive(Serialize, Type, tauri_specta::Event, Clone, Debug)]
-pub struct UpdateReady {
-    pub version: String,
-    pub installed: bool,
-}
-
-#[derive(Clone)]
-struct PendingUpdate {
-    update: Update,
-    version: String,
-    installed: bool,
-}
-
-#[derive(Default)]
-pub struct UpdatesState {
-    pending: Mutex>,
-    announced_version: Mutex>,
-    install: Mutex<()>,
-    install_phase: UpdateInstallState,
-    notify: Notify,
-}
-
-impl UpdatesState {
-    pub(crate) fn is_installing(&self) -> bool {
-        self.install_phase.is_installing()
-    }
-}
-
-pub(crate) fn recording_start_blocked(app: &AppHandle) -> bool {
-    app.try_state::()
-        .is_none_or(|state| state.install_phase.blocks_recording())
-}
-
-fn begin_install<'a>(
-    app: &AppHandle,
-    state: &'a UpdatesState,
-) -> Result, String> {
-    crate::with_idle_app(app, true, || {
-        state
-            .install_phase
-            .begin()
-            .ok_or(ExitBlocked::UpdateInstalling)
-    })
-    .and_then(std::convert::identity)
-    .map_err(|reason| reason.message().to_string())
-}
-
-fn current_channel(app: &AppHandle) -> UpdateChannel {
-    GeneralSettingsStore::get(app)
-        .ok()
-        .flatten()
-        .map(|s| s.update_channel)
-        .unwrap_or_default()
-}
-
-fn updater_target() -> Result {
-    let arch = if cfg!(target_arch = "aarch64") {
-        "aarch64"
-    } else {
-        "x86_64"
-    };
-
-    #[cfg(target_os = "linux")]
-    {
-        cap_utils::linux_package::updater_target(arch)
-    }
-    #[cfg(not(target_os = "linux"))]
-    {
-        let platform = if cfg!(target_os = "macos") {
-            "darwin"
-        } else {
-            "windows"
-        };
-        Ok(format!("{platform}-{arch}"))
-    }
-}
-
-fn endpoint(channel: UpdateChannel) -> Result {
-    let url = match channel {
-        UpdateChannel::Stable => UPDATE_ENDPOINT.to_string(),
-        UpdateChannel::Nightly => format!("{UPDATE_ENDPOINT}?channel=nightly"),
-    };
-    Url::parse(&url).map_err(|e| e.to_string())
-}
-
-async fn check_channel(
-    app: &AppHandle,
-    channel: UpdateChannel,
-    allow_stable_downgrade: bool,
-) -> Result, String> {
-    let builder = app
-        .updater_builder()
-        .target(updater_target()?)
-        .endpoints(vec![endpoint(channel)?])
-        .map_err(|e| e.to_string())?;
-
-    // A user on a nightly prerelease who switches back to Stable should land
-    // on the newest stable build even though it is semver-lower than their
-    // current version, so any differing non-prerelease remote counts as an
-    // update (deliberate downgrade-on-channel-switch semantics). This must
-    // ONLY apply when the user's configured channel is Stable: a nightly user
-    // on the latest nightly would otherwise see the older stable release
-    // qualify and flip-flop between the two channels forever.
-    let builder = if allow_stable_downgrade {
-        builder.version_comparator(|current, remote| {
-            remote.version > current
-                || (!current.pre.is_empty()
-                    && remote.version.pre.is_empty()
-                    && remote.version != current)
-        })
-    } else {
-        builder.version_comparator(|current, remote| remote.version > current)
-    };
-
-    builder
-        .build()
-        .map_err(|e| e.to_string())?
-        .check()
-        .await
-        .map_err(|e| e.to_string())
-}
-
-fn pick_higher_version(a: Option, b: Option) -> Option {
-    match (a, b) {
-        (Some(a), Some(b)) => {
-            match (
-                semver::Version::parse(&a.version),
-                semver::Version::parse(&b.version),
-            ) {
-                (Ok(a_version), Ok(b_version)) => Some(if b_version > a_version { b } else { a }),
-                (Ok(_), Err(_)) => Some(a),
-                _ => Some(b),
-            }
-        }
-        (a, b) => a.or(b),
-    }
-}
-
-pub async fn check(app: &AppHandle) -> Result, String> {
-    let channel = current_channel(app);
-
-    let stable = check_channel(app, UpdateChannel::Stable, channel == UpdateChannel::Stable).await;
-
-    let update = if channel == UpdateChannel::Nightly {
-        let nightly = check_channel(app, UpdateChannel::Nightly, false).await;
-
-        // Both channels can produce a candidate when a stable release was
-        // promoted after the last nightly; the higher version wins.
-        match (stable, nightly) {
-            (Ok(stable), Ok(nightly)) => pick_higher_version(stable, nightly),
-            (Ok(update), Err(err)) | (Err(err), Ok(update)) => {
-                warn!("Update check failed for one channel: {err}");
-                update
-            }
-            (Err(err), Err(_)) => return Err(err),
-        }
-    } else {
-        stable?
-    };
-
-    let state = app.state::();
-    let mut pending = state.pending.lock().await;
-    *pending = update.as_ref().map(|update| PendingUpdate {
-        // Keep the installed flag if the background loop already installed
-        // this version silently.
-        installed: pending
-            .as_ref()
-            .is_some_and(|p| p.version == update.version && p.installed),
-        version: update.version.clone(),
-        update: update.clone(),
-    });
-
-    Ok(update)
-}
-
-async fn download_with_progress(app: &AppHandle, update: &Update) -> Result, String> {
-    let mut downloaded: u32 = 0;
-    update
-        .download(
-            |chunk, total| {
-                downloaded = downloaded.saturating_add(chunk as u32);
-                let _ = UpdateDownloadProgress {
-                    downloaded,
-                    total: total.and_then(|t| u32::try_from(t).ok()),
-                }
-                .emit(app);
-            },
-            || {},
-        )
-        .await
-        .map_err(|e| e.to_string())
-}
-
-fn is_busy(app: &AppHandle) -> bool {
-    crate::with_idle_app(app, true, || ()).is_err()
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn updates_check(app: AppHandle) -> Result, String> {
-    let channel = current_channel(&app);
-    Ok(check(&app).await?.map(|update| UpdateCheckResult {
-        version: update.version.clone(),
-        notes: update.body.clone(),
-        channel,
-    }))
-}
-
-#[tauri::command]
-#[specta::specta]
-pub async fn updates_download_and_install(app: AppHandle) -> Result<(), String> {
-    let state = app.state::();
-    let _install = state.install.lock().await;
-
-    if is_busy(&app) {
-        return Err(UPDATE_BUSY_ERROR.to_string());
-    }
-
-    let pending = match state.pending.lock().await.clone() {
-        Some(pending) => pending,
-        None => {
-            let Some(update) = check(&app).await? else {
-                return Err("No update available".to_string());
-            };
-            PendingUpdate {
-                version: update.version.clone(),
-                update,
-                installed: false,
-            }
-        }
-    };
-
-    // The macOS background loop may have already installed this version
-    // silently; restarting is all that's left to do.
-    if pending.installed {
-        return Ok(());
-    }
-
-    let bytes = download_with_progress(&app, &pending.update).await?;
-
-    let install_admission = begin_install(&app, &state)?;
-    info!("Installing update {}", pending.version);
-    pending.update.install(bytes).map_err(|e| e.to_string())?;
-    install_admission.complete(cfg!(windows));
-
-    let mut guard = state.pending.lock().await;
-    if let Some(p) = guard.as_mut()
-        && p.version == pending.version
-    {
-        p.installed = true;
-    }
-
-    Ok(())
-}
-
-#[tauri::command]
-#[specta::specta]
-pub fn updates_channel_changed(app: AppHandle) -> Result<(), String> {
-    app.state::().notify.notify_one();
-    Ok(())
-}
-
-pub fn spawn_background_loop(app: AppHandle) {
-    // Never auto-update dev builds.
-    if cfg!(debug_assertions) {
-        return;
-    }
-
-    tokio::spawn(async move {
-        let mut delay = FIRST_CHECK_DELAY;
-
-        loop {
-            {
-                let state = app.state::();
-                tokio::select! {
-                    _ = tokio::time::sleep(delay) => {}
-                    _ = state.notify.notified() => {}
-                }
-            }
-
-            delay = CHECK_INTERVAL;
-
-            // Stable updates stay frontend-driven; this loop only owns nightly.
-            if current_channel(&app) != UpdateChannel::Nightly {
-                continue;
-            }
-
-            if is_busy(&app) {
-                delay = BUSY_RETRY_DELAY;
-                continue;
-            }
-
-            let update = match check(&app).await {
-                Ok(Some(update)) => update,
-                Ok(None) => continue,
-                Err(err) => {
-                    warn!("Nightly update check failed: {err}");
-                    continue;
-                }
-            };
-
-            let version = update.version.clone();
-            let state = app.state::();
-
-            if state.announced_version.lock().await.as_deref() == Some(version.as_str()) {
-                continue;
-            }
-
-            let installed = if cfg!(target_os = "macos") {
-                let _install = state.install.lock().await;
-                if is_busy(&app) {
-                    delay = BUSY_RETRY_DELAY;
-                    continue;
-                }
-                let already_installed = state
-                    .pending
-                    .lock()
-                    .await
-                    .as_ref()
-                    .is_some_and(|p| p.version == version && p.installed);
-
-                if already_installed {
-                    true
-                } else {
-                    let bytes = match update.download(|_, _| {}, || {}).await {
-                        Ok(bytes) => bytes,
-                        Err(err) => {
-                            warn!("Failed to download nightly update {version}: {err}");
-                            continue;
-                        }
-                    };
-
-                    // A recording or export may have started mid-download;
-                    // don't touch the install while one is running.
-                    let install_admission = match begin_install(&app, &state) {
-                        Ok(admission) => admission,
-                        Err(_) => {
-                            delay = BUSY_RETRY_DELAY;
-                            continue;
-                        }
-                    };
-
-                    // Safe while Cap runs: the .app bundle is swapped in place
-                    // and takes effect on relaunch.
-                    if let Err(err) = update.install(bytes) {
-                        warn!("Failed to install nightly update {version}: {err}");
-                        continue;
-                    }
-                    install_admission.complete(false);
-
-                    let mut pending = state.pending.lock().await;
-                    if let Some(p) = pending.as_mut()
-                        && p.version == version
-                    {
-                        p.installed = true;
-                    }
-
-                    info!("Nightly update {version} installed; restart to apply");
-                    true
-                }
-            } else {
-                // Windows (NSIS) install exits the app mid-session and Linux
-                // (deb) prompts for privileges, so never auto-install there;
-                // announce and let the user trigger the install.
-                info!("Nightly update {version} available");
-                false
-            };
-
-            let _ = UpdateReady {
-                version: version.clone(),
-                installed,
-            }
-            .emit(&app);
-
-            *state.announced_version.lock().await = Some(version);
-        }
-    });
-}
diff --git a/apps/desktop/src-tauri/src/upload.rs b/apps/desktop/src-tauri/src/upload.rs
deleted file mode 100644
index be19c9d61db..00000000000
--- a/apps/desktop/src-tauri/src/upload.rs
+++ /dev/null
@@ -1,5511 +0,0 @@
-// credit @filleduchaos
-
-use crate::{
-    UploadProgress, VideoUploadInfo,
-    api::{self, PresignedS3PutRequest, PresignedS3PutRequestMethod, S3VideoMeta, UploadedPart},
-    http_client::{HttpClient, RetryableHttpClient},
-    telemetry::{AnalyticsEvent, async_capture_event},
-    web_api::{AuthedApiError, ManagerExt},
-};
-use async_stream::{stream, try_stream};
-use bytes::Bytes;
-use cap_project::{RecordingMeta, S3UploadMeta, UploadMeta};
-use cap_recording::{
-    upload_resume::UploadLock,
-    upload_verification::{UploadVerification, VerifiedUploadReceipt},
-};
-use cap_utils::spawn_actor;
-use ffmpeg::ffi::AV_TIME_BASE;
-use flume::Receiver;
-use futures::future::join;
-use futures::{Stream, StreamExt, TryStreamExt, stream};
-use image::{ImageReader, codecs::jpeg::JpegEncoder};
-use reqwest::StatusCode;
-use serde::{Deserialize, Serialize};
-use specta::Type;
-use std::{
-    collections::HashMap,
-    io,
-    path::{Path, PathBuf},
-    pin::pin,
-    sync::{
-        Arc, Mutex, PoisonError,
-        atomic::{AtomicUsize, Ordering},
-    },
-    time::Duration,
-};
-use tauri::{AppHandle, Manager, ipc::Channel};
-use tauri_specta::Event;
-use tokio::{
-    fs::File,
-    io::{AsyncReadExt, BufReader},
-    task::{self, JoinHandle},
-    time::{self, Instant, timeout},
-};
-use tokio_util::io::ReaderStream;
-use tracing::{Span, debug, error, info, info_span, instrument, trace, warn};
-
-pub(crate) mod lifecycle;
-pub(crate) mod preparation;
-pub(crate) mod recovery_age;
-pub(crate) mod resume;
-use tracing_futures::Instrument;
-
-pub(crate) fn acquire_upload_lock(recording_dir: &Path) -> Result {
-    let lock = UploadLock::acquire(recording_dir).map_err(|error| error.to_string())?;
-    match std::fs::symlink_metadata(recording_dir.join("instant-upload.json")) {
-        Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(lock),
-        Ok(_) => Err("This recording's upload is managed by Cap GPUI; local files retained".into()),
-        Err(error) => Err(format!("Could not verify recording upload ownership: {error}").into()),
-    }
-}
-
-async fn await_upload_verification(
-    app: &AppHandle,
-    video_id: &str,
-    verification: &UploadVerification,
-    session: &lifecycle::Session,
-) -> Result {
-    session.set_verification(verification)?;
-    let started = Instant::now();
-    while started.elapsed() < Duration::from_secs(10 * 60) {
-        session.check()?;
-        let result = tokio::select! {
-            result = api::verify_recording_complete(app, video_id, verification) => result,
-            _ = session.cancelled() => return Err("Upload verification cancelled; local files retained".into()),
-        };
-        match result {
-            Ok(Some(receipt)) => {
-                session.record_receipt(verification, &receipt)?;
-                return Ok(receipt);
-            }
-            Err(error @ AuthedApiError::ReuploadRequired) => {
-                session.clear_verification()?;
-                return Err(error);
-            }
-            Ok(None) => {}
-            Err(error @ AuthedApiError::InvalidAuthentication) => return Err(error),
-            Err(error) => warn!(%error, "Recording verification pending; local files retained"),
-        }
-        tokio::select! { _ = tokio::time::sleep(Duration::from_secs(5)) => {}, _ = session.cancelled() => return Err("Upload verification cancelled; local files retained".into()) }
-    }
-    Err(AuthedApiError::VerificationPending)
-}
-
-fn validate_uploaded_segment_inventory(
-    manifest: &SegmentUploadManifest,
-    expected: &[cap_enc_ffmpeg::segmented_stream::SegmentCompletedEvent],
-) -> Result<(), AuthedApiError> {
-    use cap_enc_ffmpeg::segmented_stream::SegmentMediaType;
-    for media_type in [SegmentMediaType::Video, SegmentMediaType::Audio] {
-        let mut indices = expected
-            .iter()
-            .filter(|event| !event.is_init && event.media_type == media_type)
-            .map(|event| event.index)
-            .collect::>();
-        indices.sort_unstable();
-        let expected_init = expected
-            .iter()
-            .any(|event| event.is_init && event.media_type == media_type);
-        let (actual_init, actual_segments) = match media_type {
-            SegmentMediaType::Video => (manifest.video_init_uploaded, &manifest.video_segments),
-            SegmentMediaType::Audio => (manifest.audio_init_uploaded, &manifest.audio_segments),
-        };
-        if actual_init != expected_init
-            || !actual_segments.iter().map(|entry| entry.index).eq(indices)
-        {
-            return Err("Uploaded segments do not cover the final recording inventory".into());
-        }
-    }
-    Ok(())
-}
-
-pub struct UploadedItem {
-    pub link: String,
-    pub id: String,
-    pub object_identity: Option,
-    // #[allow(unused)]
-    // pub config: S3UploadMeta,
-}
-
-#[derive(Clone, Serialize, Type, tauri_specta::Event)]
-pub struct UploadProgressEvent {
-    video_id: String,
-    uploaded: String,
-    total: String,
-}
-
-const MIN_CHUNK_SIZE: u64 = 5 * 1024 * 1024;
-const MAX_CHUNK_SIZE: u64 = 15 * 1024 * 1024;
-const NETWORK_RECOVERY_TIMEOUT: Duration = Duration::from_secs(5 * 60);
-const CONNECTIVITY_PROBE_INITIAL_DELAY: Duration = Duration::from_secs(2);
-const CONNECTIVITY_PROBE_MAX_DELAY: Duration = Duration::from_secs(30);
-
-static ACTIVE_UPLOADS: AtomicUsize = AtomicUsize::new(0);
-
-struct ActiveUploadGuard<'a>(&'a AtomicUsize);
-
-impl<'a> ActiveUploadGuard<'a> {
-    fn new(active: &'a AtomicUsize) -> Self {
-        active.fetch_add(1, Ordering::AcqRel);
-        Self(active)
-    }
-}
-
-impl Drop for ActiveUploadGuard<'_> {
-    fn drop(&mut self) {
-        self.0.fetch_sub(1, Ordering::AcqRel);
-    }
-}
-
-pub(crate) fn upload_session_active() -> bool {
-    ACTIVE_UPLOADS.load(Ordering::Acquire) > 0
-}
-
-fn is_google_drive_resumable_url(url: &str) -> bool {
-    let Ok(url) = reqwest::Url::parse(url) else {
-        return false;
-    };
-    url.host_str().is_some_and(|host| {
-        (host == "googleapis.com" || host.ends_with(".googleapis.com"))
-            && url.path().starts_with("/upload/drive/")
-    })
-}
-
-fn is_google_drive_upload(provider: Option<&str>, upload_id: &str) -> bool {
-    provider == Some("googleDrive") || is_google_drive_resumable_url(upload_id)
-}
-
-fn with_drive_content_range(
-    request: reqwest::RequestBuilder,
-    url: &str,
-    offset: u64,
-    size: u64,
-    total_size: u64,
-) -> reqwest::RequestBuilder {
-    if !is_google_drive_resumable_url(url) || size == 0 {
-        return request;
-    }
-
-    let end = offset.saturating_add(size).saturating_sub(1);
-    request.header(
-        "Content-Range",
-        format!("bytes {offset}-{end}/{total_size}"),
-    )
-}
-
-fn is_upload_response_accepted(
-    url: &str,
-    status: StatusCode,
-    offset: u64,
-    size: u64,
-    total_size: u64,
-) -> bool {
-    status.is_success()
-        || (is_google_drive_resumable_url(url)
-            && status == StatusCode::PERMANENT_REDIRECT
-            && offset.saturating_add(size) < total_size)
-}
-
-fn content_type_for_upload_subpath(subpath: &str) -> &'static str {
-    if subpath.ends_with(".json") {
-        "application/json"
-    } else if subpath.ends_with(".mp4") || subpath.ends_with(".m4s") {
-        "video/mp4"
-    } else if subpath.ends_with(".jpg") || subpath.ends_with(".jpeg") {
-        "image/jpeg"
-    } else if subpath.ends_with(".png") {
-        "image/png"
-    } else if subpath.ends_with(".aac") {
-        "audio/aac"
-    } else if subpath.ends_with(".webm") {
-        "audio/webm"
-    } else if subpath.ends_with(".m3u8") {
-        "application/x-mpegURL"
-    } else {
-        "application/octet-stream"
-    }
-}
-
-pub fn reusable_video_id(
-    sharing: Option<&cap_project::SharingMeta>,
-    upload: Option<&cap_project::UploadMeta>,
-) -> Option {
-    sharing
-        .map(|sharing| sharing.id.clone())
-        .or_else(|| match upload {
-            Some(cap_project::UploadMeta::SinglePartUpload { video_id, .. })
-            | Some(cap_project::UploadMeta::SegmentUpload { video_id, .. })
-            | Some(cap_project::UploadMeta::MultipartUpload { video_id, .. }) => {
-                Some(video_id.clone())
-            }
-            _ => None,
-        })
-}
-
-enum ReplacementAttempt {
-    Completed(T),
-    RestartRequired,
-}
-
-async fn with_replacement_restart(
-    replace_existing: bool,
-    mut attempt: F,
-) -> Result
-where
-    F: FnMut(bool) -> Fut,
-    Fut: std::future::Future, AuthedApiError>>,
-{
-    lifecycle::cancellable(async {}).await?;
-    match attempt(false).await? {
-        ReplacementAttempt::Completed(value) => return Ok(value),
-        ReplacementAttempt::RestartRequired if replace_existing => {}
-        ReplacementAttempt::RestartRequired => {
-            return Err("Unexpected replacement restart response; local files retained".into());
-        }
-    }
-    lifecycle::cancellable(async {}).await?;
-    match attempt(true).await? {
-        ReplacementAttempt::Completed(value) => Ok(value),
-        ReplacementAttempt::RestartRequired => {
-            Err("Replacement restart was rejected again; local files retained".into())
-        }
-    }
-}
-
-fn validate_replacement_restart_session(
-    restarted: bool,
-    upload_id: &str,
-) -> Result<(), AuthedApiError> {
-    if restarted && !upload_id.starts_with("cap-reupload.") {
-        return Err(
-            "Replacement restart requires a signed upload session; local files retained".into(),
-        );
-    }
-    Ok(())
-}
-
-#[derive(PartialEq, Eq)]
-struct LegacyReplacementChunk {
-    offset: u64,
-    size: usize,
-    digest: md5::Digest,
-}
-
-struct LegacyReplacementInput {
-    path: PathBuf,
-    size: u64,
-    modified: std::time::SystemTime,
-    chunks: Mutex>,
-}
-
-impl LegacyReplacementInput {
-    async fn identity(
-        path: PathBuf,
-    ) -> Result<(PathBuf, u64, std::time::SystemTime), AuthedApiError> {
-        lifecycle::file_io(move || {
-            let metadata = std::fs::symlink_metadata(&path)?;
-            #[cfg(windows)]
-            {
-                use std::os::windows::fs::MetadataExt;
-                if metadata.file_attributes() & 0x400 != 0 {
-                    return Err(io::Error::other("Replacement input is a reparse point"));
-                }
-            }
-            if !metadata.is_file() || metadata.file_type().is_symlink() || metadata.len() == 0 {
-                return Err(io::Error::other(
-                    "Replacement input must be a nonempty regular file",
-                ));
-            }
-            Ok((path.canonicalize()?, metadata.len(), metadata.modified()?))
-        })
-        .await
-        .map_err(|error| error.to_string().into())
-    }
-
-    async fn capture(path: &Path) -> Result {
-        let (path, size, modified) = Self::identity(path.to_path_buf()).await?;
-        Ok(Self {
-            path,
-            size,
-            modified,
-            chunks: Mutex::new(HashMap::new()),
-        })
-    }
-
-    async fn verify(&self, path: &Path) -> Result<(), AuthedApiError> {
-        let (path, size, modified) = Self::identity(path.to_path_buf()).await?;
-        if path != self.path || size != self.size || modified != self.modified {
-            return Err("Replacement input changed during upload; local files retained".into());
-        }
-        Ok(())
-    }
-
-    fn inspect_chunk(&self, chunk: &Chunk, record: bool) -> io::Result<()> {
-        if chunk.total_size != self.size
-            || chunk.chunk.is_empty()
-            || chunk.part_number == 0
-            || chunk
-                .offset
-                .checked_add(chunk.chunk.len() as u64)
-                .is_none_or(|end| end > self.size)
-        {
-            return Err(io::Error::other("Replacement upload byte range changed"));
-        }
-        let receipt = LegacyReplacementChunk {
-            offset: chunk.offset,
-            size: chunk.chunk.len(),
-            digest: md5::compute(&chunk.chunk),
-        };
-        let mut chunks = self.chunks.lock().unwrap_or_else(PoisonError::into_inner);
-        if let Some(expected) = chunks.get(&chunk.part_number) {
-            if expected != &receipt {
-                return Err(io::Error::other("Replacement upload bytes changed"));
-            }
-        } else if record {
-            let _ = chunks.insert(chunk.part_number, receipt);
-        } else {
-            return Err(io::Error::other(
-                "Replacement upload has an unrecognized byte range",
-            ));
-        }
-        Ok(())
-    }
-
-    fn verify_parts(&self, parts: &[UploadedPart]) -> Result<(), AuthedApiError> {
-        let chunks = self.chunks.lock().unwrap_or_else(PoisonError::into_inner);
-        let mut offset = 0_u64;
-        if parts.len() != chunks.len() {
-            return Err("Replacement upload parts are incomplete".into());
-        }
-        for (index, part) in parts.iter().enumerate() {
-            let Some(chunk) = chunks.get(&part.part_number) else {
-                return Err("Replacement upload part was not verified".into());
-            };
-            if part.part_number as usize != index + 1
-                || chunk.offset != offset
-                || chunk.size != part.size
-                || part.total_size != self.size
-            {
-                return Err("Replacement upload part inventory changed".into());
-            }
-            offset = offset
-                .checked_add(part.size as u64)
-                .ok_or("Replacement upload size overflow")?;
-        }
-        if offset != self.size {
-            return Err("Replacement upload does not cover the original file".into());
-        }
-        Ok(())
-    }
-}
-
-fn legacy_replacement_session(replace_existing: bool, upload_id: &str) -> bool {
-    replace_existing && !upload_id.starts_with("cap-reupload.")
-}
-
-#[instrument(skip(app, channel, file_path, screenshot_path))]
-pub async fn upload_video(
-    app: &AppHandle,
-    video_id: String,
-    file_path: PathBuf,
-    screenshot_path: PathBuf,
-    replace_existing: bool,
-    channel: Option>,
-) -> Result {
-    let _active_upload = ActiveUploadGuard::new(&ACTIVE_UPLOADS);
-    info!("Uploading video {video_id}...");
-
-    let start = Instant::now();
-    let initial_upload = lifecycle::cancellable(api::upload_multipart_initiate(
-        app,
-        &video_id,
-        replace_existing,
-    ))
-    .await??;
-    let legacy_input = std::sync::OnceLock::>::new();
-    let video_fut = {
-        let file_path = &file_path;
-        let video_id = &video_id;
-        let channel = &channel;
-        let legacy_input = &legacy_input;
-        let initial_upload = &initial_upload;
-        with_replacement_restart(replace_existing, move |restarted| async move {
-            if let Some(input) = legacy_input.get() {
-                input.verify(file_path).await?;
-            }
-            let upload = if restarted {
-                lifecycle::cancellable(api::upload_multipart_initiate(
-                    app,
-                    video_id,
-                    replace_existing,
-                ))
-                .await??
-            } else {
-                api::MultipartUploadInitiateResponse {
-                    upload_id: initial_upload.upload_id.clone(),
-                    provider: initial_upload.provider.clone(),
-                }
-            };
-            validate_replacement_restart_session(restarted, &upload.upload_id)?;
-            if legacy_replacement_session(replace_existing, &upload.upload_id)
-                && legacy_input.get().is_none()
-            {
-                legacy_input
-                    .set(Arc::new(LegacyReplacementInput::capture(file_path).await?))
-                    .map_err(|_| "Replacement input identity was already established")?;
-            }
-            let input = legacy_input.get();
-            let is_drive_upload =
-                is_google_drive_upload(upload.provider.as_deref(), &upload.upload_id);
-            let upload_id = upload.upload_id;
-            let failed_chunks: Arc>> = Arc::new(Mutex::new(Vec::new()));
-
-            let stream = progress(
-                app.clone(),
-                video_id.clone(),
-                multipart_uploader(
-                    app.clone(),
-                    video_id.clone(),
-                    upload_id.clone(),
-                    is_drive_upload,
-                    from_pending_file_to_chunks(file_path.clone(), None).map({
-                        let input = input.cloned();
-                        move |chunk| {
-                            let chunk = chunk?;
-                            if let Some(input) = &input {
-                                input.inspect_chunk(&chunk, !restarted)?;
-                            }
-                            Ok(chunk)
-                        }
-                    }),
-                    failed_chunks.clone(),
-                ),
-            );
-
-            let stream = if let Some(channel) = channel.clone() {
-                tauri_channel_progress(channel, stream).boxed()
-            } else {
-                stream.boxed()
-            };
-
-            let mut parts = stream.try_collect::>().await?;
-
-            let failed =
-                std::mem::take(&mut *failed_chunks.lock().unwrap_or_else(PoisonError::into_inner));
-            if !failed.is_empty() {
-                info!(
-                    count = failed.len(),
-                    "Retrying {} failed chunk(s) after main upload pass",
-                    failed.len()
-                );
-                let retry_parts = retry_failed_chunks_with_input(
-                    app,
-                    video_id,
-                    &upload_id,
-                    file_path,
-                    failed,
-                    input.map(Arc::as_ref),
-                )
-                .await?;
-                parts.extend(retry_parts);
-            }
-
-            let mut deduplicated_parts = HashMap::new();
-            for part in parts {
-                deduplicated_parts.insert(part.part_number, part);
-            }
-            parts = deduplicated_parts.into_values().collect::>();
-            parts.sort_by_key(|part| part.part_number);
-
-            let metadata = build_video_meta(file_path)
-                .map_err(|e| error!("Failed to get video metadata: {e}"))
-                .ok();
-
-            if let Some(input) = input {
-                input.verify_parts(&parts)?;
-                input.verify(file_path).await?;
-            }
-            let completed_identity = match api::upload_multipart_complete_outcome(
-                app,
-                video_id,
-                &upload_id,
-                &parts,
-                metadata.clone(),
-                replace_existing,
-            )
-            .await?
-            {
-                api::MultipartCompletion::Completed(identity) => identity,
-                api::MultipartCompletion::ReplacementRestartRequired if input.is_some() => {
-                    return Ok(ReplacementAttempt::RestartRequired);
-                }
-                api::MultipartCompletion::ReplacementRestartRequired => {
-                    return Err(
-                        "Signed replacement upload was rejected; local files retained".into(),
-                    );
-                }
-            };
-            let object_identity = if is_drive_upload {
-                parts
-                    .iter()
-                    .rev()
-                    .find_map(|part| part.object_identity.clone())
-            } else {
-                completed_identity
-            };
-            Ok(ReplacementAttempt::Completed((metadata, object_identity)))
-        })
-    };
-
-    // TODO: We don't report progress on image upload
-    let bytes = compress_image(screenshot_path).await?;
-    let thumbnail_fut = singlepart_uploader(
-        app.clone(),
-        PresignedS3PutRequest {
-            video_id: video_id.clone(),
-            subpath: "screenshot/screen-capture.jpg".to_string(),
-            method: PresignedS3PutRequestMethod::Put,
-            meta: None,
-        },
-        bytes.len() as u64,
-        stream::once(async move { Ok::<_, std::io::Error>(bytes::Bytes::from(bytes)) }),
-    );
-
-    let (video_result, thumbnail_result): (Result<_, AuthedApiError>, Result<_, AuthedApiError>) =
-        tokio::join!(video_fut, thumbnail_fut);
-
-    async_capture_event(
-        app,
-        match &video_result {
-            Ok((meta, _)) => AnalyticsEvent::MultipartUploadComplete {
-                duration: start.elapsed(),
-                length: meta
-                    .as_ref()
-                    .map(|v| Duration::from_secs(v.duration_in_secs as u64))
-                    .unwrap_or_default(),
-                size: std::fs::metadata(file_path)
-                    .map(|m| ((m.len() as f64) / 1_000_000.0) as u64)
-                    .unwrap_or_default(),
-            },
-            Err(err) => AnalyticsEvent::MultipartUploadFailed {
-                duration: start.elapsed(),
-                error: err.to_string(),
-            },
-        },
-    );
-
-    let (_, object_identity) = video_result?;
-    thumbnail_result?;
-    lifecycle::cancellable(async {}).await?;
-    emit_upload_complete(app, &video_id);
-
-    Ok(UploadedItem {
-        link: app.make_app_url(format!("/s/{video_id}")).await,
-        id: video_id,
-        object_identity,
-    })
-}
-
-/// Open a file and construct a stream to it.
-async fn file_reader_stream(path: impl AsRef) -> Result<(ReaderStream, u64), String> {
-    let file = File::open(path)
-        .await
-        .map_err(|e| format!("Failed to open file: {e}"))?;
-
-    let metadata = file
-        .metadata()
-        .await
-        .map_err(|e| format!("Failed to get file metadata: {e}"))?;
-
-    Ok((ReaderStream::new(file), metadata.len()))
-}
-
-fn screenshot_upload_subpath(content_type: &str) -> &'static str {
-    if content_type.eq_ignore_ascii_case("image/png") {
-        "screenshot/screen-capture.png"
-    } else {
-        "screenshot/screen-capture.jpg"
-    }
-}
-
-fn screenshot_content_type_from_path(path: &Path) -> &'static str {
-    match path
-        .extension()
-        .and_then(|extension| extension.to_str())
-        .map(str::to_ascii_lowercase)
-        .as_deref()
-    {
-        Some("png") => "image/png",
-        _ => "image/jpeg",
-    }
-}
-
-pub async fn upload_screenshot_bytes(
-    app: &AppHandle,
-    image_bytes: Vec,
-    content_type: &str,
-    video_id: Option,
-    organization_id: Option,
-) -> Result {
-    let _active_upload = ActiveUploadGuard::new(&ACTIVE_UPLOADS);
-    let created = create_or_get_video(app, true, video_id, None, None, organization_id).await?;
-    let link = created.link(app).await;
-    let s3_config = created.config;
-    let subpath = screenshot_upload_subpath(content_type);
-    let total_size = image_bytes.len() as u64;
-
-    singlepart_uploader(
-        app.clone(),
-        PresignedS3PutRequest {
-            video_id: s3_config.id.clone(),
-            subpath: subpath.to_string(),
-            method: PresignedS3PutRequestMethod::Put,
-            meta: None,
-        },
-        total_size,
-        stream::once(async move { Ok::<_, std::io::Error>(Bytes::from(image_bytes)) }),
-    )
-    .await?;
-
-    Ok(UploadedItem {
-        link,
-        id: s3_config.id,
-        object_identity: None,
-    })
-}
-
-pub async fn upload_screenshot_file(
-    app: &AppHandle,
-    file_path: PathBuf,
-    video_id: Option,
-    organization_id: Option,
-) -> Result {
-    let _active_upload = ActiveUploadGuard::new(&ACTIVE_UPLOADS);
-    let content_type = screenshot_content_type_from_path(&file_path);
-    let created = create_or_get_video(app, true, video_id, None, None, organization_id).await?;
-    let link = created.link(app).await;
-    let s3_config = created.config;
-    let subpath = screenshot_upload_subpath(content_type);
-    let (stream, total_size) = file_reader_stream(file_path).await?;
-
-    singlepart_uploader(
-        app.clone(),
-        PresignedS3PutRequest {
-            video_id: s3_config.id.clone(),
-            subpath: subpath.to_string(),
-            method: PresignedS3PutRequestMethod::Put,
-            meta: None,
-        },
-        total_size,
-        stream,
-    )
-    .await?;
-
-    Ok(UploadedItem {
-        link,
-        id: s3_config.id,
-        object_identity: None,
-    })
-}
-
-#[instrument(skip(app))]
-pub async fn create_or_get_video(
-    app: &AppHandle,
-    is_screenshot: bool,
-    video_id: Option,
-    name: Option,
-    meta: Option,
-    organization_id: Option,
-) -> Result {
-    create_or_get_video_with_mode(
-        app,
-        is_screenshot,
-        video_id,
-        name,
-        meta,
-        organization_id,
-        "desktopMP4",
-    )
-    .await
-}
-
-#[instrument(skip(app))]
-pub async fn create_or_get_video_with_mode(
-    app: &AppHandle,
-    is_screenshot: bool,
-    video_id: Option,
-    name: Option,
-    meta: Option,
-    organization_id: Option,
-    recording_mode: &str,
-) -> Result {
-    let mut s3_config_url = if let Some(id) = video_id {
-        let mut url =
-            format!("/api/desktop/video/create?recordingMode={recording_mode}&videoId={id}");
-        if is_screenshot {
-            url.push_str("&isScreenshot=true");
-        }
-        url
-    } else if is_screenshot {
-        format!("/api/desktop/video/create?recordingMode={recording_mode}&isScreenshot=true")
-    } else {
-        format!("/api/desktop/video/create?recordingMode={recording_mode}")
-    };
-
-    if let Some(name) = name {
-        s3_config_url.push_str(&format!("&name={name}"));
-    }
-
-    if let Some(meta) = meta {
-        s3_config_url.push_str(&format!("&durationInSecs={}", meta.duration_in_secs));
-        s3_config_url.push_str(&format!("&width={}", meta.width));
-        s3_config_url.push_str(&format!("&height={}", meta.height));
-        if let Some(fps) = meta.fps {
-            s3_config_url.push_str(&format!("&fps={fps}"));
-        }
-    }
-
-    if let Some(org_id) = organization_id {
-        s3_config_url.push_str(&format!("&orgId={org_id}"));
-    }
-
-    let response = app
-        .authed_api_request(s3_config_url, |client, url| client.get(url))
-        .await?;
-
-    if response.status() != StatusCode::OK {
-        #[derive(Deserialize, Clone, Debug)]
-        pub struct CreateErrorResponse {
-            error: String,
-        }
-
-        let status = response.status();
-        let body = response.text().await;
-
-        if let Some(error) = body
-            .as_ref()
-            .ok()
-            .and_then(|body| serde_json::from_str::(body).ok())
-            && status == StatusCode::FORBIDDEN
-            && error.error == "upgrade_required"
-        {
-            return Err(AuthedApiError::UpgradeRequired);
-        }
-
-        return Err(format!("create_or_get_video/error/{status}: {body:?}").into());
-    }
-
-    let response_text = response
-        .text()
-        .await
-        .map_err(|e| format!("Failed to read response body: {e}"))?;
-
-    parse_created_video(&response_text).map_err(|e| {
-        format!("Failed to deserialize response: {e}. Response body: {response_text}").into()
-    })
-}
-
-pub struct CreatedVideo {
-    pub config: S3UploadMeta,
-    pub share_url: Option,
-}
-
-impl CreatedVideo {
-    pub async fn link(&self, app: &AppHandle) -> String {
-        match &self.share_url {
-            Some(share_url) => share_url.clone(),
-            None => app.make_app_url(format!("/s/{}", self.config.id)).await,
-        }
-    }
-}
-
-fn parse_created_video(body: &str) -> Result {
-    #[derive(Deserialize)]
-    struct CreateVideoResponse {
-        id: String,
-        #[serde(default)]
-        share_url: Option,
-    }
-
-    let response = serde_json::from_str::(body)?;
-    let share_url = response
-        .share_url
-        .filter(|share_url| is_share_url_for(share_url, &response.id));
-    Ok(CreatedVideo {
-        config: S3UploadMeta { id: response.id },
-        share_url,
-    })
-}
-
-fn is_share_url_for(share_url: &str, video_id: &str) -> bool {
-    reqwest::Url::parse(share_url).is_ok_and(|url| {
-        url.scheme() == "https"
-            && url.host_str().is_some_and(|host| !host.is_empty())
-            && url.username().is_empty()
-            && url.password().is_none()
-            && url.port().is_none()
-            && url.path() == format!("/s/{video_id}")
-            && url.query().is_none()
-            && url.fragment().is_none()
-    })
-}
-
-#[instrument]
-pub fn build_video_meta(path: &PathBuf) -> Result {
-    let input =
-        ffmpeg::format::input(path).map_err(|e| format!("Failed to read input file: {e}"))?;
-    let video_stream = input
-        .streams()
-        .best(ffmpeg::media::Type::Video)
-        .ok_or_else(|| "Failed to find appropriate video stream in file".to_string())?;
-
-    let video_codec = ffmpeg::codec::context::Context::from_parameters(video_stream.parameters())
-        .map_err(|e| format!("Unable to read video codec information: {e}"))?;
-    let video = video_codec
-        .decoder()
-        .video()
-        .map_err(|e| format!("Unable to get video decoder: {e}"))?;
-
-    Ok(S3VideoMeta {
-        duration_in_secs: input.duration() as f64 / AV_TIME_BASE as f64,
-        width: video.width(),
-        height: video.height(),
-        fps: video
-            .frame_rate()
-            .map(|v| v.numerator() as f32 / v.denominator() as f32),
-    })
-}
-
-#[instrument]
-pub async fn compress_image(path: PathBuf) -> Result, String> {
-    task::spawn_blocking(move || {
-        let img = ImageReader::open(&path)
-            .map_err(|e| format!("Failed to open image: {e}"))?
-            .decode()
-            .map_err(|e| format!("Failed to decode image: {e}"))?;
-
-        let resized_img = img.resize(
-            img.width() / 2,
-            img.height() / 2,
-            image::imageops::FilterType::Nearest,
-        );
-
-        let mut buffer = Vec::new();
-        let mut encoder = JpegEncoder::new_with_quality(&mut buffer, 30);
-        encoder
-            .encode(
-                resized_img.as_bytes(),
-                resized_img.width(),
-                resized_img.height(),
-                resized_img.color().into(),
-            )
-            .map_err(|e| format!("Failed to compress image: {e}"))?;
-
-        Ok(buffer)
-    })
-    .await
-    .map_err(|e| format!("Failed to compress image: {e}"))?
-}
-
-pub struct InstantMultipartUpload {
-    #[cfg(not(target_os = "linux"))]
-    pub(crate) session: Arc,
-    #[cfg(not(target_os = "linux"))]
-    pub handle: tokio::task::JoinHandle>,
-}
-
-impl InstantMultipartUpload {
-    /// starts a progressive (multipart) upload that runs until recording stops
-    /// and the file has stabilized (no additional data is being written).
-    #[cfg(not(target_os = "linux"))]
-    pub(crate) fn spawn(
-        app: AppHandle,
-        file_path: PathBuf,
-        pre_created_video: VideoUploadInfo,
-        session: Arc,
-        realtime_upload_done: Option>,
-        required_audio: bool,
-    ) -> Self {
-        let recording_dir = session.directory.clone();
-        let worker_session = session.clone();
-        let handle = spawn_actor(async move {
-            let start = Instant::now();
-            let result = worker_session
-                .run(async {
-                    worker_session.acquire()?;
-                    crate::web_api::inherit_upload_context(
-                        worker_session.context(),
-                        Self::run(
-                            app.clone(),
-                            file_path.clone(),
-                            pre_created_video,
-                            recording_dir,
-                            realtime_upload_done,
-                            required_audio,
-                            worker_session.clone(),
-                        ),
-                    )
-                    .await
-                })
-                .await;
-
-            async_capture_event(
-                &app,
-                match &result {
-                    Ok(meta) => AnalyticsEvent::MultipartUploadComplete {
-                        duration: start.elapsed(),
-                        length: meta
-                            .as_ref()
-                            .map(|v| Duration::from_secs(v.duration_in_secs as u64))
-                            .unwrap_or_default(),
-                        size: std::fs::metadata(file_path)
-                            .map(|m| ((m.len() as f64) / 1_000_000.0) as u64)
-                            .unwrap_or_default(),
-                    },
-                    Err(err) => AnalyticsEvent::MultipartUploadFailed {
-                        duration: start.elapsed(),
-                        error: err.to_string(),
-                    },
-                },
-            );
-
-            result.map(|_| ())
-        });
-        Self {
-            session,
-            #[cfg(not(target_os = "linux"))]
-            handle,
-        }
-    }
-
-    pub(crate) async fn run(
-        app: AppHandle,
-        file_path: PathBuf,
-        pre_created_video: VideoUploadInfo,
-        recording_dir: PathBuf,
-        realtime_video_done: Option>,
-        required_audio: bool,
-        session: Arc,
-    ) -> Result, AuthedApiError> {
-        session.check()?;
-        if let Some(verification) = session.cached_verification()? {
-            await_upload_verification(&app, &pre_created_video.id, &verification, &session).await?;
-            return Ok(Some(build_video_meta(&file_path)?));
-        }
-        let active_upload = ActiveUploadGuard::new(&ACTIVE_UPLOADS);
-        let video_id = pre_created_video.id.clone();
-        debug!("Initiating multipart upload for {video_id}...");
-
-        session.persist_upload(UploadMeta::MultipartUpload {
-            video_id: video_id.clone(),
-            file_path: file_path.clone(),
-            pre_created_video: pre_created_video.clone(),
-            recording_dir: recording_dir.clone(),
-        })?;
-
-        let upload = api::upload_multipart_initiate(&app, &video_id, false).await?;
-        let is_drive_upload = is_google_drive_upload(upload.provider.as_deref(), &upload.upload_id);
-        let upload_id = upload.upload_id;
-
-        let failed_chunks: Arc>> = Arc::new(Mutex::new(Vec::new()));
-
-        let mut parts = progress(
-            app.clone(),
-            video_id.clone(),
-            multipart_uploader(
-                app.clone(),
-                video_id.clone(),
-                upload_id.clone(),
-                is_drive_upload,
-                from_pending_file_to_chunks(file_path.clone(), realtime_video_done),
-                failed_chunks.clone(),
-            ),
-        )
-        .try_collect::>()
-        .await?;
-
-        let failed =
-            std::mem::take(&mut *failed_chunks.lock().unwrap_or_else(PoisonError::into_inner));
-        if !failed.is_empty() {
-            info!(
-                count = failed.len(),
-                "Retrying {} failed chunk(s) after main upload pass",
-                failed.len()
-            );
-            let retry_parts =
-                retry_failed_chunks(&app, &video_id, &upload_id, &file_path, failed).await?;
-            parts.extend(retry_parts);
-        }
-
-        let mut deduplicated_parts = HashMap::new();
-        for part in parts {
-            deduplicated_parts.insert(part.part_number, part);
-        }
-        parts = deduplicated_parts.into_values().collect::>();
-        parts.sort_by_key(|part| part.part_number);
-
-        // Multipart parts already describe the original bytes. Repairing the file here
-        // would validate different bytes from those being completed remotely.
-        let metadata = build_video_meta(&file_path).map_err(|error| {
-            format!(
-                "Uploaded recording could not be validated; original retained for recovery: {error}"
-            )
-        })?;
-        let file_size = std::fs::metadata(&file_path)
-            .map_err(|error| error.to_string())?
-            .len();
-        let duration = metadata.duration_in_secs;
-        let metadata = Some(metadata);
-        session.wait_ready().await?;
-        let completed_identity = api::upload_multipart_complete(
-            &app,
-            &video_id,
-            &upload_id,
-            &parts,
-            metadata.clone(),
-            false,
-        )
-        .await?;
-        let object_identity = if is_drive_upload {
-            parts
-                .iter()
-                .rev()
-                .find_map(|part| part.object_identity.clone())
-        } else {
-            completed_identity
-        };
-        let verification = UploadVerification::mp4(
-            file_size,
-            duration,
-            required_audio,
-            object_identity.ok_or(
-                "Server did not return the uploaded object identity; local recording retained",
-            )?,
-        )?;
-        // Every byte is on the server now; verification is server-side and resumes on
-        // the next launch via the persisted intent, so it must not block app exit.
-        drop(active_upload);
-        await_upload_verification(&app, &video_id, &verification, &session).await?;
-        info!("Multipart upload complete for {video_id}.");
-
-        emit_upload_complete(&app, &video_id);
-
-        Ok(metadata)
-    }
-}
-
-pub struct SegmentUploader {
-    pub(crate) session: Arc,
-    pub handle: tokio::task::JoinHandle>,
-}
-
-type SegmentUploadTasks =
-    futures::stream::FuturesUnordered>>;
-
-struct SegmentUploadState {
-    uploaded_video_segments: std::collections::HashMap,
-    uploaded_audio_segments: std::collections::HashMap,
-    video_init_uploaded: bool,
-    audio_init_uploaded: bool,
-    failed_segments: Vec,
-    worker_error: Option,
-    total_bytes_uploaded: u64,
-}
-
-#[derive(Clone)]
-struct FailedSegmentInfo {
-    subpath: String,
-    file_path: PathBuf,
-    is_init: bool,
-    media_type: cap_enc_ffmpeg::segmented_stream::SegmentMediaType,
-    index: u32,
-    duration: f64,
-    expected_size: u64,
-}
-
-impl SegmentUploadState {
-    fn new() -> Self {
-        Self {
-            uploaded_video_segments: std::collections::HashMap::new(),
-            uploaded_audio_segments: std::collections::HashMap::new(),
-            video_init_uploaded: false,
-            audio_init_uploaded: false,
-            failed_segments: Vec::new(),
-            worker_error: None,
-            total_bytes_uploaded: 0,
-        }
-    }
-
-    fn to_manifest(&self) -> SegmentUploadManifest {
-        let mut video_segments: Vec = self
-            .uploaded_video_segments
-            .iter()
-            .map(|(&index, &duration)| SegmentManifestEntry { index, duration })
-            .collect();
-        video_segments.sort_by_key(|s| s.index);
-        let mut audio_segments: Vec = self
-            .uploaded_audio_segments
-            .iter()
-            .map(|(&index, &duration)| SegmentManifestEntry { index, duration })
-            .collect();
-        audio_segments.sort_by_key(|s| s.index);
-
-        SegmentUploadManifest {
-            version: 2,
-            video_init_uploaded: self.video_init_uploaded,
-            audio_init_uploaded: self.audio_init_uploaded,
-            video_segments,
-            audio_segments,
-            is_complete: false,
-        }
-    }
-
-    fn to_complete_manifest(&self) -> SegmentUploadManifest {
-        let mut manifest = self.to_manifest();
-        manifest.is_complete = true;
-        manifest
-    }
-
-    fn record_worker_failure(&mut self, error: String) {
-        warn!(%error, "Segment upload worker failed");
-        if self.worker_error.is_none() {
-            self.worker_error = Some(error);
-        }
-    }
-
-    fn record_task_result(
-        &mut self,
-        result: Result, tokio::task::JoinError>,
-    ) {
-        let error = match result {
-            Ok(Ok(())) => return,
-            Ok(Err(error)) => error.to_string(),
-            Err(error) => format!("Segment upload task did not complete: {error}"),
-        };
-        self.record_worker_failure(error);
-    }
-
-    fn completed_manifest(&self) -> Result {
-        if let Some(error) = &self.worker_error {
-            return Err(error.clone().into());
-        }
-        if !self.failed_segments.is_empty() {
-            return Err(format!(
-                "Segment upload is incomplete: {} required segment uploads failed",
-                self.failed_segments.len()
-            )
-            .into());
-        }
-        let manifest = self.to_complete_manifest();
-        if !manifest.has_video_content() {
-            return Err("Segment upload completed without video segments".into());
-        }
-        Ok(manifest)
-    }
-}
-
-async fn publish_completed_segments(
-    state: &Mutex,
-    publish: F,
-) -> Result
-where
-    F: FnOnce(SegmentUploadManifest) -> Fut,
-    Fut: std::future::Future>,
-{
-    let manifest = state
-        .lock()
-        .unwrap_or_else(|error| error.into_inner())
-        .completed_manifest()?;
-    publish(manifest).await
-}
-
-async fn drain_segment_upload_tasks(
-    state: &Mutex,
-    tasks: &mut SegmentUploadTasks,
-) {
-    while let Some(result) = tasks.next().await {
-        state
-            .lock()
-            .unwrap_or_else(|error| error.into_inner())
-            .record_task_result(result);
-    }
-}
-
-async fn cancel_segment_prefetch_tasks(
-    tasks: &mut futures::stream::FuturesUnordered>,
-) {
-    for task in tasks.iter() {
-        task.abort();
-    }
-    while let Some(result) = tasks.next().await {
-        if let Err(error) = result
-            && !error.is_cancelled()
-        {
-            warn!(%error, "Optional segment URL prefetch failed");
-        }
-    }
-}
-
-#[derive(Serialize, Deserialize, Debug, Clone)]
-struct SegmentManifestEntry {
-    index: u32,
-    duration: f64,
-}
-
-#[derive(Serialize, Deserialize, Debug, Clone)]
-struct SegmentUploadManifest {
-    version: u32,
-    video_init_uploaded: bool,
-    audio_init_uploaded: bool,
-    video_segments: Vec,
-    audio_segments: Vec,
-    is_complete: bool,
-}
-
-impl SegmentUploadManifest {
-    fn has_video_content(&self) -> bool {
-        self.video_init_uploaded && !self.video_segments.is_empty()
-    }
-}
-
-struct PresignedUrlCache {
-    urls: tokio::sync::Mutex>,
-}
-
-impl PresignedUrlCache {
-    fn new() -> Self {
-        Self {
-            urls: tokio::sync::Mutex::new(HashMap::new()),
-        }
-    }
-
-    async fn prefetch(&self, app: &AppHandle, video_id: &str, segment_count: u32) {
-        let mut subpaths = Vec::with_capacity((segment_count as usize) * 2 + 3);
-        subpaths.push("segments/video/init.mp4".to_string());
-        subpaths.push("segments/audio/init.mp4".to_string());
-        subpaths.push("segments/manifest.json".to_string());
-        for i in 1..=segment_count {
-            subpaths.push(format!("segments/video/segment_{i:03}.m4s"));
-            subpaths.push(format!("segments/audio/segment_{i:03}.m4s"));
-        }
-
-        match api::upload_signed_batch(app, video_id, &subpaths).await {
-            Ok(urls) => {
-                let mut cache = self.urls.lock().await;
-                let count = urls.len();
-                for (subpath, url) in urls {
-                    cache.insert(subpath, url);
-                }
-                info!(count, "Pre-fetched presigned URLs for segments");
-            }
-            Err(e) => {
-                warn!("Failed to batch-prefetch presigned URLs: {e}");
-            }
-        }
-    }
-
-    async fn get_or_fetch(
-        &self,
-        app: &AppHandle,
-        video_id: &str,
-        subpath: &str,
-    ) -> Result {
-        {
-            let mut cache = self.urls.lock().await;
-            if let Some(url) = cache.remove(subpath) {
-                return Ok(url);
-            }
-        }
-
-        api::upload_signed(
-            app,
-            api::PresignedS3PutRequest {
-                video_id: video_id.to_string(),
-                subpath: subpath.to_string(),
-                method: api::PresignedS3PutRequestMethod::Put,
-                meta: None,
-            },
-        )
-        .await
-        .map(|target| target.url)
-    }
-
-    async fn extend_prefetch(&self, app: &AppHandle, video_id: &str, from: u32, count: u32) {
-        let mut subpaths = Vec::with_capacity((count as usize) * 2);
-        for i in from..from + count {
-            subpaths.push(format!("segments/video/segment_{i:03}.m4s"));
-            subpaths.push(format!("segments/audio/segment_{i:03}.m4s"));
-        }
-
-        match api::upload_signed_batch(app, video_id, &subpaths).await {
-            Ok(urls) => {
-                let mut cache = self.urls.lock().await;
-                let count = urls.len();
-                for (subpath, url) in urls {
-                    cache.insert(subpath, url);
-                }
-                info!(count, from, "Extended presigned URL cache");
-            }
-            Err(e) => {
-                warn!("Failed to extend presigned URL cache: {e}");
-            }
-        }
-    }
-}
-
-impl SegmentUploader {
-    #[cfg(not(target_os = "linux"))]
-    pub(crate) fn spawn(
-        app: AppHandle,
-        segment_rx: std::sync::mpsc::Receiver<
-            cap_enc_ffmpeg::segmented_stream::SegmentCompletedEvent,
-        >,
-        recording_done: Option>,
-        session: Arc,
-        pre_created_video: VideoUploadInfo,
-        required_audio: bool,
-    ) -> Self {
-        let recording_dir = session.directory.clone();
-        let worker_session = session.clone();
-        Self {
-            session,
-            handle: spawn_actor(async move {
-                let start = Instant::now();
-                let result = worker_session
-                    .run(async {
-                        worker_session.acquire()?;
-                        crate::web_api::inherit_upload_context(
-                            worker_session.context(),
-                            Self::run(
-                                app.clone(),
-                                segment_rx,
-                                recording_done,
-                                recording_dir.clone(),
-                                pre_created_video,
-                                required_audio,
-                                worker_session.clone(),
-                            ),
-                        )
-                        .await
-                    })
-                    .await;
-
-                async_capture_event(
-                    &app,
-                    match &result {
-                        Ok(total_bytes) => AnalyticsEvent::MultipartUploadComplete {
-                            duration: start.elapsed(),
-                            length: start.elapsed(),
-                            size: total_bytes / (1024 * 1024),
-                        },
-                        Err(err) => AnalyticsEvent::MultipartUploadFailed {
-                            duration: start.elapsed(),
-                            error: err.to_string(),
-                        },
-                    },
-                );
-
-                result.map(|_| ())
-            }),
-        }
-    }
-
-    async fn read_segment_data(
-        file_path: &Path,
-        subpath: &str,
-        expected_size: u64,
-    ) -> Result {
-        const FILE_WAIT_TIMEOUT: Duration = Duration::from_secs(10);
-        const DATA_WAIT_TIMEOUT: Duration = Duration::from_secs(30);
-
-        Self::read_segment_data_with_timeouts(
-            file_path,
-            subpath,
-            expected_size,
-            FILE_WAIT_TIMEOUT,
-            DATA_WAIT_TIMEOUT,
-        )
-        .await
-    }
-
-    async fn read_segment_data_with_timeouts(
-        file_path: &Path,
-        subpath: &str,
-        expected_size: u64,
-        file_wait_timeout: Duration,
-        data_wait_timeout: Duration,
-    ) -> Result {
-        if expected_size == 0 {
-            return Err(format!("segment_upload/{subpath}: expected segment size is zero").into());
-        }
-
-        let start = Instant::now();
-        let actual_path = loop {
-            if file_path.exists() {
-                break file_path.to_path_buf();
-            }
-            if start.elapsed() >= file_wait_timeout {
-                return Err(format!(
-                    "segment_upload/timeout/{subpath}: file not found after {:?} ({})",
-                    file_wait_timeout,
-                    file_path.display()
-                )
-                .into());
-            }
-            lifecycle::cancellable(tokio::time::sleep(Duration::from_millis(50))).await?;
-        };
-
-        let start = Instant::now();
-        let file_data = loop {
-            let path = actual_path.clone();
-            let data = lifecycle::file_io(move || std::fs::read(path))
-                .await
-                .map_err(|e| {
-                    format!(
-                        "segment_upload/read/{subpath}: {e} ({})",
-                        actual_path.display()
-                    )
-                })?;
-
-            if data.len() as u64 == expected_size {
-                break data;
-            }
-
-            if data.len() as u64 > expected_size || start.elapsed() >= data_wait_timeout {
-                return Err(format!(
-                    "segment_upload/{subpath}: expected {expected_size} bytes, found {}",
-                    data.len()
-                )
-                .into());
-            }
-
-            lifecycle::cancellable(tokio::time::sleep(Duration::from_millis(50))).await?;
-        };
-
-        Ok(Bytes::from(file_data))
-    }
-
-    async fn put_segment_to_s3(
-        app: &AppHandle,
-        video_id: &str,
-        subpath: &str,
-        file_bytes: Bytes,
-        url_cache: &PresignedUrlCache,
-        prefetched_url: Option,
-    ) -> Result {
-        const MAX_RETRIES: u32 = 3;
-        let file_size = file_bytes.len();
-        let mut cached_url = prefetched_url;
-
-        for attempt in 0..MAX_RETRIES {
-            let presigned_url = match cached_url.take() {
-                Some(url) => url,
-                None => url_cache.get_or_fetch(app, video_id, subpath).await?,
-            };
-
-            let client = app
-                .state::()
-                .as_ref()
-                .map_err(|err| format!("segment_upload/client: {err:?}"))?
-                .clone();
-
-            let request = client
-                .put(&presigned_url)
-                .header("Content-Length", file_size)
-                .header("Content-Type", content_type_for_upload_subpath(subpath))
-                .timeout(Duration::from_secs(5 * 60))
-                .body(file_bytes.clone());
-            let send_result = lifecycle::cancellable(
-                with_drive_content_range(
-                    request,
-                    &presigned_url,
-                    0,
-                    file_size as u64,
-                    file_size as u64,
-                )
-                .send(),
-            )
-            .await?
-            .map_err(reqwest::Error::without_url);
-
-            match send_result {
-                Ok(resp) if resp.status().is_success() => {
-                    return Ok(file_size as u64);
-                }
-                Ok(resp) => {
-                    let status = resp.status();
-                    if attempt < MAX_RETRIES - 1 {
-                        warn!(
-                            attempt = attempt + 1,
-                            subpath,
-                            status = %status,
-                            "Segment upload failed, retrying"
-                        );
-                        tokio::time::sleep(Duration::from_millis(500 * (1 << attempt) as u64))
-                            .await;
-                        continue;
-                    }
-                    return Err(format!("segment_upload/{subpath}/error: {status}").into());
-                }
-                Err(err) if is_reqwest_network_error(&err) => {
-                    if attempt < MAX_RETRIES - 1 {
-                        warn!(
-                            attempt = attempt + 1,
-                            subpath,
-                            error = %err,
-                            "Segment upload network error, retrying"
-                        );
-                        if !wait_for_network_recovery(app, video_id).await {
-                            return Err(
-                                format!("segment_upload/{subpath}/network_timeout: {err}").into()
-                            );
-                        }
-                        continue;
-                    }
-                    return Err(format!("segment_upload/{subpath}/network_error: {err}").into());
-                }
-                Err(err) => {
-                    return Err(format!("segment_upload/{subpath}/error: {err}").into());
-                }
-            }
-        }
-
-        Err(format!("segment_upload/{subpath}/exhausted_retries").into())
-    }
-
-    async fn upload_manifest(
-        app: &AppHandle,
-        video_id: &str,
-        manifest: &SegmentUploadManifest,
-        url_cache: &PresignedUrlCache,
-    ) -> Result<(), AuthedApiError> {
-        let json = serde_json::to_string_pretty(manifest)
-            .map_err(|e| format!("segment_upload/manifest/serialize: {e}"))?;
-
-        let presigned_url = url_cache
-            .get_or_fetch(app, video_id, "segments/manifest.json")
-            .await?;
-
-        let client = app
-            .state::()
-            .as_ref()
-            .map_err(|err| format!("segment_upload/manifest/client: {err:?}"))?
-            .clone();
-
-        let content_length = json.len() as u64;
-        let request = client
-            .put(&presigned_url)
-            .header("Content-Length", content_length)
-            .header("Content-Type", "application/json")
-            .timeout(Duration::from_secs(60))
-            .body(json);
-        let resp = lifecycle::cancellable(
-            with_drive_content_range(request, &presigned_url, 0, content_length, content_length)
-                .send(),
-        )
-        .await?
-        .map_err(reqwest::Error::without_url)
-        .map_err(|err| format!("segment_upload/manifest/error: {err}"))?;
-
-        if !resp.status().is_success() {
-            return Err(format!("segment_upload/manifest/error: {}", resp.status()).into());
-        }
-
-        Ok(())
-    }
-
-    async fn run(
-        app: AppHandle,
-        segment_rx: std::sync::mpsc::Receiver<
-            cap_enc_ffmpeg::segmented_stream::SegmentCompletedEvent,
-        >,
-        recording_done: Option>,
-        recording_dir: PathBuf,
-        pre_created_video: VideoUploadInfo,
-        required_audio: bool,
-        session: Arc,
-    ) -> Result {
-        use cap_enc_ffmpeg::segmented_stream::SegmentMediaType;
-        let video_id = pre_created_video.id.clone();
-
-        session.check()?;
-
-        if let Some(verification) = session.cached_verification()? {
-            await_upload_verification(&app, &video_id, &verification, &session).await?;
-            return Ok(0);
-        }
-        let active_upload = ActiveUploadGuard::new(&ACTIVE_UPLOADS);
-        info!("Starting segment uploader for {video_id}");
-
-        session.persist_upload(UploadMeta::SegmentUpload {
-            video_id: video_id.clone(),
-            pre_created_video: pre_created_video.clone(),
-            recording_dir: recording_dir.clone(),
-        })?;
-
-        let state = Arc::new(Mutex::new(SegmentUploadState::new()));
-        let preparation = preparation::start(
-            app.clone(),
-            video_id.clone(),
-            state.clone(),
-            session.clone(),
-        );
-        let semaphore = Arc::new(tokio::sync::Semaphore::new(6));
-        let read_semaphore = Arc::new(tokio::sync::Semaphore::new(12));
-        let consecutive_failures = Arc::new(std::sync::atomic::AtomicU32::new(0));
-        let mut in_flight = SegmentUploadTasks::new();
-        let mut prefetch_tasks = futures::stream::FuturesUnordered::new();
-
-        let url_cache = Arc::new(PresignedUrlCache::new());
-        {
-            let cache = url_cache.clone();
-            let app = app.clone();
-            let vid = video_id.clone();
-            let context = session.context();
-            prefetch_tasks.push(tokio::spawn(crate::web_api::inherit_upload_context(
-                context,
-                async move {
-                    cache.prefetch(&app, &vid, 20).await;
-                },
-            )));
-        }
-
-        let manifest_dirty = Arc::new(std::sync::atomic::AtomicBool::new(false));
-        let manifest_shutdown = Arc::new(std::sync::atomic::AtomicBool::new(false));
-        let manifest_notify = Arc::new(tokio::sync::Notify::new());
-        let manifest_handle = {
-            let app = app.clone();
-            let video_id = video_id.clone();
-            let state = state.clone();
-            let dirty = manifest_dirty.clone();
-            let shutdown = manifest_shutdown.clone();
-            let notify = manifest_notify.clone();
-            let url_cache = url_cache.clone();
-            let context = session.context();
-            tokio::spawn(crate::web_api::inherit_upload_context(
-                context,
-                async move {
-                    let mut interval = tokio::time::interval(Duration::from_secs(1));
-                    interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
-                    loop {
-                        tokio::select! {
-                            _ = interval.tick() => {}
-                            _ = notify.notified() => {}
-                        }
-                        if dirty.swap(false, std::sync::atomic::Ordering::AcqRel) {
-                            let manifest = state
-                                .lock()
-                                .unwrap_or_else(|e| e.into_inner())
-                                .to_manifest();
-                            if let Err(e) =
-                                Self::upload_manifest(&app, &video_id, &manifest, &url_cache).await
-                            {
-                                warn!("Periodic manifest upload failed: {e}");
-                            }
-                        }
-                        if shutdown.load(std::sync::atomic::Ordering::Acquire) {
-                            if dirty.swap(false, std::sync::atomic::Ordering::AcqRel) {
-                                let manifest = state
-                                    .lock()
-                                    .unwrap_or_else(|e| e.into_inner())
-                                    .to_manifest();
-                                Self::upload_manifest(&app, &video_id, &manifest, &url_cache)
-                                    .await
-                                    .ok();
-                            }
-                            break;
-                        }
-                    }
-                },
-            ))
-        };
-
-        let (async_segment_tx, mut async_segment_rx) = tokio::sync::mpsc::unbounded_channel::<
-            cap_enc_ffmpeg::segmented_stream::SegmentCompletedEvent,
-        >();
-
-        let bridge_handle = {
-            let async_segment_tx = async_segment_tx;
-            let recording_done = recording_done.clone();
-            let session = session.clone();
-            std::thread::Builder::new()
-                .name("segment-rx-bridge".to_string())
-                .spawn(move || {
-                    while session.check().is_ok() && !async_segment_tx.is_closed() {
-                        match segment_rx.recv_timeout(std::time::Duration::from_millis(20)) {
-                            Ok(event) => {
-                                if async_segment_tx.send(event).is_err() {
-                                    break;
-                                }
-                            }
-                            Err(std::sync::mpsc::RecvTimeoutError::Timeout) => {
-                                if let Some(ref done_rx) = recording_done
-                                    && done_rx.try_recv().is_ok()
-                                {
-                                    while let Ok(event) = segment_rx.try_recv() {
-                                        if async_segment_tx.send(event).is_err() {
-                                            return;
-                                        }
-                                    }
-                                    break;
-                                }
-                            }
-                            Err(std::sync::mpsc::RecvTimeoutError::Disconnected) => {
-                                while let Ok(event) = segment_rx.try_recv() {
-                                    if async_segment_tx.send(event).is_err() {
-                                        return;
-                                    }
-                                }
-                                break;
-                            }
-                        }
-                    }
-                })
-                .map_err(|e| format!("Failed to spawn bridge thread: {e}"))
-        };
-
-        let bridge_handle = match bridge_handle {
-            Ok(handle) => handle,
-            Err(error) => {
-                manifest_shutdown.store(true, std::sync::atomic::Ordering::Release);
-                manifest_notify.notify_one();
-                let _ = manifest_handle.await;
-                cancel_segment_prefetch_tasks(&mut prefetch_tasks).await;
-                return Err(error.into());
-            }
-        };
-
-        use futures::StreamExt as _;
-
-        const CONSECUTIVE_FAILURE_LIMIT: u32 = 5;
-
-        loop {
-            tokio::select! {
-                biased;
-                _ = session.cancelled() => { async_segment_rx.close(); break; }
-                Some(join_result) = in_flight.next(), if !in_flight.is_empty() => {
-                    state.lock().unwrap_or_else(|error| error.into_inner()).record_task_result(join_result);
-                }
-                maybe_event = async_segment_rx.recv() => {
-                    let Some(event) = maybe_event else {
-                        break;
-                    };
-
-                    let subpath = match (event.is_init, event.media_type) {
-                        (true, SegmentMediaType::Video) => "segments/video/init.mp4".to_string(),
-                        (true, SegmentMediaType::Audio) => "segments/audio/init.mp4".to_string(),
-                        (false, SegmentMediaType::Video) => {
-                            format!("segments/video/segment_{:03}.m4s", event.index)
-                        }
-                        (false, SegmentMediaType::Audio) => {
-                            format!("segments/audio/segment_{:03}.m4s", event.index)
-                        }
-                    };
-
-                    let app_clone = app.clone();
-                    let video_id_clone = video_id.clone();
-                    let state_clone = state.clone();
-                    let failures_clone = consecutive_failures.clone();
-                    let semaphore_clone = semaphore.clone();
-                    let read_semaphore_clone = read_semaphore.clone();
-                    let url_cache_clone = url_cache.clone();
-                    let manifest_dirty_clone = manifest_dirty.clone();
-                    let manifest_notify_clone = manifest_notify.clone();
-
-                    let file_path = event.path.clone();
-                    let is_init = event.is_init;
-                    let media_type = event.media_type;
-                    let index = event.index;
-                    let duration = event.duration;
-                    let expected_size = event.file_size;
-                    let subpath_for_fail = subpath.clone();
-
-                    let context = session.context();
-                    let task_session = session.clone();
-                    let handle = tokio::spawn(crate::web_api::inherit_upload_context(context, async move {
-                        task_session.check()?;
-                        let _read_permit = read_semaphore_clone
-                            .acquire()
-                            .await
-                            .map_err(|e| format!("segment_upload/read_semaphore: {e}"))?;
-
-                        let (file_result, url_result) = tokio::join!(
-                            Self::read_segment_data(&file_path, &subpath, expected_size),
-                            url_cache_clone.get_or_fetch(
-                                &app_clone,
-                                &video_id_clone,
-                                &subpath
-                            ),
-                        );
-
-                        let file_data = match file_result {
-                            Ok(data) => data,
-                            Err(e) => {
-                                let prev = failures_clone
-                                    .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
-                                warn!(
-                                    subpath,
-                                    error = %e,
-                                    consecutive_failures = prev + 1,
-                                    "Failed to read segment, queued for retry"
-                                );
-                                let mut s =
-                                    state_clone.lock().unwrap_or_else(|e| e.into_inner());
-                                s.failed_segments.push(FailedSegmentInfo {
-                                    subpath: subpath_for_fail,
-                                    file_path,
-                                    is_init,
-                                    media_type,
-                                    index,
-                                    duration,
-                                    expected_size,
-                                });
-                                return Ok(());
-                            }
-                        };
-
-                        let prefetched_url = match url_result {
-                            Ok(url) => Some(url),
-                            Err(e) => {
-                                warn!(subpath, error = %e, "Pre-fetch URL failed, will fetch on demand");
-                                None
-                            }
-                        };
-
-                        drop(_read_permit);
-
-                        let permit = semaphore_clone
-                            .acquire_owned()
-                            .await
-                            .map_err(|e| format!("segment_upload/semaphore: {e}"))?;
-
-                        let result = Self::put_segment_to_s3(
-                            &app_clone,
-                            &video_id_clone,
-                            &subpath,
-                            file_data,
-                            &url_cache_clone,
-                            prefetched_url,
-                        )
-                        .await;
-
-                        drop(permit);
-
-                        match result {
-                            Err(e) => {
-                                let prev = failures_clone
-                                    .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
-                                warn!(
-                                    subpath,
-                                    error = %e,
-                                    consecutive_failures = prev + 1,
-                                    "Failed to upload segment, queued for retry"
-                                );
-                                let mut s =
-                                    state_clone.lock().unwrap_or_else(|e| e.into_inner());
-                                s.failed_segments.push(FailedSegmentInfo {
-                                    subpath: subpath_for_fail,
-                                    file_path,
-                                    is_init,
-                                    media_type,
-                                    index,
-                                    duration,
-                                    expected_size,
-                                });
-                            }
-                            Ok(bytes) => {
-                                failures_clone
-                                    .store(0, std::sync::atomic::Ordering::Relaxed);
-                                let mut s =
-                                    state_clone.lock().unwrap_or_else(|e| e.into_inner());
-                                s.total_bytes_uploaded += bytes;
-                                if is_init {
-                                    match media_type {
-                                        SegmentMediaType::Video => {
-                                            s.video_init_uploaded = true
-                                        }
-                                        SegmentMediaType::Audio => {
-                                            s.audio_init_uploaded = true
-                                        }
-                                    }
-                                } else {
-                                    match media_type {
-                                        SegmentMediaType::Video => {
-                                            s.uploaded_video_segments
-                                                .insert(index, duration);
-                                        }
-                                        SegmentMediaType::Audio => {
-                                            s.uploaded_audio_segments
-                                                .insert(index, duration);
-                                        }
-                                    }
-                                }
-                                manifest_dirty_clone
-                                    .store(true, std::sync::atomic::Ordering::Release);
-                                manifest_notify_clone.notify_one();
-                                info!(subpath, "Segment uploaded successfully");
-                            }
-                        }
-
-                        Ok(())
-                    }));
-
-                    in_flight.push(handle);
-
-                    if !event.is_init
-                        && event.media_type == SegmentMediaType::Video
-                        && event.index > 0
-                        && event.index % 15 == 0
-                    {
-                        let cache = url_cache.clone();
-                        let app_ref = app.clone();
-                        let vid_ref = video_id.clone();
-                        let from = event.index + 1;
-                        let context = session.context();
-                        prefetch_tasks.push(tokio::spawn(crate::web_api::inherit_upload_context(context, async move {
-                            cache.extend_prefetch(&app_ref, &vid_ref, from, 20).await;
-                        })));
-                    }
-
-                    if consecutive_failures.load(std::sync::atomic::Ordering::Relaxed) >= CONSECUTIVE_FAILURE_LIMIT {
-                        warn!("Consecutive upload failures reached threshold, attempting network recovery");
-                        if !wait_for_network_recovery(&app, &video_id).await {
-                            warn!("Network recovery failed during segment upload");
-                        }
-                        consecutive_failures.store(0, std::sync::atomic::Ordering::Relaxed);
-                    }
-                }
-            }
-        }
-
-        drain_segment_upload_tasks(&state, &mut in_flight).await;
-        preparation.stop().await;
-
-        if bridge_handle.join().is_err() {
-            state
-                .lock()
-                .unwrap_or_else(|error| error.into_inner())
-                .record_worker_failure("Segment upload bridge did not complete".to_string());
-        }
-
-        manifest_shutdown.store(true, std::sync::atomic::Ordering::Release);
-        manifest_dirty.store(true, std::sync::atomic::Ordering::Release);
-        manifest_notify.notify_one();
-        let manifest_result = manifest_handle.await;
-        state
-            .lock()
-            .unwrap_or_else(|error| error.into_inner())
-            .record_task_result(manifest_result.map(|()| Ok(())));
-        cancel_segment_prefetch_tasks(&mut prefetch_tasks).await;
-
-        session.check()?;
-        let failed = {
-            let s = state.lock().unwrap_or_else(|e| e.into_inner());
-            s.failed_segments.clone()
-        };
-
-        if !failed.is_empty() {
-            info!(
-                count = failed.len(),
-                "Retrying failed segment uploads before completing"
-            );
-            for seg in failed {
-                session.check()?;
-                let file_data =
-                    Self::read_segment_data(&seg.file_path, &seg.subpath, seg.expected_size).await;
-
-                let file_data = match file_data {
-                    Ok(data) => data,
-                    Err(e) => {
-                        warn!(
-                            subpath = seg.subpath,
-                            error = %e,
-                            "Failed segment retry read failed, segment will be missing"
-                        );
-                        continue;
-                    }
-                };
-
-                match Self::put_segment_to_s3(
-                    &app,
-                    &video_id,
-                    &seg.subpath,
-                    file_data,
-                    &url_cache,
-                    None,
-                )
-                .await
-                {
-                    Ok(bytes) => {
-                        let mut s = state.lock().unwrap_or_else(|e| e.into_inner());
-                        s.total_bytes_uploaded += bytes;
-                        if seg.is_init {
-                            match seg.media_type {
-                                SegmentMediaType::Video => s.video_init_uploaded = true,
-                                SegmentMediaType::Audio => s.audio_init_uploaded = true,
-                            }
-                        } else {
-                            match seg.media_type {
-                                SegmentMediaType::Video => {
-                                    s.uploaded_video_segments.insert(seg.index, seg.duration);
-                                }
-                                SegmentMediaType::Audio => {
-                                    s.uploaded_audio_segments.insert(seg.index, seg.duration);
-                                }
-                            }
-                        }
-                        s.failed_segments.retain(|f| f.subpath != seg.subpath);
-                        info!(subpath = seg.subpath, "Failed segment retry succeeded");
-                    }
-                    Err(e) => {
-                        warn!(
-                            subpath = seg.subpath,
-                            error = %e,
-                            "Failed segment retry also failed, segment will be missing"
-                        );
-                    }
-                }
-            }
-        }
-
-        session.wait_ready().await?;
-        let completion_state = state.as_ref();
-        let expected_events = resume::collect_segment_events(&recording_dir, required_audio)?;
-        validate_uploaded_segment_inventory(
-            &completion_state
-                .lock()
-                .unwrap_or_else(|error| error.into_inner())
-                .completed_manifest()?,
-            &expected_events,
-        )?;
-        publish_completed_segments(completion_state, |final_manifest| async move {
-            let final_json = serde_json::to_vec_pretty(&final_manifest)?;
-            let verification = UploadVerification::segments(&final_json, required_audio);
-            {
-                let mut manifest_err: Option = None;
-                for attempt in 0..3u32 {
-                    match Self::upload_manifest(&app, &video_id, &final_manifest, &url_cache).await
-                    {
-                        Ok(()) => {
-                            manifest_err = None;
-                            break;
-                        }
-                        Err(e) => {
-                            warn!(
-                                attempt = attempt + 1,
-                                "Failed to upload final manifest: {e}"
-                            );
-                            manifest_err = Some(e);
-                            if attempt < 2 {
-                                tokio::time::sleep(Duration::from_millis(
-                                    1000 * (1 << attempt) as u64,
-                                ))
-                                .await;
-                            }
-                        }
-                    }
-                }
-                if let Some(e) = manifest_err {
-                    error!("All attempts to upload final manifest failed for {video_id}");
-
-                    // Leave the UploadMeta::SegmentUpload written at upload start in
-                    // place so resume_uploads retries this recording on next launch.
-                    emit_upload_complete(&app, &video_id);
-
-                    return Err(format!("segment_upload/final_manifest: {e}").into());
-                }
-            }
-
-            // All segments and the final manifest are on the server; the remaining wait is
-            // server-side finalization polled every 5s, which can take minutes and resumes
-            // on the next launch via the persisted verification, so stop blocking app exit.
-            drop(active_upload);
-            await_upload_verification(&app, &video_id, &verification, &session).await?;
-            emit_upload_complete(&app, &video_id);
-
-            let total_bytes = completion_state
-                .lock()
-                .unwrap_or_else(|e| e.into_inner())
-                .total_bytes_uploaded;
-
-            info!(total_bytes, "Segment upload complete for {video_id}");
-
-            Ok(total_bytes)
-        })
-        .await
-    }
-}
-
-pub struct Chunk {
-    total_size: u64,
-    part_number: u32,
-    offset: u64,
-    chunk: Bytes,
-}
-
-struct FailedChunkInfo {
-    part_number: u32,
-    offset: u64,
-    chunk_size: usize,
-    total_size: u64,
-    error: String,
-}
-
-/// Creates a stream that reads chunks from a file, yielding [Chunk]'s.
-#[allow(unused)]
-#[instrument]
-pub fn from_file_to_chunks(path: PathBuf) -> impl Stream> {
-    try_stream! {
-        let file = File::open(path).await?;
-        let total_size = file.metadata().await?.len();
-        let mut file = BufReader::new(file);
-
-        let mut buf = vec![0u8; MAX_CHUNK_SIZE as usize];
-        let mut part_number = 0;
-        let mut current_offset: u64 = 0;
-        loop {
-            part_number += 1;
-            let n = file.read(&mut buf).await?;
-            if n == 0 { break; }
-            yield Chunk {
-                total_size,
-                part_number,
-                offset: current_offset,
-                chunk: Bytes::copy_from_slice(&buf[..n]),
-            };
-            current_offset += n as u64;
-        }
-    }
-    .instrument(Span::current())
-}
-
-/// Creates a stream that reads chunks from a potentially growing file, yielding [Chunk]'s.
-/// The first chunk of the file is yielded last to allow for header rewriting after recording completion.
-/// This uploader will continually poll the filesystem and wait for the file to stop uploading before flushing the rest.
-struct UploadFile {
-    file: Mutex,
-    _guard: Option,
-}
-
-async fn open_upload_file(path: PathBuf) -> io::Result> {
-    let guard = lifecycle::UploadScope::current().map(|scope| scope.read_guard());
-    lifecycle::file_io(move || {
-        Ok(Arc::new(UploadFile {
-            file: Mutex::new(std::fs::File::open(path)?),
-            _guard: guard,
-        }))
-    })
-    .await
-}
-
-async fn upload_file_size(file: Arc) -> io::Result {
-    lifecycle::file_io(move || {
-        file.file
-            .lock()
-            .unwrap_or_else(PoisonError::into_inner)
-            .metadata()
-            .map(|metadata| metadata.len())
-    })
-    .await
-}
-
-async fn upload_file_chunk(file: Arc, offset: u64, count: usize) -> io::Result {
-    lifecycle::file_io(move || {
-        use std::io::{Read, Seek};
-        let mut file = file.file.lock().unwrap_or_else(PoisonError::into_inner);
-        file.seek(std::io::SeekFrom::Start(offset))?;
-        let mut bytes = vec![0; count];
-        file.read_exact(&mut bytes)?;
-        Ok(Bytes::from(bytes))
-    })
-    .await
-}
-
-#[instrument(skip(realtime_upload_done))]
-pub fn from_pending_file_to_chunks(
-    path: PathBuf,
-    realtime_upload_done: Option>,
-) -> impl Stream> {
-    try_stream! {
-        let file = timeout(Duration::from_secs(20), async {
-            loop {
-                if let Ok(file) = open_upload_file(path.clone()).await { return Ok::<_, io::Error>(file); }
-                lifecycle::cancellable(tokio::time::sleep(Duration::from_millis(100))).await.map_err(io::Error::other)?;
-            }
-        }).await.map_err(|_| io::Error::other("Failed to open recording upload file"))??;
-        let mut part_number = 1;
-        let mut offset = 0u64;
-        let mut realtime_is_done = realtime_upload_done.as_ref().map(|_| false);
-        let mut recording_completed_cleanly = false;
-        let mut first_chunk_size = None;
-        loop {
-            lifecycle::cancellable(async {}).await.map_err(io::Error::other)?;
-            if !realtime_is_done.unwrap_or(true) && let Some(receiver) = &realtime_upload_done {
-                match receiver.try_recv() {
-                    Ok(()) => { realtime_is_done = Some(true); recording_completed_cleanly = true; }
-                    Err(flume::TryRecvError::Empty) => {},
-                    Err(flume::TryRecvError::Disconnected) => { realtime_is_done = Some(true); }
-                }
-            }
-            let file_size = upload_file_size(file.clone()).await?;
-            let available = file_size.saturating_sub(offset);
-            let should_read = match realtime_is_done {
-                Some(done) => available >= MIN_CHUNK_SIZE || (done && available > 0),
-                None => available > 0,
-            };
-            if should_read {
-                let count = available.min(MAX_CHUNK_SIZE) as usize;
-                let chunk = upload_file_chunk(file.clone(), offset, count).await?;
-                if offset == 0 { first_chunk_size = Some(count); }
-                yield Chunk { total_size: file_size, part_number, offset, chunk };
-                part_number += 1;
-                offset = offset.saturating_add(count as u64);
-            } else if available == 0 && realtime_is_done.unwrap_or(true) {
-                if let Some(count) = first_chunk_size && realtime_upload_done.is_some() && recording_completed_cleanly {
-                    let chunk = upload_file_chunk(file.clone(), 0, count).await?;
-                    yield Chunk { total_size: file_size, part_number: 1, offset: 0, chunk };
-                }
-                break;
-            } else {
-                lifecycle::cancellable(tokio::time::sleep(Duration::from_millis(100))).await.map_err(io::Error::other)?;
-            }
-        }
-    }.instrument(Span::current())
-}
-
-#[instrument(skip(app, stream, upload_id, failed_chunks))]
-fn multipart_uploader(
-    app: AppHandle,
-    video_id: String,
-    upload_id: String,
-    is_drive_upload: bool,
-    stream: impl Stream> + Send + 'static,
-    failed_chunks: Arc>>,
-) -> impl Stream> + 'static {
-    const MAX_CONCURRENT_UPLOADS: usize = 5;
-
-    debug!("Initializing multipart uploader for video {video_id:?}");
-    let start = Instant::now();
-    let video_id2 = video_id.clone();
-
-    stream::once(async move {
-        let use_md5_hashes = app.is_server_url_custom().await;
-        let max_concurrent_uploads = if is_drive_upload {
-            1
-        } else {
-            MAX_CONCURRENT_UPLOADS
-        };
-        let first_chunk_presigned_url = Arc::new(Mutex::new(None::<(String, Instant)>));
-
-        stream::unfold(
-            (Box::pin(stream), 1),
-            move |(mut stream, expected_part_number)| {
-                let app = app.clone();
-                let video_id = video_id.clone();
-                let upload_id = upload_id.clone();
-                let first_chunk_presigned_url = first_chunk_presigned_url.clone();
-                let failed_chunks = failed_chunks.clone();
-
-                async move {
-                    let (Some(item), presigned_url) = join(stream.next(), async {
-                        if use_md5_hashes {
-                            return Ok(None);
-                        }
-
-                        api::upload_multipart_presign_part(
-                            &app,
-                            &video_id,
-                            &upload_id,
-                            expected_part_number,
-                            None,
-                        )
-                        .await
-                        .map(Some)
-                    })
-                    .await
-                    else {
-                        return None;
-                    };
-
-                    let part_number = item
-                        .as_ref()
-                        .map(|c| c.part_number.to_string())
-                        .unwrap_or_else(|_| "--".into());
-
-                    Some((
-                        async move {
-                            let Chunk {
-                                total_size,
-                                part_number,
-                                chunk,
-                                offset,
-                            } = match item {
-                                Ok(c) => c,
-                                Err(err) => {
-                                    return Some(Err(AuthedApiError::Other(format!(
-                                        "uploader/part/{expected_part_number:?}/fs: {err:?}"
-                                    ))));
-                                }
-                            };
-
-                            let chunk_size = chunk.len();
-
-                            let upload_result = async move {
-                                trace!(
-                                    "Uploading chunk {part_number} ({chunk_size} bytes) for video {video_id:?}",
-                                );
-
-                                let md5_sum =
-                                    use_md5_hashes.then(|| base64::encode(md5::compute(&chunk).0));
-                                let presigned_url = if let Some(url) = presigned_url?
-                                    && part_number == expected_part_number
-                                {
-                                    url
-                                } else if part_number == 1
-                                    && !use_md5_hashes
-                                    && let Some((url, expiry)) = first_chunk_presigned_url
-                                        .lock()
-                                        .unwrap_or_else(PoisonError::into_inner)
-                                        .clone()
-                                    && expiry.elapsed() < Duration::from_secs(60 * 50)
-                                {
-                                    url
-                                } else {
-                                    api::upload_multipart_presign_part(
-                                        &app,
-                                        &video_id,
-                                        &upload_id,
-                                        part_number,
-                                        md5_sum.as_deref(),
-                                    )
-                                    .await?
-                                };
-
-                                if part_number == 1 {
-                                    *first_chunk_presigned_url
-                                        .lock()
-                                        .unwrap_or_else(PoisonError::into_inner) =
-                                        Some((presigned_url.clone(), Instant::now()));
-                                }
-
-                                let size = chunk.len();
-                                let chunk_for_retry = chunk.clone();
-                                let client = app
-                                    .state::()
-                                    .as_ref()
-                                    .map_err(|err| {
-                                        format!("uploader/part/{part_number}/client: {err:?}")
-                                    })?
-                                    .clone();
-
-                                let req = client
-                                    .put(&presigned_url)
-                                    .header("Content-Length", size)
-                                    .timeout(Duration::from_secs(5 * 60))
-                                    .body(chunk);
-                                let mut req = with_drive_content_range(
-                                    req,
-                                    &presigned_url,
-                                    offset,
-                                    size as u64,
-                                    total_size,
-                                );
-
-                                if let Some(md5_sum) = &md5_sum {
-                                    req = req.header("Content-MD5", md5_sum);
-                                }
-
-                                let send_result = lifecycle::cancellable(req.send().instrument(info_span!("s3_put", size = size))).await?.map_err(reqwest::Error::without_url);
-
-                                let resp = match send_result {
-                                    Ok(resp) => resp,
-                                    Err(err) if is_reqwest_network_error(&err) => {
-                                        info!(
-                                            part_number,
-                                            error = %err,
-                                            "Chunk upload failed due to network error, waiting for connectivity"
-                                        );
-                                        if !wait_for_network_recovery(&app, &video_id).await {
-                                            return Err(format!(
-                                                "uploader/part/{part_number}/network_timeout: {err:?}"
-                                            )
-                                            .into());
-                                        }
-                                        let retry_url = api::upload_multipart_presign_part(
-                                            &app,
-                                            &video_id,
-                                            &upload_id,
-                                            part_number,
-                                            md5_sum.as_deref(),
-                                        )
-                                        .await?;
-                                        let retry_req = client
-                                            .put(&retry_url)
-                                            .header("Content-Length", size)
-                                            .timeout(Duration::from_secs(5 * 60))
-                                            .body(chunk_for_retry);
-                                        let mut retry_req = with_drive_content_range(
-                                            retry_req,
-                                            &retry_url,
-                                            offset,
-                                            size as u64,
-                                            total_size,
-                                        );
-                                        if let Some(md5_sum) = &md5_sum {
-                                            retry_req =
-                                                retry_req.header("Content-MD5", md5_sum);
-                                        }
-                                        lifecycle::cancellable(retry_req.send().instrument(info_span!("s3_put_after_network_recovery", size = size))).await?
-                                            .map_err(reqwest::Error::without_url)
-                                            .map_err(|err| {
-                                                format!(
-                                                    "uploader/part/{part_number}/network_retry_error: {err:?}"
-                                                )
-                                            })?
-                                    }
-                                    Err(err) => {
-                                        return Err(format!(
-                                            "uploader/part/{part_number}/error: {err:?}"
-                                        )
-                                        .into());
-                                    }
-                                };
-
-                                let etag = resp
-                                    .headers()
-                                    .get("ETag")
-                                    .as_ref()
-                                    .and_then(|etag| etag.to_str().ok())
-                                    .map(|v| v.trim_matches('"').to_string());
-
-                                if !is_upload_response_accepted(&presigned_url, resp.status(), offset, size as u64, total_size) {
-                                    return Err(format!("uploader/part/{part_number}/error: {}", resp.status()).into());
-                                }
-
-                                trace!("Completed upload of part {part_number}");
-
-                                let etag = match etag {
-                                    Some(etag) => etag,
-                                    None if is_google_drive_resumable_url(&presigned_url) => {
-                                        format!("drive-{part_number}")
-                                    }
-                                    None => {
-                                        return Err(format!(
-                                            "uploader/part/{part_number}/missing_etag"
-                                        )
-                                        .into());
-                                    }
-                                };
-
-                                let object_identity = completed_drive_upload_identity(resp, is_google_drive_resumable_url(&presigned_url), total_size).await;
-                                Ok::<_, AuthedApiError>(UploadedPart {
-                                    object_identity,
-                                    etag,
-                                    part_number,
-                                    size,
-                                    total_size,
-                                })
-                            }
-                            .await;
-
-                            match upload_result {
-                                Ok(part) => Some(Ok(part)),
-                                Err(err) => {
-                                    warn!(
-                                        part_number = part_number,
-                                        offset = offset,
-                                        chunk_size = chunk_size,
-                                        error = %err,
-                                        "Chunk upload failed, will retry after remaining chunks"
-                                    );
-                                    failed_chunks
-                                        .lock()
-                                        .unwrap_or_else(PoisonError::into_inner)
-                                        .push(FailedChunkInfo {
-                                            part_number,
-                                            offset,
-                                            chunk_size,
-                                            total_size,
-                                            error: err.to_string(),
-                                        });
-                                    None
-                                }
-                            }
-                        }
-                        .instrument(info_span!("upload_part", part_number = part_number)),
-                        (stream, expected_part_number + 1),
-                    ))
-                }
-            },
-        )
-        .buffered(max_concurrent_uploads)
-        .filter_map(|item| async { item })
-        .boxed()
-    })
-    .chain(stream::once(async move {
-        debug!(
-            "Completed multipart upload for {video_id2:?} in {:?}",
-            start.elapsed()
-        );
-
-        stream::empty().boxed()
-    }))
-    .flatten()
-    .instrument(Span::current())
-}
-
-async fn read_exact_upload_chunk(
-    file_path: &Path,
-    offset: u64,
-    expected_size: usize,
-) -> io::Result {
-    if expected_size == 0 {
-        return Err(io::Error::new(
-            io::ErrorKind::InvalidInput,
-            "Upload chunk must not be empty",
-        ));
-    }
-    let path = file_path.to_path_buf();
-    lifecycle::file_io(move || {
-        use std::io::{Read, Seek};
-        let mut file = std::fs::File::open(path)?;
-        file.seek(std::io::SeekFrom::Start(offset))?;
-        let mut bytes = vec![0; expected_size];
-        file.read_exact(&mut bytes)?;
-        Ok(Bytes::from(bytes))
-    })
-    .await
-}
-
-#[instrument(skip(app, failed_chunks))]
-async fn retry_failed_chunks(
-    app: &AppHandle,
-    video_id: &str,
-    upload_id: &str,
-    file_path: &Path,
-    failed_chunks: Vec,
-) -> Result, AuthedApiError> {
-    retry_failed_chunks_with_input(app, video_id, upload_id, file_path, failed_chunks, None).await
-}
-
-async fn retry_failed_chunks_with_input(
-    app: &AppHandle,
-    video_id: &str,
-    upload_id: &str,
-    file_path: &Path,
-    failed_chunks: Vec,
-    input: Option<&LegacyReplacementInput>,
-) -> Result, AuthedApiError> {
-    let use_md5_hashes = app.is_server_url_custom().await;
-    let mut retry_parts = Vec::new();
-
-    for failed in &failed_chunks {
-        info!(
-            part_number = failed.part_number,
-            offset = failed.offset,
-            chunk_size = failed.chunk_size,
-            original_error = %failed.error,
-            "Retrying failed chunk upload"
-        );
-
-        let chunk = read_exact_upload_chunk(file_path, failed.offset, failed.chunk_size)
-            .await
-            .map_err(|error| format!("retry/part/{}/read: {error}", failed.part_number))?;
-
-        if let Some(input) = input {
-            input
-                .inspect_chunk(
-                    &Chunk {
-                        total_size: failed.total_size,
-                        part_number: failed.part_number,
-                        offset: failed.offset,
-                        chunk: chunk.clone(),
-                    },
-                    false,
-                )
-                .map_err(|error| error.to_string())?;
-        }
-
-        let md5_sum = use_md5_hashes.then(|| base64::encode(md5::compute(&chunk).0));
-
-        let presigned_url = api::upload_multipart_presign_part(
-            app,
-            video_id,
-            upload_id,
-            failed.part_number,
-            md5_sum.as_deref(),
-        )
-        .await?;
-
-        let size = chunk.len();
-        let chunk_for_retry = chunk.clone();
-        let client = app
-            .state::()
-            .as_ref()
-            .map_err(|err| format!("retry/part/{}/client: {err:?}", failed.part_number))?
-            .clone();
-
-        let req = client
-            .put(&presigned_url)
-            .header("Content-Length", size)
-            .timeout(Duration::from_secs(5 * 60))
-            .body(chunk);
-        let mut req = with_drive_content_range(
-            req,
-            &presigned_url,
-            failed.offset,
-            size as u64,
-            failed.total_size,
-        );
-
-        if let Some(md5_sum) = &md5_sum {
-            req = req.header("Content-MD5", md5_sum);
-        }
-
-        let send_result = lifecycle::cancellable(req.send().instrument(info_span!(
-            "s3_put_retry",
-            part_number = failed.part_number,
-            size = size
-        )))
-        .await?
-        .map_err(reqwest::Error::without_url);
-
-        let resp = match send_result {
-            Ok(resp) => resp,
-            Err(err) if is_reqwest_network_error(&err) => {
-                info!(
-                    part_number = failed.part_number,
-                    error = %err,
-                    "Retry chunk upload failed due to network error, waiting for connectivity"
-                );
-                if !wait_for_network_recovery(app, video_id).await {
-                    return Err(format!(
-                        "retry/part/{}/network_timeout: {err:?}",
-                        failed.part_number
-                    )
-                    .into());
-                }
-                let retry_url = api::upload_multipart_presign_part(
-                    app,
-                    video_id,
-                    upload_id,
-                    failed.part_number,
-                    md5_sum.as_deref(),
-                )
-                .await?;
-                let retry_req = client
-                    .put(&retry_url)
-                    .header("Content-Length", size)
-                    .timeout(Duration::from_secs(5 * 60))
-                    .body(chunk_for_retry);
-                let mut retry_req = with_drive_content_range(
-                    retry_req,
-                    &retry_url,
-                    failed.offset,
-                    size as u64,
-                    failed.total_size,
-                );
-                if let Some(md5_sum) = &md5_sum {
-                    retry_req = retry_req.header("Content-MD5", md5_sum);
-                }
-                lifecycle::cancellable(retry_req.send().instrument(info_span!(
-                    "s3_put_retry_after_network_recovery",
-                    part_number = failed.part_number,
-                    size = size
-                )))
-                .await?
-                .map_err(reqwest::Error::without_url)
-                .map_err(|err| {
-                    format!(
-                        "retry/part/{}/network_retry_error: {err:?}",
-                        failed.part_number
-                    )
-                })?
-            }
-            Err(err) => {
-                return Err(format!("retry/part/{}/error: {err:?}", failed.part_number).into());
-            }
-        };
-
-        let etag = resp
-            .headers()
-            .get("ETag")
-            .as_ref()
-            .and_then(|etag| etag.to_str().ok())
-            .map(|v| v.trim_matches('"').to_string());
-
-        if !is_upload_response_accepted(
-            &presigned_url,
-            resp.status(),
-            failed.offset,
-            size as u64,
-            failed.total_size,
-        ) {
-            return Err(
-                format!("retry/part/{}/error: {}", failed.part_number, resp.status()).into(),
-            );
-        }
-
-        info!(
-            part_number = failed.part_number,
-            "Successfully retried chunk upload"
-        );
-
-        let etag = match etag {
-            Some(etag) => etag,
-            None if is_google_drive_resumable_url(&presigned_url) => {
-                format!("drive-{}", failed.part_number)
-            }
-            None => {
-                return Err(format!("retry/part/{}/missing_etag", failed.part_number).into());
-            }
-        };
-
-        let object_identity = completed_drive_upload_identity(
-            resp,
-            is_google_drive_resumable_url(&presigned_url),
-            failed.total_size,
-        )
-        .await;
-        retry_parts.push(UploadedPart {
-            object_identity,
-            etag,
-            part_number: failed.part_number,
-            size,
-            total_size: failed.total_size,
-        });
-    }
-
-    Ok(retry_parts)
-}
-
-async fn completed_drive_upload_identity(
-    response: reqwest::Response,
-    is_drive: bool,
-    expected_size: u64,
-) -> Option {
-    if !is_drive || !response.status().is_success() {
-        return None;
-    }
-    lifecycle::cancellable(response.json::())
-        .await
-        .ok()?
-        .ok()
-        .and_then(|value| {
-            cap_recording::upload_verification::completed_drive_object_identity(
-                &value,
-                expected_size,
-            )
-        })
-}
-
-fn is_reqwest_network_error(err: &reqwest::Error) -> bool {
-    err.is_connect() || err.is_timeout() || err.status().is_none()
-}
-
-async fn probe_connectivity(app: &AppHandle) -> bool {
-    let url = app.make_app_url("/").await;
-    app.state::()
-        .head(&url)
-        .timeout(Duration::from_secs(5))
-        .send()
-        .await
-        .is_ok()
-}
-
-async fn wait_for_network_recovery(app: &AppHandle, video_id: &str) -> bool {
-    let start = Instant::now();
-    let mut delay = CONNECTIVITY_PROBE_INITIAL_DELAY;
-
-    warn!(
-        video_id,
-        "Network loss detected, pausing uploads until connectivity is restored"
-    );
-
-    loop {
-        if start.elapsed() > NETWORK_RECOVERY_TIMEOUT {
-            error!(
-                video_id,
-                elapsed_secs = start.elapsed().as_secs(),
-                "Network recovery timeout exceeded (5 minutes), giving up"
-            );
-            return false;
-        }
-
-        if lifecycle::cancellable(tokio::time::sleep(delay))
-            .await
-            .is_err()
-        {
-            return false;
-        }
-
-        if lifecycle::cancellable(probe_connectivity(app))
-            .await
-            .unwrap_or(false)
-        {
-            info!(
-                video_id,
-                waited_secs = start.elapsed().as_secs(),
-                "Network connectivity restored, resuming uploads"
-            );
-            return true;
-        }
-
-        delay = (delay * 2).min(CONNECTIVITY_PROBE_MAX_DELAY);
-    }
-}
-
-#[instrument(skip(app, stream))]
-pub async fn singlepart_uploader(
-    app: AppHandle,
-    request: PresignedS3PutRequest,
-    total_size: u64,
-    stream: impl Stream> + Send + 'static,
-) -> Result<(), AuthedApiError> {
-    let upload_target = api::upload_signed(&app, request).await?;
-    let presigned_url = upload_target.url;
-
-    let mut request = app
-        .state::()
-        .as_ref()
-        .map_err(|err| format!("singlepart_uploader/client: {err:?}"))?
-        .put(&presigned_url)
-        .header("Content-Length", total_size)
-        .body(reqwest::Body::wrap_stream(stream));
-
-    for (key, value) in upload_target.headers {
-        if key.eq_ignore_ascii_case("content-length") {
-            continue;
-        }
-        request = request.header(key, value);
-    }
-
-    let resp = lifecycle::cancellable(
-        with_drive_content_range(request, &presigned_url, 0, total_size, total_size).send(),
-    )
-    .await?
-    .map_err(reqwest::Error::without_url)
-    .map_err(|err| format!("singlepart_uploader/error: {err:?}"))?;
-
-    match !resp.status().is_success() {
-        true => Err(format!("singlepart_uploader/error: {}", resp.status())),
-        false => Ok(()),
-    }?;
-
-    Ok(())
-}
-
-pub trait UploadedChunk {
-    /// total size of the file
-    fn total(&self) -> u64;
-
-    /// size of the current chunk
-    fn size(&self) -> u64;
-}
-
-impl UploadedChunk for UploadedPart {
-    fn total(&self) -> u64 {
-        self.total_size
-    }
-
-    fn size(&self) -> u64 {
-        self.size as u64
-    }
-}
-
-impl UploadedChunk for Chunk {
-    fn total(&self) -> u64 {
-        self.total_size
-    }
-
-    fn size(&self) -> u64 {
-        self.chunk.len() as u64
-    }
-}
-
-impl UploadedChunk for (u64, Bytes) {
-    fn total(&self) -> u64 {
-        self.0
-    }
-
-    fn size(&self) -> u64 {
-        self.1.len() as u64
-    }
-}
-
-/// Monitor the stream to report the upload progress
-fn progress(
-    app: AppHandle,
-    video_id: String,
-    stream: impl Stream>,
-) -> impl Stream> {
-    let mut uploaded = 0u64;
-    let mut pending_task: Option> = None;
-    let mut reemit_task: Option> = None;
-
-    stream! {
-        let mut stream = pin!(stream);
-
-        while let Some(chunk) = stream.next().await {
-            if let Ok(chunk) = &chunk {
-                uploaded += chunk.size();
-                let total = chunk.total();
-
-                if let Some(handle) = pending_task.take() {
-                    handle.abort();
-                }
-
-                if let Some(handle) = reemit_task.take() {
-                    handle.abort();
-                }
-
-                let should_send_immediately = uploaded >= total;
-
-                if should_send_immediately {
-                    let app_clone = app.clone();
-                    let video_id_clone = video_id.clone();
-                    tokio::spawn(crate::web_api::inherit_upload_context(crate::web_api::UploadRequestContext::current(), async move {
-                        api::desktop_video_progress(&app_clone, &video_id_clone, uploaded, total).await.ok();
-                    }));
-                } else {
-                    let app_clone = app.clone();
-                    let video_id_clone = video_id.clone();
-                    pending_task = Some(tokio::spawn(crate::web_api::inherit_upload_context(crate::web_api::UploadRequestContext::current(), async move {
-                        tokio::time::sleep(Duration::from_secs(2)).await;
-                        api::desktop_video_progress(&app_clone, &video_id_clone, uploaded, total).await.ok();
-                    })));
-
-                    let app_reemit = app.clone();
-                    let video_id_reemit = video_id.clone();
-                    let uploaded_reemit = uploaded;
-                    let total_reemit = total;
-                    reemit_task = Some(tokio::spawn(async move {
-                        let mut interval = time::interval(Duration::from_millis(700));
-                        interval.tick().await;
-
-                        loop {
-                            interval.tick().await;
-                            UploadProgressEvent {
-                                video_id: video_id_reemit.clone(),
-                                uploaded: uploaded_reemit.to_string(),
-                                total: total_reemit.to_string(),
-                            }
-                            .emit(&app_reemit)
-                            .ok();
-                        }
-                    }));
-                }
-
-                UploadProgressEvent {
-                    video_id: video_id.clone(),
-                    uploaded: uploaded.to_string(),
-                    total: total.to_string(),
-                }
-                .emit(&app)
-                .ok();
-            }
-
-            yield chunk;
-        }
-
-        if let Some(handle) = reemit_task.take() {
-            handle.abort();
-        }
-    }
-}
-
-pub fn emit_upload_complete(app: &AppHandle, video_id: &str) {
-    UploadProgressEvent {
-        video_id: video_id.to_string(),
-        uploaded: "0".into(),
-        total: "0".into(),
-    }
-    .emit(app)
-    .ok();
-}
-
-/// Track the upload progress into a Tauri channel
-fn tauri_channel_progress(
-    channel: Channel,
-    stream: impl Stream>,
-) -> impl Stream> {
-    let mut uploaded = 0u64;
-
-    stream! {
-        let mut stream = pin!(stream);
-
-        while let Some(chunk) = stream.next().await {
-            if let Ok(chunk) = &chunk {
-                uploaded += chunk.size();
-
-                channel.send(UploadProgress {
-                    progress: uploaded as f64 / chunk.total() as f64
-                })
-                .ok();
-            }
-
-            yield chunk;
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use std::io::Write;
-    use std::sync::atomic::{AtomicU32, Ordering};
-
-    #[test]
-    fn created_video_uses_a_custom_domain_share_link() {
-        let created = parse_created_video(
-            r#"{"id":"abc123","share_url":"https://videos.team.test/s/abc123","user_id":"u"}"#,
-        )
-        .unwrap();
-        assert_eq!(created.config.id, "abc123");
-        assert_eq!(
-            created.share_url.as_deref(),
-            Some("https://videos.team.test/s/abc123")
-        );
-    }
-
-    #[test]
-    fn created_video_without_a_share_link_keeps_the_default() {
-        let created = parse_created_video(r#"{"id":"abc123","user_id":"u"}"#).unwrap();
-        assert_eq!(created.config.id, "abc123");
-        assert_eq!(created.share_url, None);
-
-        let created = parse_created_video(r#"{"id":"abc123","share_url":null}"#).unwrap();
-        assert_eq!(created.share_url, None);
-    }
-
-    #[test]
-    fn created_video_ignores_share_links_for_other_pages() {
-        for share_url in [
-            "",
-            "not a url",
-            "http://videos.team.test/s/abc123",
-            "https://videos.team.test/s/other",
-            "https://videos.team.test/s/abc123/extra",
-            "https://videos.team.test/c/abc123",
-            "https://videos.team.test/s/abc123?x=1",
-            "https://videos.team.test/s/abc123#x",
-            "https://user:pass@videos.team.test/s/abc123",
-            "https://videos.team.test:8443/s/abc123",
-            "javascript:alert(1)//s/abc123",
-        ] {
-            let body = serde_json::json!({ "id": "abc123", "share_url": share_url }).to_string();
-            let created = parse_created_video(&body).unwrap();
-            assert_eq!(created.share_url, None, "{share_url}");
-        }
-    }
-
-    #[tokio::test]
-    async fn restart_requires_a_signed_session_before_any_further_upload_work() {
-        for upload_id in ["legacy-again", "cap-reupload.signed"] {
-            let uploads = AtomicUsize::new(0);
-            let uploads = &uploads;
-            let result = with_replacement_restart(true, |restarted| async move {
-                validate_replacement_restart_session(
-                    restarted,
-                    if restarted { upload_id } else { "legacy-first" },
-                )?;
-                uploads.fetch_add(1, Ordering::AcqRel);
-                Ok(if restarted {
-                    ReplacementAttempt::Completed(())
-                } else {
-                    ReplacementAttempt::RestartRequired
-                })
-            })
-            .await;
-            assert_eq!(result.is_ok(), upload_id.starts_with("cap-reupload."));
-            assert_eq!(
-                uploads.load(Ordering::Acquire),
-                if result.is_ok() { 2 } else { 1 }
-            );
-        }
-    }
-
-    #[tokio::test]
-    async fn legacy_replacement_restarts_the_entire_attempt_once() {
-        let stages = Mutex::new(Vec::new());
-        let identity = with_replacement_restart(true, |restarted| {
-            let mut stages = stages.lock().unwrap();
-            let session = if restarted { "fresh" } else { "legacy" };
-            stages.extend([
-                (session, "initiate"),
-                (session, "parts"),
-                (session, "complete"),
-            ]);
-            std::future::ready(Ok(if restarted {
-                ReplacementAttempt::Completed("fresh-object")
-            } else {
-                ReplacementAttempt::RestartRequired
-            }))
-        })
-        .await
-        .unwrap();
-        assert_eq!(identity, "fresh-object");
-        assert_eq!(
-            *stages.lock().unwrap(),
-            vec![
-                ("legacy", "initiate"),
-                ("legacy", "parts"),
-                ("legacy", "complete"),
-                ("fresh", "initiate"),
-                ("fresh", "parts"),
-                ("fresh", "complete"),
-            ]
-        );
-    }
-
-    #[tokio::test]
-    async fn replacement_restart_is_bounded_and_never_turns_failure_into_success() {
-        for (replace_existing, expected) in [(false, 1), (true, 2)] {
-            let calls = AtomicUsize::new(0);
-            let result = with_replacement_restart(replace_existing, |_| {
-                calls.fetch_add(1, Ordering::AcqRel);
-                std::future::ready(Ok::, AuthedApiError>(
-                    ReplacementAttempt::RestartRequired,
-                ))
-            })
-            .await;
-            assert!(result.is_err());
-            assert_eq!(calls.load(Ordering::Acquire), expected);
-        }
-        for restart_first in [false, true] {
-            let calls = AtomicUsize::new(0);
-            let result = with_replacement_restart(true, |restarted| {
-                calls.fetch_add(1, Ordering::AcqRel);
-                std::future::ready(if restart_first && !restarted {
-                    Ok(ReplacementAttempt::<()>::RestartRequired)
-                } else {
-                    Err(AuthedApiError::InvalidAuthentication)
-                })
-            })
-            .await;
-            assert!(matches!(result, Err(AuthedApiError::InvalidAuthentication)));
-            assert_eq!(
-                calls.load(Ordering::Acquire),
-                if restart_first { 2 } else { 1 }
-            );
-        }
-    }
-
-    #[tokio::test]
-    async fn successful_or_dropped_attempt_cannot_start_a_replacement() {
-        let calls = AtomicUsize::new(0);
-        let result = with_replacement_restart(true, |_| {
-            calls.fetch_add(1, Ordering::AcqRel);
-            std::future::ready(Ok(ReplacementAttempt::Completed(None::)))
-        })
-        .await
-        .unwrap();
-        assert_eq!(result, None);
-        assert_eq!(calls.load(Ordering::Acquire), 1);
-        let future = with_replacement_restart(true, |_| {
-            calls.fetch_add(1, Ordering::AcqRel);
-            std::future::pending::, AuthedApiError>>()
-        });
-        let mut future = Box::pin(future);
-        assert!(matches!(
-            futures::poll!(&mut future),
-            std::task::Poll::Pending
-        ));
-        drop(future);
-        assert_eq!(calls.load(Ordering::Acquire), 2);
-    }
-
-    #[test]
-    fn only_raw_replacement_sessions_need_byte_receipts() {
-        for replace_existing in [false, true] {
-            assert!(!legacy_replacement_session(
-                replace_existing,
-                "cap-reupload.signed-token"
-            ));
-        }
-        for upload_id in [
-            "raw-s3-id",
-            "https://www.googleapis.com/upload/raw-drive-session",
-        ] {
-            assert!(!legacy_replacement_session(false, upload_id));
-            assert!(legacy_replacement_session(true, upload_id));
-        }
-    }
-
-    fn replacement_input() -> LegacyReplacementInput {
-        LegacyReplacementInput {
-            path: PathBuf::from("unused"),
-            size: 4,
-            modified: std::time::SystemTime::UNIX_EPOCH,
-            chunks: Mutex::new(HashMap::new()),
-        }
-    }
-
-    fn replacement_chunk(bytes: &'static [u8]) -> Chunk {
-        Chunk {
-            total_size: 4,
-            part_number: 1,
-            offset: 0,
-            chunk: Bytes::from_static(bytes),
-        }
-    }
-
-    #[test]
-    fn restarted_and_failed_part_reads_must_match_original_bytes() {
-        let input = replacement_input();
-        let original = replacement_chunk(b"test");
-        assert!(input.inspect_chunk(&original, false).is_err());
-        input.inspect_chunk(&original, true).unwrap();
-        input.inspect_chunk(&original, false).unwrap();
-        for changed in [
-            replacement_chunk(b"best"),
-            Chunk {
-                offset: 1,
-                ..replacement_chunk(b"test")
-            },
-            Chunk {
-                total_size: 5,
-                ..replacement_chunk(b"test")
-            },
-            Chunk {
-                part_number: 2,
-                ..replacement_chunk(b"test")
-            },
-            replacement_chunk(b""),
-        ] {
-            assert!(input.inspect_chunk(&changed, false).is_err());
-        }
-        assert!(
-            input
-                .inspect_chunk(&replacement_chunk(b"best"), true)
-                .is_err()
-        );
-        input.inspect_chunk(&original, false).unwrap();
-    }
-
-    #[test]
-    fn replacement_completion_requires_the_complete_verified_inventory() {
-        let input = replacement_input();
-        input
-            .inspect_chunk(&replacement_chunk(b"test"), true)
-            .unwrap();
-        assert!(input.verify_parts(&[]).is_err());
-        let mut parts = vec![UploadedPart {
-            part_number: 1,
-            etag: "fresh-etag".into(),
-            size: 4,
-            total_size: 4,
-            object_identity: None,
-        }];
-        input.verify_parts(&parts).unwrap();
-        parts[0].size = 3;
-        assert!(input.verify_parts(&parts).is_err());
-        parts[0].size = 4;
-        parts[0].total_size = 5;
-        assert!(input.verify_parts(&parts).is_err());
-        parts[0].total_size = 4;
-        parts[0].part_number = 2;
-        assert!(input.verify_parts(&parts).is_err());
-    }
-
-    #[tokio::test]
-    async fn changed_local_input_blocks_fresh_initiation_after_restart_response() {
-        let directory = tempfile::tempdir().unwrap();
-        let path = directory.path().join("output.mp4");
-        std::fs::write(&path, b"test").unwrap();
-        let input = LegacyReplacementInput::capture(&path).await.unwrap();
-        let initiations = AtomicUsize::new(0);
-        let result = with_replacement_restart(true, |restarted| {
-            let path = &path;
-            let input = &input;
-            let initiations = &initiations;
-            async move {
-                input.verify(path).await?;
-                initiations.fetch_add(1, Ordering::AcqRel);
-                if !restarted {
-                    std::fs::write(path, b"changed").unwrap();
-                    return Ok(ReplacementAttempt::RestartRequired);
-                }
-                Ok(ReplacementAttempt::Completed(()))
-            }
-        })
-        .await;
-        assert!(result.is_err());
-        assert_eq!(initiations.load(Ordering::Acquire), 1);
-        assert_eq!(std::fs::read(&path).unwrap(), b"changed");
-    }
-
-    #[test]
-    fn reupload_keeps_sharing_identity_after_completion_or_failure() {
-        let sharing = cap_project::SharingMeta {
-            id: "existing-video".into(),
-            link: "https://cap.link/existing-video".into(),
-            content_hash: None,
-        };
-        for upload in [
-            None,
-            Some(cap_project::UploadMeta::Complete),
-            Some(cap_project::UploadMeta::Failed {
-                error: "offline".into(),
-            }),
-        ] {
-            assert_eq!(
-                reusable_video_id(Some(&sharing), upload.as_ref()).as_deref(),
-                Some("existing-video")
-            );
-        }
-    }
-
-    #[test]
-    fn retry_keeps_the_reserved_identity_until_sharing_is_saved() {
-        let upload = cap_project::UploadMeta::SinglePartUpload {
-            video_id: "reserved-video".into(),
-            file_path: "output.mp4".into(),
-            screenshot_path: "display.jpg".into(),
-            recording_dir: "recording.cap".into(),
-        };
-        assert_eq!(
-            reusable_video_id(None, Some(&upload)).as_deref(),
-            Some("reserved-video")
-        );
-        assert_eq!(reusable_video_id(None, None), None);
-    }
-
-    #[test]
-    fn active_upload_guards_track_overlapping_sessions() {
-        let active = AtomicUsize::new(0);
-        let first = ActiveUploadGuard::new(&active);
-        let second = ActiveUploadGuard::new(&active);
-
-        assert_eq!(active.load(Ordering::Acquire), 2);
-        drop(first);
-        assert_eq!(active.load(Ordering::Acquire), 1);
-        drop(second);
-        assert_eq!(active.load(Ordering::Acquire), 0);
-    }
-
-    #[test]
-    fn dropping_an_upload_future_releases_its_session() {
-        let active = AtomicUsize::new(0);
-        let mut upload = Box::pin(async {
-            let _guard = ActiveUploadGuard::new(&active);
-            std::future::pending::<()>().await;
-        });
-
-        let mut context = std::task::Context::from_waker(std::task::Waker::noop());
-        assert!(std::future::Future::poll(upload.as_mut(), &mut context).is_pending());
-        assert_eq!(active.load(Ordering::Acquire), 1);
-        drop(upload);
-        assert_eq!(active.load(Ordering::Acquire), 0);
-    }
-
-    #[test]
-    fn screenshot_upload_subpath_matches_content_type() {
-        assert_eq!(
-            screenshot_upload_subpath("image/png"),
-            "screenshot/screen-capture.png"
-        );
-        assert_eq!(
-            screenshot_upload_subpath("image/jpeg"),
-            "screenshot/screen-capture.jpg"
-        );
-        assert_eq!(
-            screenshot_content_type_from_path(Path::new("screen-capture.png")),
-            "image/png"
-        );
-        assert_eq!(
-            screenshot_content_type_from_path(Path::new("screen-capture.jpg")),
-            "image/jpeg"
-        );
-    }
-
-    #[tokio::test]
-    async fn multipart_retry_reads_exact_file_range_without_padding() {
-        let dir = tempfile::tempdir().unwrap();
-        let path = dir.path().join("output.mp4");
-        let data = b"init-video-fragment-final";
-        std::fs::write(&path, data).unwrap();
-
-        let chunk = read_exact_upload_chunk(&path, 5, 14).await.unwrap();
-        assert_eq!(chunk.as_ref(), &data[5..19]);
-
-        for (offset, size) in [(5, data.len()), (data.len() as u64, 1)] {
-            let error = read_exact_upload_chunk(&path, offset, size)
-                .await
-                .unwrap_err();
-            assert_eq!(error.kind(), io::ErrorKind::UnexpectedEof);
-        }
-        assert_eq!(
-            read_exact_upload_chunk(&path, 0, 0)
-                .await
-                .unwrap_err()
-                .kind(),
-            io::ErrorKind::InvalidInput
-        );
-
-        std::fs::write(&path, b"").unwrap();
-        assert_eq!(
-            read_exact_upload_chunk(&path, 0, 1)
-                .await
-                .unwrap_err()
-                .kind(),
-            io::ErrorKind::UnexpectedEof
-        );
-    }
-
-    #[tokio::test]
-    async fn read_segment_data_returns_existing_file() {
-        let dir = tempfile::tempdir().unwrap();
-        let path = dir.path().join("segment_001.m4s");
-        std::fs::write(&path, b"fake segment data 12345").unwrap();
-
-        let result = SegmentUploader::read_segment_data(
-            &path,
-            "segments/video/segment_001.m4s",
-            b"fake segment data 12345".len() as u64,
-        )
-        .await;
-
-        let data = result.unwrap();
-        assert_eq!(data.as_ref(), b"fake segment data 12345");
-    }
-
-    #[tokio::test]
-    async fn read_segment_data_waits_for_file_to_appear() {
-        let dir = tempfile::tempdir().unwrap();
-        let path = dir.path().join("segment_002.m4s");
-
-        let path_clone = path.clone();
-        tokio::spawn(async move {
-            tokio::time::sleep(Duration::from_millis(200)).await;
-            std::fs::write(&path_clone, b"delayed segment data").unwrap();
-        });
-
-        let start = Instant::now();
-        let result = SegmentUploader::read_segment_data(
-            &path,
-            "segments/video/segment_002.m4s",
-            b"delayed segment data".len() as u64,
-        )
-        .await;
-        let elapsed = start.elapsed();
-
-        let data = result.unwrap();
-        assert_eq!(data.as_ref(), b"delayed segment data");
-        assert!(
-            elapsed >= Duration::from_millis(150),
-            "should have waited for file: {elapsed:?}"
-        );
-        assert!(
-            elapsed < Duration::from_secs(2),
-            "should not have waited too long: {elapsed:?}"
-        );
-    }
-
-    #[tokio::test]
-    async fn read_segment_data_waits_for_expected_size() {
-        let dir = tempfile::tempdir().unwrap();
-        let path = dir.path().join("segment_003.m4s");
-
-        let mut file = std::fs::File::create(&path).unwrap();
-        file.write_all(b"sm").unwrap();
-        file.flush().unwrap();
-        drop(file);
-
-        let path_clone = path.clone();
-        tokio::spawn(async move {
-            tokio::time::sleep(Duration::from_millis(200)).await;
-            std::fs::write(&path_clone, b"full segment data here!").unwrap();
-        });
-
-        let result = SegmentUploader::read_segment_data(
-            &path,
-            "segments/video/segment_003.m4s",
-            b"full segment data here!".len() as u64,
-        )
-        .await;
-
-        let data = result.unwrap();
-        assert_eq!(data.as_ref(), b"full segment data here!");
-    }
-
-    #[tokio::test]
-    async fn read_segment_data_rejects_empty_short_oversized_and_unknown_size() {
-        let dir = tempfile::tempdir().unwrap();
-        let path = dir.path().join("segment.m4s");
-        for (bytes, expected_size) in [
-            (b"".as_slice(), 5),
-            (b"tiny".as_slice(), 5),
-            (b"too long".as_slice(), 5),
-            (b"valid".as_slice(), 0),
-        ] {
-            std::fs::write(&path, bytes).unwrap();
-            let result = SegmentUploader::read_segment_data_with_timeouts(
-                &path,
-                "segments/video/segment.m4s",
-                expected_size,
-                Duration::ZERO,
-                Duration::ZERO,
-            )
-            .await;
-            assert!(result.is_err(), "accepted {bytes:?} for {expected_size}");
-        }
-    }
-
-    #[tokio::test]
-    async fn read_segment_data_rejects_missing_and_unreadable_input() {
-        let dir = tempfile::tempdir().unwrap();
-        for path in [dir.path().join("missing.m4s"), dir.path().to_path_buf()] {
-            let result = SegmentUploader::read_segment_data_with_timeouts(
-                &path,
-                "segments/video/segment.m4s",
-                5,
-                Duration::ZERO,
-                Duration::ZERO,
-            )
-            .await;
-            assert!(result.is_err());
-        }
-    }
-
-    #[tokio::test]
-    async fn read_segment_data_polls_at_50ms_not_200ms() {
-        let dir = tempfile::tempdir().unwrap();
-        let path = dir.path().join("segment_fast.m4s");
-
-        let path_clone = path.clone();
-        tokio::spawn(async move {
-            tokio::time::sleep(Duration::from_millis(120)).await;
-            std::fs::write(&path_clone, b"fast poll data").unwrap();
-        });
-
-        let start = Instant::now();
-        let result = SegmentUploader::read_segment_data(
-            &path,
-            "segments/video/segment_fast.m4s",
-            b"fast poll data".len() as u64,
-        )
-        .await;
-        let elapsed = start.elapsed();
-
-        assert!(result.is_ok());
-        assert!(
-            elapsed < Duration::from_millis(300),
-            "50ms polling should detect file within ~170ms, got {elapsed:?}"
-        );
-    }
-
-    #[tokio::test]
-    async fn url_cache_returns_prefetched_url() {
-        let cache = PresignedUrlCache::new();
-        {
-            let mut urls = cache.urls.lock().await;
-            urls.insert(
-                "segments/video/segment_001.m4s".to_string(),
-                "https://s3.example.com/presigned/seg1".to_string(),
-            );
-            urls.insert(
-                "segments/video/segment_002.m4s".to_string(),
-                "https://s3.example.com/presigned/seg2".to_string(),
-            );
-        }
-
-        let mut urls = cache.urls.lock().await;
-        let url1 = urls.remove("segments/video/segment_001.m4s");
-        let url2 = urls.remove("segments/video/segment_002.m4s");
-        let url3 = urls.remove("segments/video/segment_003.m4s");
-        drop(urls);
-
-        assert_eq!(
-            url1.as_deref(),
-            Some("https://s3.example.com/presigned/seg1")
-        );
-        assert_eq!(
-            url2.as_deref(),
-            Some("https://s3.example.com/presigned/seg2")
-        );
-        assert!(url3.is_none(), "uncached key should return None");
-    }
-
-    #[tokio::test]
-    async fn url_cache_consumes_entry_on_use() {
-        let cache = PresignedUrlCache::new();
-        {
-            let mut urls = cache.urls.lock().await;
-            urls.insert(
-                "segments/video/init.mp4".to_string(),
-                "https://s3.example.com/presigned/init".to_string(),
-            );
-        }
-
-        let mut urls = cache.urls.lock().await;
-        let first = urls.remove("segments/video/init.mp4");
-        let second = urls.remove("segments/video/init.mp4");
-        drop(urls);
-
-        assert!(first.is_some(), "first access should hit cache");
-        assert!(second.is_none(), "second access should miss (consumed)");
-    }
-
-    #[tokio::test]
-    async fn semaphore_allows_six_concurrent_uploads() {
-        let semaphore = Arc::new(tokio::sync::Semaphore::new(6));
-        let active = Arc::new(AtomicU32::new(0));
-        let peak = Arc::new(AtomicU32::new(0));
-        let completed = Arc::new(AtomicU32::new(0));
-
-        let mut handles = Vec::new();
-        for _ in 0..12 {
-            let sem = semaphore.clone();
-            let active = active.clone();
-            let peak = peak.clone();
-            let completed = completed.clone();
-            handles.push(tokio::spawn(async move {
-                let _permit = sem.acquire().await.unwrap();
-                let current = active.fetch_add(1, Ordering::SeqCst) + 1;
-                peak.fetch_max(current, Ordering::SeqCst);
-                tokio::time::sleep(Duration::from_millis(50)).await;
-                active.fetch_sub(1, Ordering::SeqCst);
-                completed.fetch_add(1, Ordering::SeqCst);
-            }));
-        }
-
-        for h in handles {
-            h.await.unwrap();
-        }
-
-        assert_eq!(completed.load(Ordering::SeqCst), 12);
-        assert_eq!(
-            peak.load(Ordering::SeqCst),
-            6,
-            "peak concurrency should be 6"
-        );
-    }
-
-    #[tokio::test]
-    async fn file_read_runs_outside_semaphore() {
-        let semaphore = Arc::new(tokio::sync::Semaphore::new(2));
-        let dir = tempfile::tempdir().unwrap();
-
-        let read_start_times = Arc::new(tokio::sync::Mutex::new(Vec::::new()));
-        let overall_start = Instant::now();
-
-        let mut handles = Vec::new();
-        for i in 0..6u32 {
-            let path = dir.path().join(format!("seg_{i:03}.m4s"));
-            std::fs::write(&path, format!("data for segment {i}")).unwrap();
-
-            let sem = semaphore.clone();
-            let times = read_start_times.clone();
-            handles.push(tokio::spawn(async move {
-                {
-                    let mut t = times.lock().await;
-                    t.push(Instant::now());
-                }
-                let _data = tokio::fs::read(&path).await.unwrap();
-
-                let _permit = sem.acquire().await.unwrap();
-                tokio::time::sleep(Duration::from_millis(100)).await;
-            }));
-        }
-
-        for h in handles {
-            h.await.unwrap();
-        }
-
-        let times = read_start_times.lock().await;
-        let max_read_delay = times
-            .iter()
-            .map(|t| t.duration_since(overall_start))
-            .max()
-            .unwrap();
-
-        assert!(
-            max_read_delay < Duration::from_millis(50),
-            "all file reads should start nearly immediately (not blocked by semaphore), max delay was {max_read_delay:?}"
-        );
-    }
-
-    #[tokio::test]
-    async fn manifest_debounce_reduces_upload_count() {
-        let dirty = Arc::new(std::sync::atomic::AtomicBool::new(false));
-        let shutdown = Arc::new(std::sync::atomic::AtomicBool::new(false));
-        let notify = Arc::new(tokio::sync::Notify::new());
-        let upload_count = Arc::new(AtomicU32::new(0));
-
-        let manifest_handle = {
-            let dirty = dirty.clone();
-            let shutdown = shutdown.clone();
-            let notify = notify.clone();
-            let upload_count = upload_count.clone();
-            tokio::spawn(async move {
-                let mut interval = tokio::time::interval(Duration::from_millis(100));
-                interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
-                loop {
-                    tokio::select! {
-                        _ = interval.tick() => {}
-                        _ = notify.notified() => {}
-                    }
-                    if dirty.swap(false, std::sync::atomic::Ordering::AcqRel) {
-                        upload_count.fetch_add(1, Ordering::SeqCst);
-                    }
-                    if shutdown.load(std::sync::atomic::Ordering::Acquire) {
-                        if dirty.swap(false, std::sync::atomic::Ordering::AcqRel) {
-                            upload_count.fetch_add(1, Ordering::SeqCst);
-                        }
-                        break;
-                    }
-                }
-            })
-        };
-
-        for _ in 0..20 {
-            dirty.store(true, std::sync::atomic::Ordering::Release);
-            tokio::time::sleep(Duration::from_millis(10)).await;
-        }
-
-        tokio::time::sleep(Duration::from_millis(200)).await;
-
-        shutdown.store(true, std::sync::atomic::Ordering::Release);
-        dirty.store(true, std::sync::atomic::Ordering::Release);
-        notify.notify_one();
-        manifest_handle.await.unwrap();
-
-        let count = upload_count.load(Ordering::SeqCst);
-        assert!(
-            count < 10,
-            "debounce should batch 20 dirty flags into far fewer uploads, got {count}"
-        );
-        assert!(
-            count >= 1,
-            "should have uploaded manifest at least once, got {count}"
-        );
-    }
-
-    #[tokio::test]
-    async fn manifest_notify_wakes_immediately_on_shutdown() {
-        let dirty = Arc::new(std::sync::atomic::AtomicBool::new(false));
-        let shutdown = Arc::new(std::sync::atomic::AtomicBool::new(false));
-        let notify = Arc::new(tokio::sync::Notify::new());
-        let upload_count = Arc::new(AtomicU32::new(0));
-
-        let manifest_handle = {
-            let dirty = dirty.clone();
-            let shutdown = shutdown.clone();
-            let notify = notify.clone();
-            let upload_count = upload_count.clone();
-            tokio::spawn(async move {
-                let mut interval = tokio::time::interval(Duration::from_secs(60));
-                interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
-                loop {
-                    tokio::select! {
-                        _ = interval.tick() => {}
-                        _ = notify.notified() => {}
-                    }
-                    if dirty.swap(false, std::sync::atomic::Ordering::AcqRel) {
-                        upload_count.fetch_add(1, Ordering::SeqCst);
-                    }
-                    if shutdown.load(std::sync::atomic::Ordering::Acquire) {
-                        if dirty.swap(false, std::sync::atomic::Ordering::AcqRel) {
-                            upload_count.fetch_add(1, Ordering::SeqCst);
-                        }
-                        break;
-                    }
-                }
-            })
-        };
-
-        tokio::time::sleep(Duration::from_millis(50)).await;
-
-        let start = Instant::now();
-        shutdown.store(true, std::sync::atomic::Ordering::Release);
-        dirty.store(true, std::sync::atomic::Ordering::Release);
-        notify.notify_one();
-        manifest_handle.await.unwrap();
-        let elapsed = start.elapsed();
-
-        assert!(
-            elapsed < Duration::from_millis(100),
-            "notify should wake task immediately, not wait for interval. took {elapsed:?}"
-        );
-        assert_eq!(upload_count.load(Ordering::SeqCst), 1);
-    }
-
-    #[tokio::test]
-    async fn parallel_file_read_and_url_fetch() {
-        let dir = tempfile::tempdir().unwrap();
-        let path = dir.path().join("segment_001.m4s");
-        std::fs::write(&path, vec![0u8; 4096]).unwrap();
-
-        let start = Instant::now();
-        let (file_result, url_result) = tokio::join!(
-            async {
-                tokio::time::sleep(Duration::from_millis(100)).await;
-                tokio::fs::read(&path).await
-            },
-            async {
-                tokio::time::sleep(Duration::from_millis(100)).await;
-                Ok::("https://s3.example.com/presigned".to_string())
-            },
-        );
-        let elapsed = start.elapsed();
-
-        assert!(file_result.is_ok());
-        assert!(url_result.is_ok());
-        assert!(
-            elapsed < Duration::from_millis(180),
-            "parallel operations (100ms each) should complete in ~100ms, not ~200ms. took {elapsed:?}"
-        );
-    }
-
-    #[tokio::test]
-    async fn new_architecture_faster_than_old() {
-        let segment_count = 12u32;
-
-        let old_start = Instant::now();
-        {
-            let semaphore = Arc::new(tokio::sync::Semaphore::new(3));
-            let completed = Arc::new(AtomicU32::new(0));
-            let mut in_flight = futures::stream::FuturesUnordered::new();
-
-            for _ in 0..segment_count {
-                let permit = semaphore.clone().acquire_owned().await.unwrap();
-                let completed = completed.clone();
-                in_flight.push(tokio::spawn(async move {
-                    let _permit = permit;
-                    tokio::time::sleep(Duration::from_millis(10)).await;
-                    tokio::time::sleep(Duration::from_millis(50)).await;
-                    tokio::time::sleep(Duration::from_millis(30)).await;
-                    completed.fetch_add(1, Ordering::SeqCst);
-                }));
-            }
-
-            use futures::StreamExt;
-            while in_flight.next().await.is_some() {}
-        }
-        let old_duration = old_start.elapsed();
-
-        let new_start = Instant::now();
-        {
-            let semaphore = Arc::new(tokio::sync::Semaphore::new(6));
-            let completed = Arc::new(AtomicU32::new(0));
-            let manifest_uploads = Arc::new(AtomicU32::new(0));
-            let mut in_flight = futures::stream::FuturesUnordered::new();
-
-            for _ in 0..segment_count {
-                let semaphore = semaphore.clone();
-                let completed = completed.clone();
-                let manifest_uploads = manifest_uploads.clone();
-                in_flight.push(tokio::spawn(async move {
-                    tokio::time::sleep(Duration::from_millis(10)).await;
-
-                    let _permit = semaphore.acquire_owned().await.unwrap();
-                    tokio::time::sleep(Duration::from_millis(50)).await;
-                    drop(_permit);
-
-                    completed.fetch_add(1, Ordering::SeqCst);
-                    let _ = &manifest_uploads;
-                }));
-            }
-
-            use futures::StreamExt;
-            while in_flight.next().await.is_some() {}
-        }
-        let new_duration = new_start.elapsed();
-
-        assert!(
-            new_duration < old_duration,
-            "new architecture ({new_duration:?}) should be faster than old ({old_duration:?})"
-        );
-
-        let speedup =
-            old_duration.as_secs_f64() / new_duration.as_secs_f64().max(f64::MIN_POSITIVE);
-        assert!(
-            speedup > 1.5,
-            "expected at least 1.5x speedup, got {speedup:.2}x (old={old_duration:?}, new={new_duration:?})"
-        );
-    }
-
-    fn upload_state_with_video() -> SegmentUploadState {
-        let mut state = SegmentUploadState::new();
-        state.video_init_uploaded = true;
-        state.uploaded_video_segments.insert(1, 3.0);
-        state
-    }
-
-    #[tokio::test]
-    async fn failed_required_segment_prevents_all_completion_side_effects() {
-        use cap_enc_ffmpeg::segmented_stream::SegmentMediaType;
-
-        for (media_type, is_init) in [
-            (SegmentMediaType::Video, true),
-            (SegmentMediaType::Video, false),
-            (SegmentMediaType::Audio, true),
-            (SegmentMediaType::Audio, false),
-        ] {
-            let mut state = upload_state_with_video();
-            state.failed_segments.push(FailedSegmentInfo {
-                subpath: "required segment".to_string(),
-                file_path: PathBuf::from("required.m4s"),
-                is_init,
-                media_type,
-                index: 2,
-                duration: 3.0,
-                expected_size: 7,
-            });
-            let state = Mutex::new(state);
-            let published = AtomicUsize::new(0);
-            let result = publish_completed_segments(&state, |_| async {
-                published.fetch_add(1, Ordering::SeqCst);
-                Ok(())
-            })
-            .await;
-            assert!(result.is_err());
-            assert_eq!(published.load(Ordering::SeqCst), 0);
-            assert_eq!(state.lock().unwrap().failed_segments.len(), 1);
-        }
-    }
-
-    #[tokio::test]
-    async fn successful_required_segment_retry_restores_completion() {
-        let mut state = upload_state_with_video();
-        state.failed_segments.push(FailedSegmentInfo {
-            subpath: "segments/video/segment_002.m4s".to_string(),
-            file_path: PathBuf::from("segment_002.m4s"),
-            is_init: false,
-            media_type: cap_enc_ffmpeg::segmented_stream::SegmentMediaType::Video,
-            index: 2,
-            duration: 3.0,
-            expected_size: 7,
-        });
-        assert!(state.completed_manifest().is_err());
-        state.uploaded_video_segments.insert(2, 3.0);
-        state.failed_segments.clear();
-        let published = AtomicUsize::new(0);
-        let result = publish_completed_segments(&Mutex::new(state), |manifest| {
-            assert!(manifest.is_complete);
-            assert_eq!(manifest.video_segments.len(), 2);
-            published.fetch_add(1, Ordering::SeqCst);
-            async { Ok(()) }
-        })
-        .await;
-        assert!(result.is_ok());
-        assert_eq!(published.load(Ordering::SeqCst), 1);
-    }
-
-    #[tokio::test]
-    async fn missing_video_and_publication_errors_do_not_become_success() {
-        let result: Result<(), AuthedApiError> =
-            publish_completed_segments(&Mutex::new(SegmentUploadState::new()), |_| async {
-                panic!("an empty upload must not publish")
-            })
-            .await;
-        assert!(result.is_err());
-
-        let result: Result<(), AuthedApiError> =
-            publish_completed_segments(&Mutex::new(upload_state_with_video()), |_| async {
-                Err("injected manifest failure".into())
-            })
-            .await;
-        assert!(
-            result
-                .unwrap_err()
-                .to_string()
-                .contains("injected manifest failure")
-        );
-    }
-
-    #[tokio::test]
-    async fn panicked_and_cancelled_upload_workers_block_completion() {
-        for cancel in [false, true] {
-            let task: tokio::task::JoinHandle> = if cancel {
-                let task = tokio::spawn(std::future::pending());
-                task.abort();
-                task
-            } else {
-                tokio::spawn(async { panic!("injected segment worker panic") })
-            };
-            let mut state = upload_state_with_video();
-            state.record_task_result(task.await);
-            let result: Result<(), AuthedApiError> =
-                publish_completed_segments(&Mutex::new(state), |_| async {
-                    panic!("a failed worker must not publish")
-                })
-                .await;
-            assert!(result.is_err());
-        }
-    }
-
-    #[tokio::test]
-    async fn failed_upload_worker_does_not_skip_joining_other_owned_work() {
-        let state = Mutex::new(upload_state_with_video());
-        let mut tasks = SegmentUploadTasks::new();
-        let (entered_tx, entered_rx) = tokio::sync::oneshot::channel();
-        let (release_tx, release_rx) = tokio::sync::oneshot::channel();
-        tasks.push(tokio::spawn(async {
-            Err("injected upload failure".into())
-        }));
-        tasks.push(tokio::spawn(async move {
-            entered_tx.send(()).unwrap();
-            release_rx.await.unwrap();
-            Ok(())
-        }));
-        entered_rx.await.unwrap();
-        let mut drain = Box::pin(drain_segment_upload_tasks(&state, &mut tasks));
-        assert!(futures::poll!(&mut drain).is_pending());
-        release_tx.send(()).unwrap();
-        drain.await;
-        assert!(tasks.is_empty());
-        let result: Result<(), AuthedApiError> = publish_completed_segments(&state, |_| async {
-            panic!("a failed upload must not publish after its workers are joined")
-        })
-        .await;
-        assert!(result.is_err());
-    }
-
-    #[tokio::test]
-    async fn optional_prefetch_panic_does_not_block_successful_media_completion() {
-        let mut tasks = futures::stream::FuturesUnordered::new();
-        let (entered_tx, entered_rx) = tokio::sync::oneshot::channel();
-        tasks.push(tokio::spawn(async move {
-            entered_tx.send(()).unwrap();
-            panic!("injected optional URL prefetch panic");
-        }));
-        entered_rx.await.unwrap();
-        assert!(tasks.iter().all(tokio::task::JoinHandle::is_finished));
-        cancel_segment_prefetch_tasks(&mut tasks).await;
-        assert!(tasks.is_empty());
-
-        let published = AtomicUsize::new(0);
-        let result =
-            publish_completed_segments(&Mutex::new(upload_state_with_video()), |_| async {
-                published.fetch_add(1, Ordering::SeqCst);
-                Ok(())
-            })
-            .await;
-        assert!(result.is_ok());
-        assert_eq!(published.load(Ordering::SeqCst), 1);
-    }
-
-    #[tokio::test]
-    async fn upload_state_manifest_generation() {
-        let state = SegmentUploadState::new();
-        let manifest = state.to_manifest();
-        assert!(!manifest.is_complete);
-        assert!(!manifest.video_init_uploaded);
-        assert!(!manifest.audio_init_uploaded);
-        assert!(manifest.video_segments.is_empty());
-        assert!(manifest.audio_segments.is_empty());
-    }
-
-    #[tokio::test]
-    async fn upload_state_tracks_segments() {
-        let mut state = SegmentUploadState::new();
-        state.video_init_uploaded = true;
-        state.audio_init_uploaded = true;
-        state.uploaded_video_segments.insert(1, 3.0);
-        state.uploaded_video_segments.insert(2, 3.0);
-        state.uploaded_audio_segments.insert(1, 3.0);
-
-        let manifest = state.to_manifest();
-        assert!(manifest.video_init_uploaded);
-        assert!(manifest.audio_init_uploaded);
-        assert_eq!(manifest.video_segments.len(), 2);
-        assert_eq!(manifest.audio_segments.len(), 1);
-        assert!(!manifest.is_complete);
-
-        let complete = state.to_complete_manifest();
-        assert!(complete.is_complete);
-        assert_eq!(complete.video_segments.len(), 2);
-        assert!(complete.has_video_content());
-    }
-
-    #[tokio::test]
-    async fn upload_state_without_video_segments_has_no_video_content() {
-        let mut state = SegmentUploadState::new();
-        state.video_init_uploaded = true;
-        state.audio_init_uploaded = true;
-
-        let complete = state.to_complete_manifest();
-        assert!(complete.is_complete);
-        assert!(!complete.has_video_content());
-    }
-
-    #[tokio::test]
-    async fn end_to_end_pipeline_simulation() {
-        let segment_count = 10u32;
-        let semaphore = Arc::new(tokio::sync::Semaphore::new(6));
-        let state = Arc::new(Mutex::new(SegmentUploadState::new()));
-        let manifest_dirty = Arc::new(std::sync::atomic::AtomicBool::new(false));
-        let manifest_shutdown = Arc::new(std::sync::atomic::AtomicBool::new(false));
-        let manifest_notify = Arc::new(tokio::sync::Notify::new());
-        let manifest_upload_count = Arc::new(AtomicU32::new(0));
-
-        let manifest_handle = {
-            let dirty = manifest_dirty.clone();
-            let shutdown = manifest_shutdown.clone();
-            let notify = manifest_notify.clone();
-            let count = manifest_upload_count.clone();
-            tokio::spawn(async move {
-                let mut interval = tokio::time::interval(Duration::from_millis(100));
-                interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
-                loop {
-                    tokio::select! {
-                        _ = interval.tick() => {}
-                        _ = notify.notified() => {}
-                    }
-                    if dirty.swap(false, std::sync::atomic::Ordering::AcqRel) {
-                        tokio::time::sleep(Duration::from_millis(20)).await;
-                        count.fetch_add(1, Ordering::SeqCst);
-                    }
-                    if shutdown.load(std::sync::atomic::Ordering::Acquire) {
-                        if dirty.swap(false, std::sync::atomic::Ordering::AcqRel) {
-                            count.fetch_add(1, Ordering::SeqCst);
-                        }
-                        break;
-                    }
-                }
-            })
-        };
-
-        let dir = tempfile::tempdir().unwrap();
-        let start = Instant::now();
-        let mut handles = Vec::new();
-
-        for i in 0..segment_count {
-            let path = dir.path().join(format!("segment_{i:03}.m4s"));
-            std::fs::write(&path, vec![0u8; 1024]).unwrap();
-
-            let sem = semaphore.clone();
-            let st = state.clone();
-            let dirty = manifest_dirty.clone();
-            let mn = manifest_notify.clone();
-            handles.push(tokio::spawn(async move {
-                let (_data, _url) = tokio::join!(tokio::fs::read(&path), async {
-                    Ok::<_, ()>("https://example.com/presigned")
-                },);
-
-                let _permit = sem.acquire_owned().await.unwrap();
-                tokio::time::sleep(Duration::from_millis(50)).await;
-                drop(_permit);
-
-                {
-                    let mut s = st.lock().unwrap_or_else(|e| e.into_inner());
-                    s.uploaded_video_segments.insert(i, 3.0);
-                    s.total_bytes_uploaded += 1024;
-                }
-                dirty.store(true, std::sync::atomic::Ordering::Release);
-                mn.notify_one();
-            }));
-        }
-
-        for h in handles {
-            h.await.unwrap();
-        }
-
-        let upload_duration = start.elapsed();
-
-        let shutdown_start = Instant::now();
-        manifest_shutdown.store(true, std::sync::atomic::Ordering::Release);
-        manifest_dirty.store(true, std::sync::atomic::Ordering::Release);
-        manifest_notify.notify_one();
-        manifest_handle.await.unwrap();
-        let shutdown_duration = shutdown_start.elapsed();
-
-        let manifest_count = manifest_upload_count.load(Ordering::SeqCst);
-        let final_state = state.lock().unwrap();
-
-        assert_eq!(
-            final_state.uploaded_video_segments.len(),
-            segment_count as usize,
-            "all segments should be tracked"
-        );
-        assert_eq!(
-            final_state.total_bytes_uploaded,
-            segment_count as u64 * 1024
-        );
-        assert!(
-            manifest_count < segment_count,
-            "manifest uploads ({manifest_count}) should be fewer than segment count ({segment_count})"
-        );
-        assert!(
-            manifest_count >= 1,
-            "at least one manifest upload should happen"
-        );
-
-        let per_segment_ms = upload_duration.as_millis() as f64 / segment_count as f64;
-        assert!(
-            per_segment_ms < 40.0,
-            "with concurrency 6, per-segment time should be well under 50ms, got {per_segment_ms:.1}ms"
-        );
-
-        assert!(
-            shutdown_duration < Duration::from_millis(200),
-            "manifest shutdown should be near-instant via Notify, took {shutdown_duration:?}"
-        );
-    }
-}
-
-#[cfg(target_os = "linux")]
-pub(crate) mod strict_instant {
-    use super::*;
-    use cap_enc_ffmpeg::segmented_stream::{SegmentCompletedEvent, SegmentMediaType};
-    use futures::{FutureExt as _, stream::FuturesUnordered};
-    use std::{future::Future, panic::AssertUnwindSafe, sync::atomic::AtomicBool};
-
-    #[derive(Clone)]
-    pub struct Control(Arc);
-
-    struct ControlInner {
-        decision: tokio::sync::watch::Sender,
-        cleanup: tokio::sync::watch::Sender>,
-    }
-
-    pub struct Permission {
-        control: Control,
-        granted: bool,
-    }
-
-    impl Control {
-        pub fn new() -> (Self, Permission) {
-            let (decision, _) = tokio::sync::watch::channel(0);
-            let (cleanup, _) = tokio::sync::watch::channel(None);
-            let control = Self(Arc::new(ControlInner { decision, cleanup }));
-            (
-                control.clone(),
-                Permission {
-                    control,
-                    granted: false,
-                },
-            )
-        }
-
-        pub fn deny(&self) {
-            self.0.decision.send_replace(2);
-        }
-
-        pub fn check(&self) -> Result<(), AuthedApiError> {
-            if *self.0.decision.borrow() == 2 {
-                Err("Instant upload authorization revoked".to_string().into())
-            } else {
-                Ok(())
-            }
-        }
-
-        pub async fn step(&self, step: impl FnOnce() -> F) -> Result
-        where
-            F: Future>,
-        {
-            self.check()?;
-            let result = step().await;
-            self.check()?;
-            result
-        }
-
-        async fn permission(&self) -> Result<(), AuthedApiError> {
-            let mut decision = self.0.decision.subscribe();
-            loop {
-                let value = *decision.borrow_and_update();
-                match value {
-                    1 => return self.check(),
-                    2 => return Err("Instant completion was denied".to_string().into()),
-                    _ => decision
-                        .changed()
-                        .await
-                        .map_err(|_| "Instant authorization owner lost")?,
-                }
-            }
-        }
-
-        async fn cancelled(&self) {
-            let mut decision = self.0.decision.subscribe();
-            loop {
-                if *decision.borrow_and_update() == 2 {
-                    return;
-                }
-                if decision.changed().await.is_err() {
-                    return;
-                }
-            }
-        }
-
-        pub async fn joined(&self) -> bool {
-            let mut cleanup = self.0.cleanup.subscribe();
-            loop {
-                let state = *cleanup.borrow_and_update();
-                if let Some(joined) = state {
-                    return joined;
-                }
-                if cleanup.changed().await.is_err() {
-                    return false;
-                }
-            }
-        }
-    }
-
-    impl Permission {
-        pub fn grant(mut self) -> Result<(), AuthedApiError> {
-            let changed = self.control.0.decision.send_if_modified(|state| {
-                if *state != 0 {
-                    return false;
-                }
-                *state = 1;
-                true
-            });
-            if !changed {
-                return Err("Instant completion permission is no longer valid"
-                    .to_string()
-                    .into());
-            }
-            self.granted = true;
-            self.control.check()
-        }
-    }
-
-    impl Drop for Permission {
-        fn drop(&mut self) {
-            if !self.granted {
-                self.control.deny();
-            }
-        }
-    }
-
-    struct WorkerGuard(Control);
-    impl Drop for WorkerGuard {
-        fn drop(&mut self) {
-            let missing = self.0.0.cleanup.borrow().is_none();
-            if missing {
-                self.0.deny();
-                let _ = self.0.0.cleanup.send_replace(Some(false));
-            }
-        }
-    }
-
-    struct Bridge {
-        events: tokio::sync::mpsc::Receiver,
-        stop: Arc,
-        thread: Option>,
-    }
-
-    impl Bridge {
-        fn new(
-            source: std::sync::mpsc::Receiver,
-        ) -> Result {
-            let (sender, events) = tokio::sync::mpsc::channel(12);
-            let stop = Arc::new(AtomicBool::new(false));
-            let stop_thread = stop.clone();
-            let thread = std::thread::Builder::new()
-                .name("strict-instant-events".into())
-                .spawn(move || {
-                    while !stop_thread.load(Ordering::Acquire) {
-                        match source.recv_timeout(Duration::from_millis(100)) {
-                            Ok(event) => {
-                                if sender.blocking_send(event).is_err() {
-                                    break;
-                                }
-                            }
-                            Err(std::sync::mpsc::RecvTimeoutError::Timeout) => {}
-                            Err(std::sync::mpsc::RecvTimeoutError::Disconnected) => break,
-                        }
-                    }
-                })
-                .map_err(|error| format!("Starting owned Instant event bridge: {error}"))?;
-            Ok(Self {
-                events,
-                stop,
-                thread: Some(thread),
-            })
-        }
-
-        async fn finish(mut self) -> bool {
-            self.events.close();
-            self.stop.store(true, Ordering::Release);
-            let thread = self.thread.take().unwrap();
-            tokio::task::spawn_blocking(move || thread.join().is_ok())
-                .await
-                .unwrap_or(false)
-        }
-    }
-
-    impl Drop for Bridge {
-        fn drop(&mut self) {
-            self.events.close();
-            self.stop.store(true, Ordering::Release);
-            if let Some(thread) = self.thread.take() {
-                drop(tokio::task::spawn_blocking(move || thread.join()));
-            }
-        }
-    }
-
-    trait Transport: Send + Sync {
-        fn put(
-            &self,
-            path: &str,
-            bytes: Bytes,
-        ) -> impl Future> + Send;
-        fn complete(
-            &self,
-            manifest: &SegmentUploadManifest,
-            required_audio: bool,
-        ) -> impl Future> + Send;
-    }
-
-    struct LiveTransport<'a> {
-        app: &'a AppHandle,
-        video_id: &'a str,
-        control: &'a Control,
-        session: Option<&'a lifecycle::Session>,
-    }
-
-    impl Transport for LiveTransport<'_> {
-        async fn put(&self, path: &str, bytes: Bytes) -> Result<(), AuthedApiError> {
-            let mut failure = None;
-            for attempt in 0..3 {
-                if attempt > 0 {
-                    self.control
-                        .step(|| async {
-                            tokio::time::sleep(Duration::from_millis(500u64 << (attempt - 1)))
-                                .await;
-                            Ok(())
-                        })
-                        .await?;
-                }
-                let target = self
-                    .control
-                    .step(|| {
-                        api::upload_signed(
-                            self.app,
-                            PresignedS3PutRequest {
-                                video_id: self.video_id.into(),
-                                subpath: path.into(),
-                                method: PresignedS3PutRequestMethod::Put,
-                                meta: None,
-                            },
-                        )
-                    })
-                    .await?;
-                let size = bytes.len() as u64;
-                let mut request = self
-                    .app
-                    .state::()
-                    .put(&target.url)
-                    .header("Content-Length", size)
-                    .header("Content-Type", content_type_for_upload_subpath(path))
-                    .timeout(Duration::from_secs(5 * 60))
-                    .body(bytes.clone());
-                for (name, value) in target.headers {
-                    if !name.eq_ignore_ascii_case("content-length") {
-                        request = request.header(name, value);
-                    }
-                }
-                let result = self
-                    .control
-                    .step(|| async {
-                        let response =
-                            with_drive_content_range(request, &target.url, 0, size, size)
-                                .send()
-                                .await
-                                .map_err(AuthedApiError::from)?;
-                        if !response.status().is_success() {
-                            return Err(format!("Instant PUT failed: {}", response.status()).into());
-                        }
-                        Ok(())
-                    })
-                    .await;
-                match result {
-                    Ok(()) => return Ok(()),
-                    Err(error) => {
-                        let network = matches!(&error, AuthedApiError::Timeout)
-                            || matches!(&error, AuthedApiError::Request(error) if is_reqwest_network_error(error));
-                        failure = Some(error);
-                        self.control.check()?;
-                        if network && attempt < 2 {
-                            network_recovery(self.app, self.control).await?;
-                        }
-                    }
-                }
-                self.control.check()?;
-            }
-            Err(failure.unwrap())
-        }
-
-        async fn complete(
-            &self,
-            manifest: &SegmentUploadManifest,
-            required_audio: bool,
-        ) -> Result<(), AuthedApiError> {
-            let session = self.session.ok_or("Upload ownership is missing")?;
-            session.wait_ready().await?;
-            let expected = resume::collect_segment_events(&session.directory, required_audio)?;
-            validate_uploaded_segment_inventory(manifest, &expected)?;
-            let verification =
-                UploadVerification::segments(&serde_json::to_vec(manifest)?, required_audio);
-            self.control
-                .step(|| await_upload_verification(self.app, self.video_id, &verification, session))
-                .await?;
-            Ok(())
-        }
-    }
-
-    fn event_path(event: &SegmentCompletedEvent) -> String {
-        let media = match event.media_type {
-            SegmentMediaType::Video => "video",
-            SegmentMediaType::Audio => "audio",
-        };
-        if event.is_init {
-            format!("segments/{media}/init.mp4")
-        } else {
-            format!("segments/{media}/segment_{:03}.m4s", event.index)
-        }
-    }
-
-    async fn segment(
-        transport: &impl Transport,
-        control: &Control,
-        event: SegmentCompletedEvent,
-    ) -> Result {
-        control.check()?;
-        let path = event_path(&event);
-        let bytes = control
-            .step(|| SegmentUploader::read_segment_data(&event.path, &path, event.file_size))
-            .await?;
-        if bytes.is_empty() || (event.file_size > 0 && (bytes.len() as u64) < event.file_size) {
-            return Err(format!("Required Instant segment is incomplete: {path}").into());
-        }
-        control.step(|| transport.put(&path, bytes)).await?;
-        Ok(event)
-    }
-
-    async fn segments(
-        transport: &impl Transport,
-        control: &Control,
-        events: &mut tokio::sync::mpsc::Receiver,
-        required_audio: bool,
-    ) -> Result<(), AuthedApiError> {
-        let active_upload = ActiveUploadGuard::new(&ACTIVE_UPLOADS);
-        let mut uploads = FuturesUnordered::new();
-        let mut state = SegmentUploadState::new();
-        let mut closed = false;
-        let mut failure = None;
-        let mut manifest_at = Instant::now();
-        while !closed || !uploads.is_empty() {
-            tokio::select! {
-                _ = control.cancelled(), if failure.is_none() => { failure = Some("Instant upload cancelled".to_string().into()); closed = true; events.close(); }
-                event = events.recv(), if !closed && uploads.len() < 6 => {
-                    match event { Some(event) => uploads.push(segment(transport, control, event)), None => closed = true }
-                }
-                Some(result) = uploads.next(), if !uploads.is_empty() => {
-                    match result {
-                        Ok(event) => {
-                            match (event.is_init, event.media_type) {
-                                (true, SegmentMediaType::Video) => state.video_init_uploaded = true,
-                                (true, SegmentMediaType::Audio) => state.audio_init_uploaded = true,
-                                (false, SegmentMediaType::Video) => { let _ = state.uploaded_video_segments.insert(event.index, event.duration); }
-                                (false, SegmentMediaType::Audio) => { let _ = state.uploaded_audio_segments.insert(event.index, event.duration); }
-                            }
-                            if failure.is_none() && manifest_at.elapsed() >= Duration::from_secs(1) {
-                                let manifest = serde_json::to_vec(&state.to_manifest()).map_err(|error| error.to_string());
-                                let result = match manifest { Ok(bytes) => control.step(|| transport.put("segments/manifest.json", bytes.into())).await, Err(error) => Err(error.into()) };
-                                if let Err(error) = result { failure = Some(error); closed = true; events.close(); }
-                                manifest_at = Instant::now();
-                            }
-                        }
-                        Err(error) => { failure = Some(error); closed = true; events.close(); }
-                    }
-                }
-            }
-            if failure.is_some() {
-                control.deny();
-                closed = true;
-                events.close();
-            }
-        }
-        if let Some(error) = failure {
-            return Err(error);
-        }
-        control.permission().await?;
-        let manifest = state.to_complete_manifest();
-        if !manifest.has_video_content()
-            || (required_audio
-                && (!state.audio_init_uploaded || state.uploaded_audio_segments.is_empty()))
-        {
-            return Err("Required Instant media track is missing".to_string().into());
-        }
-        let bytes = serde_json::to_vec(&manifest).map_err(|error| error.to_string())?;
-        control
-            .step(|| transport.put("segments/manifest.json", bytes.into()))
-            .await?;
-        drop(active_upload);
-        control
-            .step(|| transport.complete(&manifest, required_audio))
-            .await
-    }
-
-    pub(crate) fn spawn(
-        app: AppHandle,
-        session: Arc,
-        video: VideoUploadInfo,
-        events: Option>,
-        control: Control,
-        required_audio: bool,
-    ) -> SegmentUploader {
-        let recording_dir = session.directory.clone();
-        session.bind_control(control.clone());
-        let worker_session = session.clone();
-        SegmentUploader {
-            session,
-            handle: spawn_actor(async move {
-                let _owner = WorkerGuard(control.clone());
-                let result = if let Err(error) = worker_session.acquire() {
-                    control.0.cleanup.send_replace(Some(true));
-                    Err(error)
-                } else {
-                    worker_session
-                        .run(crate::web_api::inherit_upload_context(
-                            worker_session.context(),
-                            async {
-                                if let Some(events) = events {
-                                    match Bridge::new(events) {
-                                        Ok(mut bridge) => {
-                                            let transport = LiveTransport {
-                                                app: &app,
-                                                video_id: &video.id,
-                                                control: &control,
-                                                session: Some(&worker_session),
-                                            };
-                                            let result = AssertUnwindSafe(segments(
-                                                &transport,
-                                                &control,
-                                                &mut bridge.events,
-                                                required_audio,
-                                            ))
-                                            .catch_unwind()
-                                            .await;
-                                            let joined = bridge.finish().await;
-                                            worker_session.wait_for_reads().await;
-                                            let _ = control
-                                                .0
-                                                .cleanup
-                                                .send_replace(Some(joined && result.is_ok()));
-                                            match result {
-                                                Ok(result) if joined => result,
-                                                _ => Err("Instant upload cleanup is unconfirmed"
-                                                    .to_string()
-                                                    .into()),
-                                            }
-                                        }
-                                        Err(error) => {
-                                            let _ = control.0.cleanup.send_replace(Some(true));
-                                            Err(error)
-                                        }
-                                    }
-                                } else {
-                                    let result = AssertUnwindSafe(multipart(
-                                        &app,
-                                        &recording_dir,
-                                        &video,
-                                        &control,
-                                        &worker_session,
-                                        required_audio,
-                                    ))
-                                    .catch_unwind()
-                                    .await;
-                                    worker_session.wait_for_reads().await;
-                                    let _ = control.0.cleanup.send_replace(Some(result.is_ok()));
-                                    result.unwrap_or_else(|_| {
-                                        Err("Instant multipart cleanup is unconfirmed"
-                                            .to_string()
-                                            .into())
-                                    })
-                                }
-                            },
-                        ))
-                        .await
-                };
-                if result.is_err() {
-                    control.deny();
-                }
-                result
-            }),
-        }
-    }
-
-    async fn network_recovery(app: &AppHandle, control: &Control) -> Result<(), AuthedApiError> {
-        let started = Instant::now();
-        let mut delay = CONNECTIVITY_PROBE_INITIAL_DELAY;
-        while started.elapsed() <= NETWORK_RECOVERY_TIMEOUT {
-            control
-                .step(|| async {
-                    tokio::time::sleep(delay).await;
-                    Ok(())
-                })
-                .await?;
-            if control
-                .step(|| async { Ok(probe_connectivity(app).await) })
-                .await?
-            {
-                return Ok(());
-            }
-            delay = (delay * 2).min(CONNECTIVITY_PROBE_MAX_DELAY);
-        }
-        Err("Instant upload network recovery timed out"
-            .to_string()
-            .into())
-    }
-
-    struct MultipartTarget<'a> {
-        app: &'a AppHandle,
-        video_id: &'a str,
-        upload_id: &'a str,
-        control: &'a Control,
-        use_md5: bool,
-    }
-
-    async fn part(
-        target: &MultipartTarget<'_>,
-        chunk: Chunk,
-    ) -> Result {
-        let size = chunk.chunk.len();
-        let md5_sum = target
-            .use_md5
-            .then(|| base64::encode(md5::compute(&chunk.chunk).0));
-        for attempt in 0..2 {
-            let url = target
-                .control
-                .step(|| {
-                    api::upload_multipart_presign_part(
-                        target.app,
-                        target.video_id,
-                        target.upload_id,
-                        chunk.part_number,
-                        md5_sum.as_deref(),
-                    )
-                })
-                .await?;
-            let mut request = target
-                .app
-                .state::()
-                .put(&url)
-                .header("Content-Length", size)
-                .timeout(Duration::from_secs(5 * 60))
-                .body(chunk.chunk.clone());
-            if let Some(md5_sum) = &md5_sum {
-                request = request.header("Content-MD5", md5_sum);
-            }
-            let request = with_drive_content_range(
-                request,
-                &url,
-                chunk.offset,
-                size as u64,
-                chunk.total_size,
-            );
-            let sent = target
-                .control
-                .step(|| async { Ok(request.send().await) })
-                .await?
-                .map_err(reqwest::Error::without_url);
-            let response = match sent {
-                Ok(response) => response,
-                Err(error) if attempt == 0 && is_reqwest_network_error(&error) => {
-                    network_recovery(target.app, target.control).await?;
-                    continue;
-                }
-                Err(error) => return Err(error.to_string().into()),
-            };
-            if !is_upload_response_accepted(
-                &url,
-                response.status(),
-                chunk.offset,
-                size as u64,
-                chunk.total_size,
-            ) {
-                return Err(format!("Instant multipart part failed: {}", response.status()).into());
-            }
-            let etag = response
-                .headers()
-                .get("ETag")
-                .and_then(|value| value.to_str().ok())
-                .map(|value| value.trim_matches('"').to_string())
-                .or_else(|| {
-                    is_google_drive_resumable_url(&url)
-                        .then(|| format!("drive-{}", chunk.part_number))
-                })
-                .ok_or_else(|| {
-                    format!(
-                        "Instant multipart part {} is missing ETag",
-                        chunk.part_number
-                    )
-                })?;
-            target.control.check()?;
-            let object_identity = completed_drive_upload_identity(
-                response,
-                is_google_drive_resumable_url(&url),
-                chunk.total_size,
-            )
-            .await;
-            return Ok(UploadedPart {
-                object_identity,
-                part_number: chunk.part_number,
-                etag,
-                size,
-                total_size: chunk.total_size,
-            });
-        }
-        Err("Instant multipart retries exhausted".to_string().into())
-    }
-
-    async fn multipart(
-        app: &AppHandle,
-        directory: &Path,
-        video: &VideoUploadInfo,
-        control: &Control,
-        session: &lifecycle::Session,
-        required_audio: bool,
-    ) -> Result<(), AuthedApiError> {
-        let active_upload = ActiveUploadGuard::new(&ACTIVE_UPLOADS);
-        let upload = control
-            .step(|| api::upload_multipart_initiate(app, &video.id, false))
-            .await?;
-        let concurrency = if is_google_drive_upload(upload.provider.as_deref(), &upload.upload_id) {
-            1
-        } else {
-            5
-        };
-        let target = MultipartTarget {
-            app,
-            video_id: &video.id,
-            upload_id: &upload.upload_id,
-            control,
-            use_md5: app.is_server_url_custom().await,
-        };
-        let path = directory.join("content/output.mp4");
-        let stream = strict_chunks(path.clone(), control.clone());
-        let parts = transfer_parts(&path, stream, &target, control, concurrency).await?;
-        let metadata = tokio::task::spawn_blocking(move || build_video_meta(&path))
-            .await
-            .map_err(|error| error.to_string())??;
-        session.wait_ready().await?;
-        let file_size = std::fs::metadata(directory.join("content/output.mp4"))
-            .map_err(|error| error.to_string())?
-            .len();
-        let duration = metadata.duration_in_secs;
-        let completed_identity = control
-            .step(|| {
-                api::upload_multipart_complete(
-                    app,
-                    &video.id,
-                    &upload.upload_id,
-                    &parts,
-                    Some(metadata),
-                    false,
-                )
-            })
-            .await?;
-        let object_identity =
-            if is_google_drive_upload(upload.provider.as_deref(), &upload.upload_id) {
-                parts
-                    .iter()
-                    .rev()
-                    .find_map(|part| part.object_identity.clone())
-            } else {
-                completed_identity
-            };
-        let verification = UploadVerification::mp4(
-            file_size,
-            duration,
-            required_audio,
-            object_identity.ok_or(
-                "Server did not return the uploaded object identity; local recording retained",
-            )?,
-        )?;
-        drop(active_upload);
-        control
-            .step(|| await_upload_verification(app, &video.id, &verification, session))
-            .await?;
-        Ok(())
-    }
-
-    fn strict_chunks(path: PathBuf, control: Control) -> impl Stream> {
-        try_stream! {
-            let started = Instant::now();
-            let file = loop {
-                control.check().map_err(io::Error::other)?;
-                let opened = open_upload_file(path.clone()).await;
-                control.check().map_err(io::Error::other)?;
-                match opened {
-                    Ok(file) => break file,
-                    Err(error) if started.elapsed() >= Duration::from_secs(20) => Err(error)?,
-                    Err(_) => tokio::time::sleep(Duration::from_millis(100)).await,
-                }
-            };
-            let mut offset = 0u64;
-            let mut number = 1;
-            let mut first_size = None;
-            loop {
-                control.check().map_err(io::Error::other)?;
-                let done = *control.0.decision.borrow() == 1;
-                let size = upload_file_size(file.clone()).await?;
-                control.check().map_err(io::Error::other)?;
-                let available = size.saturating_sub(offset);
-                if available >= MIN_CHUNK_SIZE || (done && available > 0) {
-                    let count = available.min(MAX_CHUNK_SIZE) as usize;
-                    let chunk = upload_file_chunk(file.clone(), offset, count).await?;
-                    control.check().map_err(io::Error::other)?;
-                    if offset == 0 { first_size = Some(count); }
-                    yield Chunk { total_size: size, part_number: number, offset, chunk };
-                    offset += count as u64; number += 1;
-                } else if done && available == 0 {
-                    if let Some(count) = first_size {
-                        let chunk = upload_file_chunk(file.clone(), 0, count).await?;
-                        control.check().map_err(io::Error::other)?;
-                        yield Chunk { total_size: size, part_number: 1, offset: 0, chunk };
-                    }
-                    break;
-                } else {
-                    tokio::select! { _ = tokio::time::sleep(Duration::from_millis(100)) => {}, _ = control.cancelled() => {} }
-                }
-            }
-        }
-    }
-
-    trait PartTransport: Send + Sync {
-        fn send(
-            &self,
-            chunk: Chunk,
-        ) -> impl Future> + Send;
-    }
-    impl PartTransport for MultipartTarget<'_> {
-        async fn send(&self, chunk: Chunk) -> Result {
-            part(self, chunk).await
-        }
-    }
-
-    async fn transfer_parts(
-        path: &Path,
-        stream: impl Stream>,
-        transport: &impl PartTransport,
-        control: &Control,
-        concurrency: usize,
-    ) -> Result, AuthedApiError> {
-        let mut chunks = Box::pin(stream);
-        let mut pending = futures::stream::FuturesOrdered::new();
-        let mut parts = Vec::new();
-        let mut failed = Vec::new();
-        let mut failure = None;
-        let mut closed = false;
-        while !closed || !pending.is_empty() {
-            tokio::select! {
-                _ = control.cancelled(), if failure.is_none() => { failure = Some("Instant multipart cancelled".to_string().into()); }
-                chunk = chunks.next(), if !closed && pending.len() < concurrency && failure.is_none() => {
-                    match chunk {
-                        Some(Ok(chunk)) => {
-                            let info = FailedChunkInfo { part_number: chunk.part_number, offset: chunk.offset, chunk_size: chunk.chunk.len(), total_size: chunk.total_size, error: String::new() };
-                            let target = transport;
-                            pending.push_back(async move { (info, control.step(|| target.send(chunk)).await) });
-                        }
-                        Some(Err(error)) => { failure = Some(error.to_string().into()); closed = true; }
-                        None => closed = true,
-                    }
-                }
-                Some((info, result)) = pending.next(), if !pending.is_empty() => {
-                    match result { Ok(part) => parts.push(part), Err(error) => { failed.push(info); if control.check().is_err() { failure = Some(error); } } }
-                }
-            }
-            if failure.is_some() {
-                control.deny();
-                if !closed {
-                    let _ = chunks.next().await;
-                }
-                closed = true;
-            }
-        }
-        drop(chunks);
-        if let Some(error) = failure {
-            return Err(error);
-        }
-        control.permission().await?;
-        for info in failed {
-            control.check()?;
-            let bytes = read_exact_upload_chunk(path, info.offset, info.chunk_size)
-                .await
-                .map_err(|error| error.to_string())?;
-            control.check()?;
-            parts.push(
-                control
-                    .step(|| {
-                        transport.send(Chunk {
-                            part_number: info.part_number,
-                            offset: info.offset,
-                            total_size: info.total_size,
-                            chunk: bytes,
-                        })
-                    })
-                    .await?,
-            );
-        }
-        let mut deduplicated = HashMap::new();
-        for part in parts {
-            let _ = deduplicated.insert(part.part_number, part);
-        }
-        let mut parts: Vec<_> = deduplicated.into_values().collect();
-        parts.sort_by_key(|part| part.part_number);
-        if parts.is_empty()
-            || parts
-                .iter()
-                .enumerate()
-                .any(|(index, part)| part.part_number as usize != index + 1 || part.size == 0)
-        {
-            return Err("Required Instant multipart data is incomplete"
-                .to_string()
-                .into());
-        }
-        Ok(parts)
-    }
-
-    pub async fn upload_thumbnail(
-        app: &AppHandle,
-        video_id: &str,
-        bytes: Vec,
-        control: &Control,
-    ) -> Result<(), AuthedApiError> {
-        let transport = LiveTransport {
-            app,
-            video_id,
-            control,
-            session: None,
-        };
-        control
-            .step(|| transport.put("screenshot/screen-capture.jpg", bytes.into()))
-            .await
-    }
-
-    #[cfg(test)]
-    mod tests {
-        use super::*;
-
-        #[derive(Default)]
-        struct FakeTransport {
-            calls: Mutex>,
-            fail_audio: AtomicBool,
-            delay_complete: AtomicBool,
-            entered: tokio::sync::Notify,
-            released: tokio::sync::Notify,
-            put_without_guard: AtomicBool,
-            complete_with_guard: AtomicBool,
-        }
-        impl Transport for FakeTransport {
-            async fn put(&self, path: &str, _: Bytes) -> Result<(), AuthedApiError> {
-                self.calls.lock().unwrap().push(path.into());
-                if !upload_session_active() {
-                    self.put_without_guard.store(true, Ordering::Release);
-                }
-                if self.fail_audio.load(Ordering::Acquire) && path.starts_with("segments/audio/") {
-                    return Err("required audio upload failed".into());
-                }
-                Ok(())
-            }
-            async fn complete(
-                &self,
-                _: &SegmentUploadManifest,
-                _: bool,
-            ) -> Result<(), AuthedApiError> {
-                self.calls.lock().unwrap().push("Complete".into());
-                if upload_session_active() {
-                    self.complete_with_guard.store(true, Ordering::Release);
-                }
-                if self.delay_complete.load(Ordering::Acquire) {
-                    self.entered.notify_one();
-                    self.released.notified().await;
-                }
-                Ok(())
-            }
-        }
-        fn serial() -> std::sync::MutexGuard<'static, ()> {
-            static SERIAL: std::sync::Mutex<()> = std::sync::Mutex::new(());
-            SERIAL.lock().unwrap_or_else(PoisonError::into_inner)
-        }
-        fn directory(tag: &str) -> PathBuf {
-            static NEXT: AtomicUsize = AtomicUsize::new(0);
-            let path = std::env::temp_dir().join(format!(
-                "cap-strict-upload-{tag}-{}-{}",
-                std::process::id(),
-                NEXT.fetch_add(1, Ordering::AcqRel)
-            ));
-            std::fs::create_dir_all(&path).unwrap();
-            path
-        }
-        fn event(path: PathBuf, audio: bool, init: bool) -> SegmentCompletedEvent {
-            SegmentCompletedEvent {
-                path,
-                index: u32::from(!init),
-                duration: if init { 0.0 } else { 1.0 },
-                file_size: 4,
-                is_init: init,
-                media_type: if audio {
-                    SegmentMediaType::Audio
-                } else {
-                    SegmentMediaType::Video
-                },
-            }
-        }
-        fn events(path: &Path, audio: bool) -> tokio::sync::mpsc::Receiver {
-            let file = path.join("synthetic-bytes");
-            std::fs::write(&file, b"test").unwrap();
-            let (sender, receiver) = tokio::sync::mpsc::channel(12);
-            for init in [true, false] {
-                sender.try_send(event(file.clone(), false, init)).unwrap();
-                if audio {
-                    sender.try_send(event(file.clone(), true, init)).unwrap();
-                }
-            }
-            receiver
-        }
-        #[tokio::test]
-        async fn strict_segment_eof_waits_for_owned_permission() {
-            let _serial = serial();
-            let dir = directory("eof");
-            let transport = FakeTransport::default();
-            let (control, permission) = Control::new();
-            let mut source = events(&dir, false);
-            let future = segments(&transport, &control, &mut source, false);
-            tokio::pin!(future);
-            assert!(
-                tokio::time::timeout(Duration::from_millis(10), &mut future)
-                    .await
-                    .is_err()
-            );
-            assert!(
-                !transport
-                    .calls
-                    .lock()
-                    .unwrap()
-                    .iter()
-                    .any(|value| value == "Complete")
-            );
-            permission.grant().unwrap();
-            future.await.unwrap();
-            assert!(
-                transport
-                    .calls
-                    .lock()
-                    .unwrap()
-                    .iter()
-                    .any(|value| value == "Complete")
-            );
-            std::fs::remove_dir_all(&dir).unwrap();
-        }
-        #[tokio::test]
-        async fn strict_required_audio_failure_or_absence_never_completes() {
-            let _serial = serial();
-            for present in [false, true] {
-                let dir = directory("audio");
-                let transport = FakeTransport::default();
-                transport.fail_audio.store(present, Ordering::Release);
-                let (control, permission) = Control::new();
-                permission.grant().unwrap();
-                let mut source = events(&dir, present);
-                assert!(
-                    segments(&transport, &control, &mut source, true)
-                        .await
-                        .is_err()
-                );
-                assert!(
-                    !transport
-                        .calls
-                        .lock()
-                        .unwrap()
-                        .iter()
-                        .any(|value| value == "Complete")
-                );
-                std::fs::remove_dir_all(&dir).unwrap();
-            }
-        }
-        #[tokio::test]
-        async fn strict_complete_inflight_revocation_rejects_late_success() {
-            let _serial = serial();
-            let dir = directory("late-complete");
-            let transport = FakeTransport::default();
-            transport.delay_complete.store(true, Ordering::Release);
-            let (control, permission) = Control::new();
-            permission.grant().unwrap();
-            let mut source = events(&dir, false);
-            let future = segments(&transport, &control, &mut source, false);
-            tokio::pin!(future);
-            tokio::select! { _ = transport.entered.notified() => {}, result = &mut future => panic!("Unexpected completion: {result:?}") }
-            control.deny();
-            transport.released.notify_one();
-            assert!(future.await.is_err());
-            assert_eq!(
-                transport
-                    .calls
-                    .lock()
-                    .unwrap()
-                    .iter()
-                    .filter(|value| *value == "Complete")
-                    .count(),
-                1
-            );
-            std::fs::remove_dir_all(&dir).unwrap();
-        }
-        #[tokio::test]
-        async fn strict_exit_guard_covers_transfer_but_not_verification() {
-            let _serial = serial();
-            let dir = directory("exit-guard");
-            let transport = FakeTransport::default();
-            transport.delay_complete.store(true, Ordering::Release);
-            let (control, permission) = Control::new();
-            permission.grant().unwrap();
-            let mut source = events(&dir, false);
-            assert!(!upload_session_active());
-            let future = segments(&transport, &control, &mut source, false);
-            tokio::pin!(future);
-            tokio::select! { _ = transport.entered.notified() => {}, result = &mut future => panic!("Unexpected completion: {result:?}") }
-            assert!(!transport.put_without_guard.load(Ordering::Acquire));
-            assert!(!transport.complete_with_guard.load(Ordering::Acquire));
-            assert!(!upload_session_active());
-            transport.released.notify_one();
-            future.await.unwrap();
-            assert!(!upload_session_active());
-            std::fs::remove_dir_all(&dir).unwrap();
-        }
-        #[tokio::test]
-        async fn strict_permission_drop_and_old_generation_cannot_complete() {
-            let _serial = serial();
-            let dir = directory("owner-drop");
-            let transport = FakeTransport::default();
-            let (old, old_permission) = Control::new();
-            old.deny();
-            assert!(old_permission.grant().is_err());
-            let (control, permission) = Control::new();
-            let mut source = events(&dir, false);
-            let future = segments(&transport, &control, &mut source, false);
-            tokio::pin!(future);
-            assert!(
-                tokio::time::timeout(Duration::from_millis(10), &mut future)
-                    .await
-                    .is_err()
-            );
-            drop(permission);
-            assert!(future.await.is_err());
-            assert!(
-                !transport
-                    .calls
-                    .lock()
-                    .unwrap()
-                    .iter()
-                    .any(|value| value == "Complete")
-            );
-            std::fs::remove_dir_all(&dir).unwrap();
-        }
-        #[tokio::test]
-        async fn owned_bridge_closes_full_queue_before_actual_thread_join() {
-            let (sender, receiver) = std::sync::mpsc::channel();
-            for _ in 0..30 {
-                sender
-                    .send(event(PathBuf::from("unused"), false, false))
-                    .unwrap();
-            }
-            let bridge = Bridge::new(receiver).unwrap();
-            tokio::time::sleep(Duration::from_millis(10)).await;
-            assert!(
-                tokio::time::timeout(Duration::from_secs(1), bridge.finish())
-                    .await
-                    .unwrap()
-            );
-            assert!(
-                sender
-                    .send(event(PathBuf::from("unused"), false, false))
-                    .is_err()
-            );
-        }
-        #[derive(Default)]
-        struct FakeParts {
-            entered: tokio::sync::Notify,
-            released: tokio::sync::Notify,
-            delayed: AtomicBool,
-            calls: AtomicUsize,
-        }
-        impl PartTransport for FakeParts {
-            async fn send(&self, chunk: Chunk) -> Result {
-                self.calls.fetch_add(1, Ordering::AcqRel);
-                if self.delayed.load(Ordering::Acquire) {
-                    self.entered.notify_one();
-                    self.released.notified().await;
-                }
-                Ok(UploadedPart {
-                    object_identity: None,
-                    part_number: chunk.part_number,
-                    etag: "synthetic".into(),
-                    size: chunk.chunk.len(),
-                    total_size: chunk.total_size,
-                })
-            }
-        }
-        fn chunks() -> impl Stream> {
-            stream::iter([Ok(Chunk {
-                total_size: 4,
-                part_number: 1,
-                offset: 0,
-                chunk: Bytes::from_static(b"test"),
-            })])
-        }
-        #[tokio::test]
-        async fn strict_multipart_eof_without_permission_does_not_finalize() {
-            let transport = FakeParts::default();
-            let (control, permission) = Control::new();
-            let future = transfer_parts(Path::new("unused"), chunks(), &transport, &control, 5);
-            tokio::pin!(future);
-            assert!(
-                tokio::time::timeout(Duration::from_millis(10), &mut future)
-                    .await
-                    .is_err()
-            );
-            permission.grant().unwrap();
-            assert_eq!(future.await.unwrap().len(), 1);
-        }
-        #[tokio::test]
-        async fn strict_multipart_cancel_drains_inflight_part_before_error() {
-            let transport = FakeParts::default();
-            transport.delayed.store(true, Ordering::Release);
-            let (control, permission) = Control::new();
-            permission.grant().unwrap();
-            let future = transfer_parts(Path::new("unused"), chunks(), &transport, &control, 5);
-            tokio::pin!(future);
-            tokio::select! { _ = transport.entered.notified() => {}, result = &mut future => panic!("Unexpected result: {result:?}") }
-            control.deny();
-            assert!(
-                tokio::time::timeout(Duration::from_millis(10), &mut future)
-                    .await
-                    .is_err()
-            );
-            transport.released.notify_one();
-            assert!(future.await.is_err());
-            assert_eq!(transport.calls.load(Ordering::Acquire), 1);
-        }
-        #[tokio::test]
-        async fn strict_request_boundary_stops_following_request_after_late_response() {
-            let (control, permission) = Control::new();
-            let called = AtomicBool::new(false);
-            let (reply, response) = tokio::sync::oneshot::channel();
-            let future = async {
-                control
-                    .step(|| async {
-                        response.await.unwrap();
-                        Ok(())
-                    })
-                    .await?;
-                control
-                    .step(|| async {
-                        called.store(true, Ordering::Release);
-                        Ok(())
-                    })
-                    .await
-            };
-            tokio::pin!(future);
-            assert!(
-                tokio::time::timeout(Duration::from_millis(1), &mut future)
-                    .await
-                    .is_err()
-            );
-            drop(permission);
-            reply.send(()).unwrap();
-            assert!(future.await.is_err());
-            assert!(!called.load(Ordering::Acquire));
-        }
-        #[tokio::test]
-        async fn lost_upload_worker_marks_cleanup_unconfirmed_and_wakes_waiter() {
-            let (control, _permission) = Control::new();
-            let worker = control.clone();
-            let task = tokio::spawn(async move {
-                let _guard = WorkerGuard(worker);
-                panic!("lost uploader");
-            });
-            assert!(task.await.is_err());
-            assert!(
-                !tokio::time::timeout(Duration::from_secs(1), control.joined())
-                    .await
-                    .unwrap()
-            );
-            assert!(control.check().is_err());
-        }
-        #[tokio::test]
-        async fn strict_reader_waits_for_permission_then_rewrites_first_part() {
-            let dir = directory("reader");
-            let path = dir.join("bytes");
-            std::fs::write(&path, b"test").unwrap();
-            let (control, permission) = Control::new();
-            let mut stream = Box::pin(strict_chunks(path, control));
-            assert!(
-                tokio::time::timeout(Duration::from_millis(10), stream.next())
-                    .await
-                    .is_err()
-            );
-            permission.grant().unwrap();
-            let first = stream.next().await.unwrap().unwrap();
-            assert_eq!(first.part_number, 1);
-            assert_eq!(first.chunk.as_ref(), b"test");
-            let rewritten = stream.next().await.unwrap().unwrap();
-            assert_eq!(rewritten.part_number, 1);
-            assert_eq!(rewritten.chunk.as_ref(), b"test");
-            assert!(stream.next().await.is_none());
-            drop(stream);
-            std::fs::remove_dir_all(dir).unwrap();
-        }
-        #[tokio::test]
-        async fn strict_reader_cancellation_is_error_not_successful_eof() {
-            let dir = directory("cancel-reader");
-            let path = dir.join("bytes");
-            std::fs::write(&path, b"test").unwrap();
-            let (control, permission) = Control::new();
-            let mut stream = Box::pin(strict_chunks(path, control));
-            assert!(
-                tokio::time::timeout(Duration::from_millis(10), stream.next())
-                    .await
-                    .is_err()
-            );
-            drop(permission);
-            assert!(
-                tokio::time::timeout(Duration::from_secs(1), stream.next())
-                    .await
-                    .unwrap()
-                    .unwrap()
-                    .is_err()
-            );
-            drop(stream);
-            std::fs::remove_dir_all(dir).unwrap();
-        }
-        #[tokio::test]
-        async fn strict_multipart_completion_step_retains_optional_success_errors_and_late_revocation()
-         {
-            let (control, permission) = Control::new();
-            permission.grant().unwrap();
-            let result: Result, AuthedApiError> = control
-                .step(|| async { Ok(Some("synthetic-location".to_string())) })
-                .await;
-            assert_eq!(result.unwrap().as_deref(), Some("synthetic-location"));
-            assert!(
-                control
-                    .step(|| async {
-                        Err::, _>("required completion failed".into())
-                    })
-                    .await
-                    .is_err()
-            );
-            let (release, released) = tokio::sync::oneshot::channel();
-            let future = control.step(|| async {
-                released.await.unwrap();
-                Ok(Some("late-location".to_string()))
-            });
-            tokio::pin!(future);
-            assert!(
-                tokio::time::timeout(Duration::from_millis(10), &mut future)
-                    .await
-                    .is_err()
-            );
-            control.deny();
-            release.send(()).unwrap();
-            assert!(future.await.is_err());
-        }
-    }
-}
diff --git a/apps/desktop/src-tauri/src/upload/lifecycle.rs b/apps/desktop/src-tauri/src/upload/lifecycle.rs
deleted file mode 100644
index b6f5927dc64..00000000000
--- a/apps/desktop/src-tauri/src/upload/lifecycle.rs
+++ /dev/null
@@ -1,1725 +0,0 @@
-use super::*;
-use crate::{auth::AuthStore, web_api::UploadRequestContext};
-use futures::FutureExt;
-use std::{io::Write, sync::atomic::AtomicBool};
-
-const FILE_NAME: &str = "tauri-upload.json";
-
-#[derive(Clone, Serialize, Deserialize)]
-#[serde(deny_unknown_fields)]
-struct Intent {
-    version: u32,
-    video_id: String,
-    server_url: String,
-    owner_id: Option,
-    required_audio: Option,
-    local_ready: bool,
-    cancelled: bool,
-    preserve_local: bool,
-    failures: u32,
-    #[serde(default)]
-    needs_authentication: bool,
-    retry_at: Option,
-    error: Option,
-    verification: Option,
-    receipt: Option,
-}
-
-fn read(directory: &Path) -> Result, AuthedApiError> {
-    let path = directory.join(FILE_NAME);
-    let metadata = match path.symlink_metadata() {
-        Ok(metadata) => metadata,
-        Err(error) if error.kind() == io::ErrorKind::NotFound => return Ok(None),
-        Err(error) => return Err(error.to_string().into()),
-    };
-    #[cfg(windows)]
-    {
-        use std::os::windows::fs::MetadataExt;
-        if metadata.file_attributes() & 0x400 != 0 {
-            return Err("Upload intent is a reparse point".into());
-        }
-    }
-    if metadata.file_type().is_symlink() || !metadata.is_file() || metadata.len() > 65536 {
-        return Err("Invalid recording upload intent".into());
-    }
-    let intent: Intent =
-        serde_json::from_slice(&std::fs::read(path).map_err(|error| error.to_string())?)?;
-    if intent.version != 1 || intent.video_id.is_empty() || intent.server_url.is_empty() {
-        return Err("Unsupported recording upload intent".into());
-    }
-    Ok(Some(intent))
-}
-
-fn write(directory: &Path, intent: &Intent) -> Result<(), AuthedApiError> {
-    read(directory)?;
-    let bytes = serde_json::to_vec_pretty(intent)?;
-    let temporary = directory.join(format!(".tauri-upload-{}.tmp", uuid::Uuid::new_v4()));
-    let result = (|| {
-        let mut file = std::fs::OpenOptions::new()
-            .write(true)
-            .create_new(true)
-            .open(&temporary)?;
-        file.write_all(&bytes)?;
-        file.sync_all()?;
-        drop(file);
-        std::fs::rename(&temporary, directory.join(FILE_NAME))?;
-        #[cfg(unix)]
-        std::fs::File::open(directory)?.sync_all()?;
-        Ok::<_, io::Error>(())
-    })();
-    if result.is_err() {
-        let _ = std::fs::remove_file(temporary);
-    }
-    result.map_err(|error| format!("Could not save upload intent: {error}").into())
-}
-
-pub(crate) async fn prepare(
-    app: &AppHandle,
-    directory: &Path,
-    video_id: &str,
-    required_audio: bool,
-) -> Result, AuthedApiError> {
-    let server_url = app.make_app_url("").await.trim_end_matches('/').to_string();
-    let owner_id = AuthStore::get(app)
-        .map_err(AuthedApiError::AuthStore)?
-        .and_then(|auth| auth.user_id);
-    let context = UploadRequestContext::new(
-        server_url.clone(),
-        owner_id
-            .clone()
-            .ok_or(AuthedApiError::InvalidAuthentication)?,
-    )?;
-    context.check(app).await?;
-    let lock = acquire_upload_lock(directory)?;
-    if read(directory)?.is_some() {
-        return Err("Recording already has an upload identity".into());
-    }
-    write(
-        directory,
-        &Intent {
-            version: 1,
-            video_id: video_id.into(),
-            server_url,
-            owner_id,
-            required_audio: Some(required_audio),
-            local_ready: false,
-            cancelled: false,
-            preserve_local: false,
-            failures: 0,
-            needs_authentication: false,
-            retry_at: None,
-            error: None,
-            verification: None,
-            receipt: None,
-        },
-    )?;
-    let session = Session::new(lock.project_path().to_path_buf(), video_id.to_string());
-    session.adopt(lock)?;
-    Ok(session)
-}
-
-#[derive(Default)]
-struct ReadTracker {
-    active: AtomicUsize,
-    changed: tokio::sync::Notify,
-}
-
-pub(crate) struct ReadGuard(Arc);
-
-impl Drop for ReadGuard {
-    fn drop(&mut self) {
-        self.0.active.fetch_sub(1, Ordering::AcqRel);
-        self.0.changed.notify_one();
-    }
-}
-
-#[derive(Clone)]
-pub(crate) struct UploadScope {
-    cancelled: tokio::sync::watch::Receiver,
-    reads: Arc,
-}
-
-tokio::task_local! {
-    static UPLOAD_SCOPE: UploadScope;
-}
-
-impl UploadScope {
-    pub(crate) fn current() -> Option {
-        UPLOAD_SCOPE.try_with(Clone::clone).ok()
-    }
-
-    pub(crate) async fn bind(self, future: F) -> F::Output {
-        UPLOAD_SCOPE.scope(self, future).await
-    }
-
-    pub(crate) fn read_guard(&self) -> ReadGuard {
-        self.reads.active.fetch_add(1, Ordering::AcqRel);
-        ReadGuard(self.reads.clone())
-    }
-
-    async fn cancelled(&self) {
-        let mut cancelled = self.cancelled.clone();
-        while !*cancelled.borrow_and_update() {
-            if cancelled.changed().await.is_err() {
-                break;
-            }
-        }
-    }
-
-    fn check(&self) -> Result<(), AuthedApiError> {
-        if *self.cancelled.borrow() {
-            Err("Recording upload cancelled; local files retained".into())
-        } else {
-            Ok(())
-        }
-    }
-}
-
-pub(crate) async fn cancellable(
-    future: F,
-) -> Result {
-    if let Some(scope) = UploadScope::current() {
-        scope.check()?;
-        let result = tokio::select! {
-            result = future => result,
-            _ = scope.cancelled() => return Err("Recording upload cancelled; local files retained".into()),
-        };
-        scope.check()?;
-        Ok(result)
-    } else {
-        Ok(future.await)
-    }
-}
-
-pub(crate) async fn file_io(
-    operation: impl FnOnce() -> io::Result + Send + 'static,
-) -> io::Result {
-    let scope = UploadScope::current();
-    if let Some(scope) = &scope {
-        scope.check().map_err(io::Error::other)?;
-    }
-    let guard = scope.map(|scope| scope.read_guard());
-    let task = tokio::task::spawn_blocking(move || {
-        let _guard = guard;
-        operation()
-    });
-    cancellable(task)
-        .await
-        .map_err(io::Error::other)?
-        .map_err(io::Error::other)?
-}
-
-pub(crate) struct Session {
-    pub(crate) directory: PathBuf,
-    video_id: String,
-    ownership: Mutex>,
-    request_context: Mutex>,
-    cancelled: tokio::sync::watch::Sender,
-    ready: tokio::sync::Notify,
-    terminal: tokio::sync::watch::Sender>>,
-    verified: Mutex>,
-    ledger: Mutex<()>,
-    reads: Arc,
-    #[cfg(target_os = "linux")]
-    strict_control: Mutex>,
-}
-
-impl Session {
-    pub(crate) fn new(directory: PathBuf, video_id: String) -> Arc {
-        Arc::new(Self {
-            directory,
-            video_id,
-            ownership: Mutex::new(None),
-            request_context: Mutex::new(None),
-            cancelled: tokio::sync::watch::channel(false).0,
-            ready: tokio::sync::Notify::new(),
-            terminal: tokio::sync::watch::channel(None).0,
-            verified: Mutex::new(None),
-            ledger: Mutex::new(()),
-            reads: Arc::new(ReadTracker::default()),
-            #[cfg(target_os = "linux")]
-            strict_control: Mutex::new(None),
-        })
-    }
-
-    pub(crate) async fn run(&self, future: F) -> F::Output {
-        let scope = UploadScope {
-            cancelled: self.cancelled.subscribe(),
-            reads: self.reads.clone(),
-        };
-        let result = std::panic::AssertUnwindSafe(scope.bind(future))
-            .catch_unwind()
-            .await;
-        self.wait_for_reads().await;
-        match result {
-            Ok(result) => result,
-            Err(panic) => std::panic::resume_unwind(panic),
-        }
-    }
-
-    pub(crate) async fn wait_for_reads(&self) {
-        while self.reads.active.load(Ordering::Acquire) != 0 {
-            tokio::select! { _ = self.reads.changed.notified() => {}, _ = tokio::time::sleep(Duration::from_millis(10)) => {} }
-        }
-    }
-
-    pub(crate) fn adopt(&self, lock: UploadLock) -> Result<(), AuthedApiError> {
-        if self
-            .directory
-            .canonicalize()
-            .map_err(|error| error.to_string())?
-            != lock.project_path()
-        {
-            return Err("Upload ownership path changed".into());
-        }
-        *self
-            .ownership
-            .lock()
-            .unwrap_or_else(PoisonError::into_inner) = Some(lock);
-        self.load_context()?;
-        self.check()
-    }
-
-    fn load_context(&self) -> Result<(), AuthedApiError> {
-        if let Some(intent) = read(&self.directory)? {
-            if intent.video_id != self.video_id || intent.cancelled {
-                return Err("Recording upload identity changed or was cancelled".into());
-            }
-            let context = UploadRequestContext::new(
-                intent.server_url,
-                intent
-                    .owner_id
-                    .ok_or(AuthedApiError::InvalidAuthentication)?,
-            )?;
-            *self
-                .request_context
-                .lock()
-                .unwrap_or_else(PoisonError::into_inner) = Some(context);
-        }
-        Ok(())
-    }
-
-    pub(crate) fn cached_verification(&self) -> Result, AuthedApiError> {
-        let verification = read(&self.directory)?.and_then(|intent| intent.verification);
-        if verification
-            .as_ref()
-            .is_some_and(UploadVerification::requires_reupload)
-        {
-            self.clear_verification()?;
-            return Ok(None);
-        }
-        if let Some(verification) = &verification
-            && let Err(error) = verify_local_artifact(&self.directory, verification)
-        {
-            self.clear_verification()?;
-            return Err(error);
-        }
-        Ok(verification)
-    }
-
-    pub(crate) fn acquire(&self) -> Result<(), AuthedApiError> {
-        let mut ownership = self
-            .ownership
-            .lock()
-            .unwrap_or_else(PoisonError::into_inner);
-        if ownership.is_some() {
-            return self.check();
-        }
-        let lock = acquire_upload_lock(&self.directory)?;
-        let meta =
-            RecordingMeta::load_for_project(&self.directory).map_err(|error| error.to_string())?;
-        if let Some(id) = upload_video_id(&meta.upload)
-            && id != self.video_id
-        {
-            return Err("Recording upload identity changed".into());
-        }
-        self.load_context()?;
-        *ownership = Some(lock);
-        self.check()
-    }
-
-    pub(crate) fn context(&self) -> Option {
-        self.request_context
-            .lock()
-            .unwrap_or_else(PoisonError::into_inner)
-            .clone()
-    }
-
-    pub(crate) fn check(&self) -> Result<(), AuthedApiError> {
-        if *self.cancelled.borrow() {
-            Err("Recording upload cancelled; local files retained".into())
-        } else {
-            Ok(())
-        }
-    }
-
-    #[cfg(target_os = "linux")]
-    pub(crate) fn bind_control(&self, control: super::strict_instant::Control) {
-        *self
-            .strict_control
-            .lock()
-            .unwrap_or_else(PoisonError::into_inner) = Some(control);
-    }
-
-    pub(crate) fn cancel(&self) {
-        #[cfg(target_os = "linux")]
-        if let Some(control) = self
-            .strict_control
-            .lock()
-            .unwrap_or_else(PoisonError::into_inner)
-            .as_ref()
-        {
-            control.deny();
-        }
-        self.cancelled.send_replace(true);
-        self.ready.notify_one();
-    }
-
-    pub(crate) async fn cancelled(&self) {
-        let mut cancelled = self.cancelled.subscribe();
-        while !*cancelled.borrow_and_update() {
-            if cancelled.changed().await.is_err() {
-                break;
-            }
-        }
-    }
-
-    pub(crate) fn persist_upload(&self, upload: UploadMeta) -> Result<(), AuthedApiError> {
-        let _ledger = self.ledger.lock().unwrap_or_else(PoisonError::into_inner);
-        self.check()?;
-        let mut meta =
-            RecordingMeta::load_for_project(&self.directory).map_err(|error| error.to_string())?;
-        meta.upload = Some(upload);
-        meta.save_for_project().map_err(|error| error.to_string())?;
-        Ok(())
-    }
-
-    pub(crate) fn persist_local_complete(
-        &self,
-        recording: cap_project::InstantRecordingMeta,
-        sharing: cap_project::SharingMeta,
-    ) -> Result<(), AuthedApiError> {
-        let _ledger = self.ledger.lock().unwrap_or_else(PoisonError::into_inner);
-        self.check()?;
-        let mut meta =
-            RecordingMeta::load_for_project(&self.directory).map_err(|error| error.to_string())?;
-        meta.inner = cap_project::RecordingMetaInner::Instant(recording);
-        meta.sharing = Some(sharing);
-        meta.save_for_project().map_err(|error| error.to_string())?;
-        Ok(())
-    }
-
-    pub(crate) fn mark_ready(&self, preserve_local: bool) -> Result<(), AuthedApiError> {
-        self.acquire()?;
-        let _ledger = self.ledger.lock().unwrap_or_else(PoisonError::into_inner);
-        if let Some(mut intent) = read(&self.directory)? {
-            intent.local_ready = true;
-            intent.preserve_local |= preserve_local;
-            intent.retry_at = None;
-            write(&self.directory, &intent)?;
-        }
-        self.ready.notify_one();
-        Ok(())
-    }
-
-    pub(crate) async fn wait_ready(&self) -> Result<(), AuthedApiError> {
-        loop {
-            self.check()?;
-            match read(&self.directory)? {
-                Some(intent) if intent.cancelled => {
-                    return Err("Recording upload was cancelled".into());
-                }
-                Some(intent) if !intent.local_ready => {}
-                _ => return Ok(()),
-            }
-            tokio::select! { _ = self.ready.notified() => {}, _ = self.cancelled() => {}, _ = tokio::time::sleep(Duration::from_millis(100)) => {} }
-        }
-    }
-
-    pub(crate) fn record_failure(&self, error: &AuthedApiError) {
-        let _ledger = self.ledger.lock().unwrap_or_else(PoisonError::into_inner);
-        let result = (|| {
-            let Some(mut intent) = read(&self.directory)? else {
-                return Ok::<_, AuthedApiError>(());
-            };
-            intent.needs_authentication = matches!(error, AuthedApiError::InvalidAuthentication);
-            if !matches!(
-                error,
-                AuthedApiError::InvalidAuthentication | AuthedApiError::VerificationPending
-            ) {
-                intent.failures = intent.failures.saturating_add(1);
-            }
-            intent.retry_at = (intent.failures < 5).then(|| {
-                chrono::Utc::now()
-                    .timestamp()
-                    .saturating_add(30 * (1_i64 << intent.failures.min(5)))
-            });
-            intent.error = Some(error.to_string());
-            write(&self.directory, &intent)
-        })();
-        if let Err(error) = result {
-            warn!(%error, "Could not save upload retry state");
-        }
-    }
-
-    pub(crate) fn mark_cancelled(&self) -> Result<(), AuthedApiError> {
-        self.cancel();
-        let _ledger = self.ledger.lock().unwrap_or_else(PoisonError::into_inner);
-        if let Some(mut intent) = read(&self.directory)? {
-            intent.cancelled = true;
-            intent.retry_at = None;
-            write(&self.directory, &intent)?;
-        }
-        Ok(())
-    }
-
-    pub(crate) fn set_verification(
-        &self,
-        verification: &UploadVerification,
-    ) -> Result<(), AuthedApiError> {
-        self.check()?;
-        let _ledger = self.ledger.lock().unwrap_or_else(PoisonError::into_inner);
-        if let Some(mut intent) = read(&self.directory)? {
-            if intent.required_audio != Some(verification.required_audio) {
-                return Err("Upload audio intent changed".into());
-            }
-            intent.verification = Some(verification.clone());
-            intent.receipt = None;
-            write(&self.directory, &intent)?;
-        }
-        Ok(())
-    }
-
-    pub(crate) fn clear_verification(&self) -> Result<(), AuthedApiError> {
-        let _ledger = self.ledger.lock().unwrap_or_else(PoisonError::into_inner);
-        *self.verified.lock().unwrap_or_else(PoisonError::into_inner) = None;
-        if let Some(mut intent) = read(&self.directory)? {
-            intent.verification = None;
-            intent.receipt = None;
-            write(&self.directory, &intent)?;
-        }
-        Ok(())
-    }
-
-    pub(crate) fn record_receipt(
-        &self,
-        verification: &UploadVerification,
-        receipt: &VerifiedUploadReceipt,
-    ) -> Result<(), AuthedApiError> {
-        self.check()?;
-        verification
-            .verified_receipt(
-                &self.video_id,
-                &serde_json::json!({"success":true,"status":"verified","verification":receipt}),
-            )?
-            .ok_or("Recording verification is pending")?;
-        let _ledger = self.ledger.lock().unwrap_or_else(PoisonError::into_inner);
-        *self.verified.lock().unwrap_or_else(PoisonError::into_inner) =
-            Some((verification.clone(), receipt.clone()));
-        if let Some(mut intent) = read(&self.directory)? {
-            intent.verification = Some(verification.clone());
-            intent.receipt = Some(receipt.clone());
-            intent.failures = 0;
-            intent.needs_authentication = false;
-            intent.retry_at = None;
-            intent.error = None;
-            write(&self.directory, &intent)?;
-        }
-        Ok(())
-    }
-
-    pub(crate) async fn complete_locally(&self, app: &AppHandle) -> Result<(), AuthedApiError> {
-        self.check()?;
-        if let Some(context) = self.context() {
-            context.check(app).await?;
-        }
-        let _ledger = self.ledger.lock().unwrap_or_else(PoisonError::into_inner);
-        let intent = read(&self.directory)?;
-        let evidence = intent
-            .as_ref()
-            .and_then(|intent| intent.verification.clone().zip(intent.receipt.clone()))
-            .or_else(|| {
-                self.verified
-                    .lock()
-                    .unwrap_or_else(PoisonError::into_inner)
-                    .clone()
-            })
-            .ok_or("Recording verification evidence is missing")?;
-        let (verification, receipt) = (&evidence.0, &evidence.1);
-        verification
-            .verified_receipt(
-                &self.video_id,
-                &serde_json::json!({"success":true,"status":"verified","verification":receipt}),
-            )?
-            .ok_or("Recording verification is pending")?;
-        verify_local_artifact(&self.directory, verification)?;
-        let mut meta =
-            RecordingMeta::load_for_project(&self.directory).map_err(|error| error.to_string())?;
-        if !matches!(
-            meta.inner,
-            cap_project::RecordingMetaInner::Instant(
-                cap_project::InstantRecordingMeta::Complete { .. }
-            )
-        ) || upload_video_id(&meta.upload).is_some_and(|id| id != self.video_id)
-            || meta
-                .sharing
-                .as_ref()
-                .is_some_and(|sharing| sharing.id != self.video_id)
-            || intent.as_ref().is_some_and(|intent| intent.cancelled)
-        {
-            return Err("Recording is not locally ready for upload completion".into());
-        }
-        self.check()?;
-        meta.upload = Some(UploadMeta::Complete);
-        meta.save_for_project().map_err(|error| error.to_string())?;
-        self.check()?;
-        if intent.as_ref().is_some_and(|intent| !intent.preserve_local)
-            && crate::general_settings::GeneralSettingsStore::get(app)
-                .ok()
-                .flatten()
-                .unwrap_or_default()
-                .delete_instant_recordings_after_upload
-        {
-            verify_local_artifact(&self.directory, verification)?;
-            self.check()?;
-            if let Err(error) = std::fs::remove_dir_all(&self.directory) {
-                warn!(%error, "Verified recording retained because cleanup failed");
-            }
-        }
-        Ok(())
-    }
-}
-
-fn upload_video_id(upload: &Option) -> Option<&str> {
-    match upload {
-        Some(
-            UploadMeta::SegmentUpload { video_id, .. }
-            | UploadMeta::MultipartUpload { video_id, .. }
-            | UploadMeta::SinglePartUpload { video_id, .. },
-        ) => Some(video_id),
-        _ => None,
-    }
-}
-
-fn verify_local_artifact(
-    directory: &Path,
-    verification: &UploadVerification,
-) -> Result<(), AuthedApiError> {
-    use cap_recording::upload_verification::UploadArtifact;
-    match &verification.artifact {
-        UploadArtifact::Segments { manifest_sha256 } => {
-            let events = resume::collect_segment_events(directory, verification.required_audio)?;
-            let manifest = manifest_from_events(&events);
-            let compact = UploadVerification::segments(
-                &serde_json::to_vec(&manifest)?,
-                verification.required_audio,
-            );
-            let pretty = UploadVerification::segments(
-                &serde_json::to_vec_pretty(&manifest)?,
-                verification.required_audio,
-            );
-            if ![compact, pretty].iter().any(|request| matches!(&request.artifact, UploadArtifact::Segments { manifest_sha256: current } if current == manifest_sha256)) {
-                return Err("Local recording manifest changed after upload".into());
-            }
-        }
-        UploadArtifact::Mp4 {
-            file_size,
-            duration,
-            ..
-        } => {
-            let path = directory.join("content/output.mp4");
-            verify_file_path(
-                &path,
-                &directory
-                    .canonicalize()
-                    .map_err(|error| error.to_string())?
-                    .join("content/output.mp4"),
-            )?;
-            let info = std::fs::symlink_metadata(&path).map_err(|error| error.to_string())?;
-            if info.file_type().is_symlink()
-                || !info.is_file()
-                || info.len() != *file_size
-                || build_video_meta(&path)?.duration_in_secs != *duration
-            {
-                return Err("Local recording changed after upload".into());
-            }
-        }
-    }
-    Ok(())
-}
-
-fn manifest_from_events(
-    events: &[cap_enc_ffmpeg::segmented_stream::SegmentCompletedEvent],
-) -> SegmentUploadManifest {
-    use cap_enc_ffmpeg::segmented_stream::SegmentMediaType;
-    let mut state = SegmentUploadState::new();
-    for event in events {
-        match (event.is_init, event.media_type) {
-            (true, SegmentMediaType::Video) => state.video_init_uploaded = true,
-            (true, SegmentMediaType::Audio) => state.audio_init_uploaded = true,
-            (false, SegmentMediaType::Video) => {
-                state
-                    .uploaded_video_segments
-                    .insert(event.index, event.duration);
-            }
-            (false, SegmentMediaType::Audio) => {
-                state
-                    .uploaded_audio_segments
-                    .insert(event.index, event.duration);
-            }
-        }
-    }
-    state.to_complete_manifest()
-}
-
-pub(crate) async fn resume_audio(
-    app: &AppHandle,
-    directory: &Path,
-    fallback: bool,
-) -> Result, AuthedApiError> {
-    Ok(match read(directory)? {
-        Some(intent)
-            if intent.cancelled
-                || intent.failures >= 5
-                || intent
-                    .retry_at
-                    .is_some_and(|at| at > chrono::Utc::now().timestamp()) =>
-        {
-            None
-        }
-        Some(intent) => {
-            if intent.needs_authentication {
-                let context = UploadRequestContext::new(
-                    intent.server_url,
-                    intent
-                        .owner_id
-                        .ok_or(AuthedApiError::InvalidAuthentication)?,
-                )?;
-                if context.check(app).await.is_err() {
-                    return Ok(None);
-                }
-            }
-            intent.required_audio
-        }
-        None => Some(fallback),
-    })
-}
-
-pub(crate) async fn resume_existing(
-    app: AppHandle,
-    meta: RecordingMeta,
-    lock: UploadLock,
-    required_audio: bool,
-) -> Result, AuthedApiError> {
-    let directory = meta.project_path.clone();
-    let video_id = upload_video_id(&meta.upload)
-        .map(str::to_string)
-        .ok_or("No resumable upload identity")?;
-    let session = Session::new(lock.project_path().to_path_buf(), video_id.clone());
-    session.adopt(lock)?;
-    session.mark_ready(false)?;
-    let worker = session.clone();
-    supervise(app.clone(), session.clone(), async move {
-        match meta.upload.clone() {
-            Some(UploadMeta::SegmentUpload {
-                video_id,
-                pre_created_video,
-                recording_dir,
-            }) => {
-                verify_bundle_path(&directory, &recording_dir)?;
-                if video_id != pre_created_video.id || video_id != pre_created_video.config.id {
-                    return Err("Upload identity changed".into());
-                }
-                let events = resume::collect_segment_events(&directory, required_audio)?;
-                let (sender, receiver) = std::sync::mpsc::channel();
-                for event in events {
-                    sender.send(event).map_err(|error| error.to_string())?;
-                }
-                drop(sender);
-                SegmentUploader::run(
-                    app.clone(),
-                    receiver,
-                    None,
-                    directory.clone(),
-                    pre_created_video,
-                    required_audio,
-                    worker.clone(),
-                )
-                .await?;
-            }
-            Some(UploadMeta::MultipartUpload {
-                video_id,
-                file_path,
-                pre_created_video,
-                recording_dir,
-            }) => {
-                verify_bundle_path(&directory, &recording_dir)?;
-                if video_id != pre_created_video.id || video_id != pre_created_video.config.id {
-                    return Err("Upload identity changed".into());
-                }
-                verify_file_path(&file_path, &directory.join("content/output.mp4"))?;
-                InstantMultipartUpload::run(
-                    app.clone(),
-                    file_path,
-                    pre_created_video,
-                    directory.clone(),
-                    None,
-                    required_audio,
-                    worker.clone(),
-                )
-                .await?;
-            }
-            Some(UploadMeta::SinglePartUpload {
-                video_id,
-                file_path,
-                screenshot_path,
-                recording_dir,
-            }) => {
-                verify_bundle_path(&directory, &recording_dir)?;
-                verify_file_path(&file_path, &meta.output_path())?;
-                verify_file_path(&screenshot_path, &directory.join("screenshots/display.jpg"))?;
-                let metadata = build_video_meta(&file_path)?;
-                let file_size = std::fs::metadata(&file_path).map_err(|error| error.to_string())?.len();
-                let duration = metadata.duration_in_secs;
-                let uploaded = upload_video(
-                    &app,
-                    video_id.clone(),
-                    file_path,
-                    screenshot_path,
-                    meta.sharing.is_some()
-                        && matches!(meta.inner, cap_project::RecordingMetaInner::Studio(_)),
-                    None,
-                )
-                .await?;
-                if uploaded.id != video_id {
-                    return Err("Server upload identity changed".into());
-                }
-                if matches!(meta.inner, cap_project::RecordingMetaInner::Instant(_)) {
-                    let verification = UploadVerification::mp4(file_size, duration, required_audio, uploaded.object_identity.ok_or("Server did not return the uploaded object identity; local recording retained")?)?;
-                    await_upload_verification(&app, &video_id, &verification, &worker).await?;
-                } else {
-                    let mut current = RecordingMeta::load_for_project(&directory)
-                        .map_err(|error| error.to_string())?;
-                    if upload_video_id(¤t.upload) != Some(video_id.as_str()) {
-                        return Err("Upload identity changed during transfer".into());
-                    }
-                    worker.check()?;
-                    current.upload = Some(UploadMeta::Complete);
-                    current.sharing = Some(cap_project::SharingMeta {
-                        id: uploaded.id,
-                        link: uploaded.link,
-                        content_hash: None,
-                    });
-                    current
-                        .save_for_project()
-                        .map_err(|error| error.to_string())?;
-                    return Ok(());
-                }
-            }
-            _ => return Err("No resumable upload remains".into()),
-        }
-        let screenshot = directory.join("screenshots/display.jpg");
-        if screenshot.is_file() {
-            let bytes = compress_image(screenshot).await?;
-            worker.check()?;
-            singlepart_uploader(
-                app.clone(),
-                PresignedS3PutRequest {
-                    video_id,
-                    subpath: "screenshot/screen-capture.jpg".into(),
-                    method: PresignedS3PutRequestMethod::Put,
-                    meta: None,
-                },
-                bytes.len() as u64,
-                futures::stream::once(async move { Ok::<_, io::Error>(Bytes::from(bytes)) }),
-            )
-            .await?;
-        }
-        worker.complete_locally(&app).await
-    })
-    .await?;
-    Ok(session)
-}
-
-fn verify_bundle_path(expected: &Path, stored: &Path) -> Result<(), AuthedApiError> {
-    if expected.canonicalize().map_err(|error| error.to_string())?
-        != stored.canonicalize().map_err(|error| error.to_string())?
-    {
-        return Err("Stored recording path changed".into());
-    }
-    Ok(())
-}
-
-fn verify_file_path(stored: &Path, expected: &Path) -> Result<(), AuthedApiError> {
-    let parent = expected
-        .parent()
-        .ok_or("Upload input has no local parent")?;
-    let parent_info = parent
-        .symlink_metadata()
-        .map_err(|error| error.to_string())?;
-    if parent_info.file_type().is_symlink() || !parent_info.is_dir() {
-        return Err("Upload input directory is not a local directory".into());
-    }
-    #[cfg(windows)]
-    {
-        use std::os::windows::fs::MetadataExt;
-        if parent_info.file_attributes() & 0x400 != 0 {
-            return Err("Upload input directory is a reparse point".into());
-        }
-    }
-    let metadata = stored
-        .symlink_metadata()
-        .map_err(|error| error.to_string())?;
-    #[cfg(windows)]
-    {
-        use std::os::windows::fs::MetadataExt;
-        if metadata.file_attributes() & 0x400 != 0 {
-            return Err("Upload input is a reparse point".into());
-        }
-    }
-    if !metadata.is_file() || metadata.file_type().is_symlink() || metadata.len() == 0 {
-        return Err("Upload input is not a valid local file".into());
-    }
-    verify_bundle_path(expected, stored)
-}
-
-fn pending_reupload(meta: &RecordingMeta, intent: &Intent) -> Result {
-    use cap_recording::upload_verification::UploadArtifact;
-    let sharing = meta
-        .sharing
-        .as_ref()
-        .ok_or("Recording share identity is missing")?;
-    if sharing.id != intent.video_id || intent.cancelled || !intent.local_ready {
-        return Err("Recording retry identity changed or was cancelled".into());
-    }
-    let video = VideoUploadInfo {
-        id: intent.video_id.clone(),
-        link: sharing.link.clone(),
-        config: S3UploadMeta {
-            id: intent.video_id.clone(),
-        },
-    };
-    let segmented = match intent
-        .verification
-        .as_ref()
-        .map(|request| &request.artifact)
-    {
-        Some(UploadArtifact::Segments { .. }) => true,
-        Some(UploadArtifact::Mp4 { .. }) => false,
-        None => match meta.project_path.join("content/display").symlink_metadata() {
-            Ok(_) => true,
-            Err(error) if error.kind() == io::ErrorKind::NotFound => false,
-            Err(error) => return Err(error.to_string().into()),
-        },
-    };
-    Ok(if segmented {
-        UploadMeta::SegmentUpload {
-            video_id: intent.video_id.clone(),
-            pre_created_video: video,
-            recording_dir: meta.project_path.clone(),
-        }
-    } else {
-        UploadMeta::MultipartUpload {
-            video_id: intent.video_id.clone(),
-            pre_created_video: video,
-            recording_dir: meta.project_path.clone(),
-            file_path: meta.project_path.join("content/output.mp4"),
-        }
-    })
-}
-
-fn prepare_retry_state(
-    directory: &Path,
-    meta: &mut RecordingMeta,
-    intent: &mut Intent,
-    save_meta: impl FnOnce(&RecordingMeta) -> Result<(), String>,
-) -> Result<(), AuthedApiError> {
-    let reupload = matches!(meta.upload, Some(UploadMeta::Complete));
-    if reupload {
-        meta.upload = Some(pending_reupload(meta, intent)?);
-        intent.verification = None;
-        intent.receipt = None;
-    }
-    if upload_video_id(&meta.upload) != Some(intent.video_id.as_str()) {
-        return Err("Recording retry identity changed".into());
-    }
-    intent.failures = 0;
-    intent.needs_authentication = false;
-    intent.retry_at = None;
-    intent.error = None;
-    write(directory, intent)?;
-    if reupload {
-        save_meta(meta)?;
-    }
-    Ok(())
-}
-
-pub(crate) fn reconcile_reupload(meta: &mut RecordingMeta) -> Result<(), AuthedApiError> {
-    if !matches!(meta.upload, Some(UploadMeta::Complete))
-        || !matches!(
-            meta.inner,
-            cap_project::RecordingMetaInner::Instant(
-                cap_project::InstantRecordingMeta::Complete { .. }
-            )
-        )
-    {
-        return Ok(());
-    }
-    let Some(intent) = read(&meta.project_path)? else {
-        return Ok(());
-    };
-    if intent.cancelled
-        || !intent.local_ready
-        || intent.verification.is_some()
-        || intent.receipt.is_some()
-    {
-        return Ok(());
-    }
-    meta.upload = Some(pending_reupload(meta, &intent)?);
-    meta.save_for_project().map_err(|error| error.to_string())?;
-    Ok(())
-}
-
-pub(crate) async fn retry_existing(
-    app: AppHandle,
-    directory: &Path,
-) -> Result, AuthedApiError> {
-    if read(directory)?.is_none() {
-        return Ok(None);
-    }
-    let lock = acquire_upload_lock(directory)?;
-    let mut intent = read(directory)?.ok_or("Upload intent disappeared")?;
-    if intent.cancelled || !intent.local_ready {
-        return Err("This recording is not available for upload retry".into());
-    }
-    let context = UploadRequestContext::new(
-        intent.server_url.clone(),
-        intent
-            .owner_id
-            .clone()
-            .ok_or(AuthedApiError::InvalidAuthentication)?,
-    )?;
-    context.check(&app).await?;
-    let required_audio = intent
-        .required_audio
-        .ok_or("Recording audio intent is unknown")?;
-    let mut meta = RecordingMeta::load_for_project(directory).map_err(|error| error.to_string())?;
-    if !matches!(
-        meta.inner,
-        cap_project::RecordingMetaInner::Instant(
-            cap_project::InstantRecordingMeta::Complete { .. }
-        )
-    ) {
-        return Err("Recording must finish locally before retry".into());
-    }
-    let link = meta
-        .sharing
-        .as_ref()
-        .map(|sharing| sharing.link.clone())
-        .ok_or("Recording share identity is missing")?;
-    prepare_retry_state(directory, &mut meta, &mut intent, |meta| {
-        meta.save_for_project().map_err(|error| error.to_string())
-    })?;
-    let session = resume_existing(app, meta, lock, required_audio).await?;
-    let mut terminal = session.terminal.subscribe();
-    timeout(Duration::from_secs(30 * 60), async {
-        loop {
-            if let Some(result) = terminal.borrow_and_update().clone() {
-                result.map_err(AuthedApiError::from)?;
-                return Ok(Some(link));
-            }
-            terminal
-                .changed()
-                .await
-                .map_err(|_| "Upload completion channel closed")?;
-        }
-    })
-    .await
-    .map_err(|_| AuthedApiError::VerificationPending)?
-}
-
-struct Job {
-    session: Arc,
-    handle: JoinHandle<()>,
-}
-
-static JOBS: std::sync::OnceLock>> = std::sync::OnceLock::new();
-static PUMP: std::sync::OnceLock>>> = std::sync::OnceLock::new();
-static WAKE: tokio::sync::Notify = tokio::sync::Notify::const_new();
-static STOPPING: AtomicBool = AtomicBool::new(false);
-
-fn jobs() -> &'static Mutex> {
-    JOBS.get_or_init(Mutex::default)
-}
-
-pub(crate) fn has_capacity() -> bool {
-    !STOPPING.load(Ordering::Acquire)
-        && jobs().lock().unwrap_or_else(PoisonError::into_inner).len() < 2
-}
-
-pub(crate) async fn supervise(
-    app: AppHandle,
-    session: Arc,
-    work: F,
-) -> Result<(), AuthedApiError>
-where
-    F: std::future::Future> + Send + 'static,
-{
-    let mut work = Some(work);
-    let registered = {
-        let mut jobs = jobs().lock().unwrap_or_else(PoisonError::into_inner);
-        if STOPPING.load(Ordering::Acquire) || jobs.contains_key(&session.directory) {
-            false
-        } else {
-            let directory = session.directory.clone();
-            let worker = session.clone();
-            let context = session.context();
-            let work = work.take().unwrap();
-            let handle = spawn_actor(async move {
-                let result = std::panic::AssertUnwindSafe(
-                    worker.run(crate::web_api::inherit_upload_context(context, work)),
-                )
-                .catch_unwind()
-                .await
-                .unwrap_or_else(|_| Err("Upload worker failed; local recording retained".into()));
-                worker
-                    .terminal
-                    .send_replace(Some(result.as_ref().copied().map_err(ToString::to_string)));
-                if let Err(error) = result {
-                    if !matches!(error, AuthedApiError::VerificationPending) {
-                        crate::notifications::NotificationType::UploadFailed.send(&app);
-                    }
-                    worker.record_failure(&error);
-                    warn!(%error, "Recording upload retained for retry");
-                }
-                emit_upload_complete(&app, &worker.video_id);
-            });
-            jobs.insert(
-                directory,
-                Job {
-                    session: session.clone(),
-                    handle,
-                },
-            );
-            true
-        }
-    };
-    if !registered {
-        session.cancel();
-        let result = session
-            .run(crate::web_api::inherit_upload_context(
-                session.context(),
-                work.unwrap(),
-            ))
-            .await;
-        session
-            .terminal
-            .send_replace(Some(result.as_ref().copied().map_err(ToString::to_string)));
-        if let Err(error) = result {
-            session.record_failure(&error);
-        }
-    }
-    Ok(())
-}
-
-async fn join_job(job: Job) {
-    if let Err(error) = job.handle.await {
-        job.session.record_failure(&AuthedApiError::Other(format!(
-            "Upload supervisor failed: {error}"
-        )));
-        warn!(%error, "Upload supervisor failed");
-    }
-}
-
-pub(crate) async fn reap() {
-    let completed = {
-        let mut jobs = jobs().lock().unwrap_or_else(PoisonError::into_inner);
-        let paths: Vec<_> = jobs
-            .iter()
-            .filter(|(_, job)| job.handle.is_finished())
-            .map(|(path, _)| path.clone())
-            .collect();
-        paths
-            .into_iter()
-            .filter_map(|path| jobs.remove(&path))
-            .collect::>()
-    };
-    for job in completed {
-        join_job(job).await;
-    }
-}
-
-pub(crate) async fn cancel(directory: &Path) {
-    let job = jobs()
-        .lock()
-        .unwrap_or_else(PoisonError::into_inner)
-        .remove(directory);
-    if let Some(job) = job {
-        job.session.mark_cancelled().ok();
-        join_job(job).await;
-    }
-}
-
-pub(crate) fn mark_cancelled(directory: &Path) -> Result<(), AuthedApiError> {
-    if let Some(mut intent) = read(directory)? {
-        intent.cancelled = true;
-        intent.retry_at = None;
-        write(directory, &intent)?;
-    }
-    Ok(())
-}
-
-pub(crate) fn init(app: AppHandle) {
-    let mut pump = PUMP
-        .get_or_init(Mutex::default)
-        .lock()
-        .unwrap_or_else(PoisonError::into_inner);
-    if pump.is_some() {
-        return;
-    }
-    *pump = Some(spawn_actor(async move {
-        loop {
-            if STOPPING.load(Ordering::Acquire) {
-                return;
-            }
-            tokio::select! {
-                ready = crate::startup::wait_for_window(&app) => {
-                    if !ready {
-                        return;
-                    }
-                    break;
-                }
-                _ = WAKE.notified() => {},
-            }
-        }
-        let mut first = true;
-        while !STOPPING.load(Ordering::Acquire) {
-            if let Err(error) = crate::resume_uploads(app.clone(), first).await {
-                warn!(%error, "Upload reconciliation failed; recordings retained");
-            }
-            first = false;
-            tokio::select! {
-                _ = WAKE.notified() => {},
-                _ = tokio::time::sleep(Duration::from_secs(30)) => {},
-            }
-        }
-    }));
-}
-
-pub(crate) async fn shutdown() {
-    STOPPING.store(true, Ordering::Release);
-    WAKE.notify_one();
-    let pump = PUMP
-        .get_or_init(Mutex::default)
-        .lock()
-        .unwrap_or_else(PoisonError::into_inner)
-        .take();
-    if let Some(pump) = pump {
-        let _ = pump.await;
-    }
-    let owned = std::mem::take(&mut *jobs().lock().unwrap_or_else(PoisonError::into_inner));
-    for job in owned.values() {
-        job.session.cancel();
-    }
-    for (_, job) in owned {
-        join_job(job).await;
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    fn project() -> (tempfile::TempDir, Arc) {
-        let directory = tempfile::tempdir().unwrap();
-        std::fs::write(
-            directory.path().join("retained-media"),
-            b"original recording bytes",
-        )
-        .unwrap();
-        write(
-            directory.path(),
-            &Intent {
-                version: 1,
-                video_id: "owned-video".into(),
-                server_url: "https://example.invalid".into(),
-                owner_id: Some("owner".into()),
-                required_audio: Some(true),
-                local_ready: false,
-                cancelled: false,
-                preserve_local: false,
-                failures: 0,
-                needs_authentication: false,
-                retry_at: None,
-                error: None,
-                verification: None,
-                receipt: None,
-            },
-        )
-        .unwrap();
-        RecordingMeta {
-            platform: None,
-            project_path: directory.path().to_path_buf(),
-            pretty_name: "retained".into(),
-            sharing: None,
-            inner: cap_project::RecordingMetaInner::Instant(
-                cap_project::InstantRecordingMeta::InProgress { recording: true },
-            ),
-            upload: None,
-        }
-        .save_for_project()
-        .unwrap();
-        let lock = UploadLock::acquire(directory.path()).unwrap();
-        let session = Session::new(lock.project_path().to_path_buf(), "owned-video".into());
-        session.adopt(lock).unwrap();
-        (directory, session)
-    }
-
-    fn receipt(request: &UploadVerification) -> VerifiedUploadReceipt {
-        VerifiedUploadReceipt {
-            version: 1,
-            video_id: "owned-video".into(),
-            artifact: request.artifact.clone(),
-            file_size: 4096,
-            duration: 10.0,
-            has_audio: true,
-            full_decode: true,
-            required_audio_verified: request.required_audio,
-        }
-    }
-
-    #[tokio::test]
-    async fn local_ready_releases_completion_gate_without_waiting_for_network() {
-        let (directory, session) = project();
-        let mut gate = Box::pin(session.wait_ready());
-        assert!(futures::poll!(gate.as_mut()).is_pending());
-        session.mark_ready(false).unwrap();
-        gate.await.unwrap();
-        let intent = read(directory.path()).unwrap().unwrap();
-        assert!(intent.local_ready);
-        assert!(intent.verification.is_none());
-        assert!(intent.receipt.is_none());
-        assert!(directory.path().join("retained-media").exists());
-    }
-
-    #[tokio::test]
-    async fn cancellation_is_persisted_and_never_opens_completion_gate() {
-        let (directory, session) = project();
-        let mut gate = Box::pin(session.wait_ready());
-        assert!(futures::poll!(gate.as_mut()).is_pending());
-        session.mark_cancelled().unwrap();
-        assert!(gate.await.is_err());
-        assert!(read(directory.path()).unwrap().unwrap().cancelled);
-        assert_eq!(
-            std::fs::read(directory.path().join("retained-media")).unwrap(),
-            b"original recording bytes"
-        );
-    }
-
-    #[test]
-    fn restart_preserves_identity_and_actual_audio_intent_with_exclusive_ownership() {
-        let (directory, session) = project();
-        session.mark_ready(false).unwrap();
-        session.record_failure(&AuthedApiError::Timeout);
-        assert!(matches!(
-            UploadLock::acquire(directory.path()),
-            Err(cap_recording::upload_resume::UploadLockError::Busy)
-        ));
-        drop(session);
-        let lock = UploadLock::acquire(directory.path()).unwrap();
-        let resumed = Session::new(lock.project_path().to_path_buf(), "owned-video".into());
-        resumed.adopt(lock).unwrap();
-        let intent = read(directory.path()).unwrap().unwrap();
-        assert_eq!(intent.video_id, "owned-video");
-        assert_eq!(intent.owner_id.as_deref(), Some("owner"));
-        assert_eq!(intent.required_audio, Some(true));
-        assert!(intent.local_ready);
-        assert_eq!(intent.failures, 1);
-        assert!(directory.path().join("retained-media").exists());
-    }
-
-    #[test]
-    fn processing_and_authentication_do_not_exhaust_failed_transfer_budget() {
-        let (directory, session) = project();
-        for _ in 0..8 {
-            session.record_failure(&AuthedApiError::VerificationPending);
-        }
-        assert_eq!(read(directory.path()).unwrap().unwrap().failures, 0);
-        session.record_failure(&AuthedApiError::InvalidAuthentication);
-        let intent = read(directory.path()).unwrap().unwrap();
-        assert!(intent.needs_authentication);
-        assert_eq!(intent.failures, 0);
-        for _ in 0..5 {
-            session.record_failure(&AuthedApiError::Timeout);
-        }
-        let intent = read(directory.path()).unwrap().unwrap();
-        assert_eq!(intent.failures, 5);
-        assert!(intent.retry_at.is_none());
-        assert_eq!(intent.video_id, "owned-video");
-        assert!(directory.path().join("retained-media").exists());
-    }
-
-    #[test]
-    fn server_retransfer_clears_only_cached_evidence() {
-        let (directory, session) = project();
-        let request = UploadVerification::segments(b"manifest", true);
-        session.set_verification(&request).unwrap();
-        session
-            .record_receipt(&request, &receipt(&request))
-            .unwrap();
-        session.clear_verification().unwrap();
-        session.record_failure(&AuthedApiError::ReuploadRequired);
-        let intent = read(directory.path()).unwrap().unwrap();
-        assert!(intent.verification.is_none());
-        assert!(intent.receipt.is_none());
-        assert_eq!(intent.video_id, "owned-video");
-        assert!(directory.path().join("retained-media").exists());
-    }
-
-    #[test]
-    fn wrong_generation_or_probe_only_receipt_never_persists_completion() {
-        let (directory, session) = project();
-        let request = UploadVerification::segments(b"manifest", true);
-        session.set_verification(&request).unwrap();
-        for change in 0..5 {
-            let mut invalid = receipt(&request);
-            match change {
-                0 => invalid.full_decode = false,
-                1 => invalid.has_audio = false,
-                2 => invalid.video_id = "other-video".into(),
-                3 => invalid.required_audio_verified = false,
-                _ => {
-                    invalid.artifact =
-                        UploadVerification::segments(b"other-manifest", true).artifact
-                }
-            }
-            assert!(session.record_receipt(&request, &invalid).is_err());
-            assert!(read(directory.path()).unwrap().unwrap().receipt.is_none());
-        }
-        assert!(directory.path().join("retained-media").exists());
-    }
-
-    #[test]
-    fn unknown_legacy_upload_does_not_acquire_an_invented_sidecar() {
-        let directory = tempfile::tempdir().unwrap();
-        let lock = UploadLock::acquire(directory.path()).unwrap();
-        let session = Session::new(lock.project_path().to_path_buf(), "legacy-video".into());
-        session.adopt(lock).unwrap();
-        session.record_failure(&AuthedApiError::Timeout);
-        session.mark_ready(false).unwrap();
-        assert!(read(directory.path()).unwrap().is_none());
-    }
-
-    #[tokio::test]
-    async fn cancelled_job_retains_lock_until_its_worker_is_joined() {
-        let (directory, session) = project();
-        let (release, released) = tokio::sync::oneshot::channel();
-        let worker = session.clone();
-        let handle = tokio::spawn(async move {
-            worker.cancelled().await;
-            released.await.unwrap();
-            assert!(worker.directory.join("retained-media").exists());
-        });
-        let job = Job {
-            session: session.clone(),
-            handle,
-        };
-        session.cancel();
-        drop(session);
-        let mut joined = Box::pin(join_job(job));
-        assert!(futures::poll!(joined.as_mut()).is_pending());
-        assert!(matches!(
-            UploadLock::acquire(directory.path()),
-            Err(cap_recording::upload_resume::UploadLockError::Busy)
-        ));
-        release.send(()).unwrap();
-        joined.await;
-        assert!(UploadLock::acquire(directory.path()).is_ok());
-        assert!(directory.path().join("retained-media").exists());
-    }
-
-    #[cfg(unix)]
-    #[test]
-    fn upload_input_cannot_escape_through_a_parent_symlink() {
-        let directory = tempfile::tempdir().unwrap();
-        let outside = tempfile::tempdir().unwrap();
-        std::fs::write(outside.path().join("output.mp4"), b"private bytes").unwrap();
-        std::os::unix::fs::symlink(outside.path(), directory.path().join("content")).unwrap();
-        let path = directory.path().join("content/output.mp4");
-        assert!(verify_file_path(&path, &path).is_err());
-        assert_eq!(
-            std::fs::read(outside.path().join("output.mp4")).unwrap(),
-            b"private bytes"
-        );
-    }
-    #[test]
-    fn legacy_mp4_proof_without_object_generation_retransfers_without_changing_identity() {
-        let (directory, session) = project();
-        let mut intent = read(directory.path()).unwrap().unwrap();
-        intent.verification = Some(serde_json::from_value(serde_json::json!({"version":1,"artifact":{"kind":"mp4","fileSize":4096,"duration":10.0},"requiredAudio":true})).unwrap());
-        write(directory.path(), &intent).unwrap();
-        assert!(session.cached_verification().unwrap().is_none());
-        let retained = read(directory.path()).unwrap().unwrap();
-        assert!(retained.verification.is_none());
-        assert!(retained.receipt.is_none());
-        assert_eq!(retained.video_id, "owned-video");
-        assert!(directory.path().join("retained-media").exists());
-    }
-    #[test]
-    fn concurrent_local_save_and_upload_start_preserve_both_updates() {
-        let (directory, session) = project();
-        let barrier = Arc::new(std::sync::Barrier::new(2));
-        let worker = session.clone();
-        let upload_barrier = barrier.clone();
-        let uploader = std::thread::spawn(move || {
-            upload_barrier.wait();
-            worker
-                .persist_upload(UploadMeta::SinglePartUpload {
-                    video_id: "owned-video".into(),
-                    file_path: worker.directory.join("content/output.mp4"),
-                    screenshot_path: worker.directory.join("screenshots/display.jpg"),
-                    recording_dir: worker.directory.clone(),
-                })
-                .unwrap();
-        });
-        barrier.wait();
-        session
-            .persist_local_complete(
-                cap_project::InstantRecordingMeta::Complete {
-                    fps: 30,
-                    sample_rate: Some(48000),
-                },
-                cap_project::SharingMeta {
-                    id: "owned-video".into(),
-                    link: "https://example.invalid/s/owned-video".into(),
-                    content_hash: None,
-                },
-            )
-            .unwrap();
-        uploader.join().unwrap();
-        let meta = RecordingMeta::load_for_project(directory.path()).unwrap();
-        assert!(matches!(
-            meta.inner,
-            cap_project::RecordingMetaInner::Instant(
-                cap_project::InstantRecordingMeta::Complete { .. }
-            )
-        ));
-        assert_eq!(upload_video_id(&meta.upload), Some("owned-video"));
-        assert_eq!(meta.sharing.unwrap().id, "owned-video");
-        assert!(directory.path().join("retained-media").exists());
-    }
-    #[tokio::test]
-    async fn cancellation_drops_inherited_request_future_without_authorizing_completion() {
-        struct PendingRequest(Arc);
-        impl Drop for PendingRequest {
-            fn drop(&mut self) {
-                self.0.store(true, Ordering::Release);
-            }
-        }
-        let (_directory, session) = project();
-        let dropped = Arc::new(AtomicBool::new(false));
-        let completed = Arc::new(AtomicBool::new(false));
-        let (entered, started) = tokio::sync::oneshot::channel();
-        let worker = session.clone();
-        let request_dropped = dropped.clone();
-        let completion = completed.clone();
-        let task = tokio::spawn(async move {
-            worker
-                .run(async move {
-                    let task =
-                        tokio::spawn(crate::web_api::inherit_upload_context(None, async move {
-                            let _request = PendingRequest(request_dropped);
-                            entered.send(()).unwrap();
-                            cancellable(std::future::pending::<()>()).await?;
-                            completion.store(true, Ordering::Release);
-                            Ok::<_, AuthedApiError>(())
-                        }));
-                    task.await.unwrap()
-                })
-                .await
-        });
-        started.await.unwrap();
-        session.cancel();
-        assert!(
-            timeout(Duration::from_secs(2), task)
-                .await
-                .unwrap()
-                .unwrap()
-                .is_err()
-        );
-        assert!(dropped.load(Ordering::Acquire));
-        assert!(!completed.load(Ordering::Acquire));
-    }
-
-    #[tokio::test]
-    async fn cancelled_filesystem_future_keeps_ownership_until_real_read_finishes() {
-        let (directory, session) = project();
-        let (entered, started) = tokio::sync::oneshot::channel();
-        let (release, released) = std::sync::mpsc::channel();
-        let closed = Arc::new(AtomicBool::new(false));
-        let finished = closed.clone();
-        let path = directory.path().join("retained-media");
-        let worker = session.clone();
-        let mut task = tokio::spawn(async move {
-            worker
-                .run(file_io(move || {
-                    use std::io::Read;
-                    let mut file = std::fs::File::open(path)?;
-                    entered.send(()).unwrap();
-                    released.recv_timeout(Duration::from_secs(2)).unwrap();
-                    let mut bytes = Vec::new();
-                    file.read_to_end(&mut bytes)?;
-                    drop(file);
-                    finished.store(true, Ordering::Release);
-                    Ok(bytes)
-                }))
-                .await
-        });
-        started.await.unwrap();
-        session.cancel();
-        assert!(futures::poll!(&mut task).is_pending());
-        assert!(!closed.load(Ordering::Acquire));
-        assert!(matches!(
-            UploadLock::acquire(directory.path()),
-            Err(cap_recording::upload_resume::UploadLockError::Busy)
-        ));
-        release.send(()).unwrap();
-        assert!(
-            timeout(Duration::from_secs(2), task)
-                .await
-                .unwrap()
-                .unwrap()
-                .is_err()
-        );
-        assert!(closed.load(Ordering::Acquire));
-        assert_eq!(session.reads.active.load(Ordering::Acquire), 0);
-        drop(session);
-        assert!(UploadLock::acquire(directory.path()).is_ok());
-    }
-
-    #[tokio::test]
-    async fn cancellation_closes_progressive_reader_without_waiting_for_recording_done() {
-        let (directory, session) = project();
-        let path = directory.path().join("retained-media");
-        let (done, receiver) = flume::bounded(1);
-        let worker = session.clone();
-        let task = tokio::spawn(async move {
-            worker
-                .run(
-                    super::super::from_pending_file_to_chunks(path, Some(receiver))
-                        .try_collect::>(),
-                )
-                .await
-        });
-        timeout(Duration::from_secs(2), async {
-            while session.reads.active.load(Ordering::Acquire) == 0 {
-                tokio::task::yield_now().await;
-            }
-        })
-        .await
-        .unwrap();
-        session.cancel();
-        assert!(
-            timeout(Duration::from_secs(2), task)
-                .await
-                .unwrap()
-                .unwrap()
-                .is_err()
-        );
-        assert_eq!(session.reads.active.load(Ordering::Acquire), 0);
-        assert!(done.is_disconnected());
-        assert_eq!(
-            std::fs::read(directory.path().join("retained-media")).unwrap(),
-            b"original recording bytes"
-        );
-    }
-    fn completed_retry_fixture(
-        directory: &Path,
-        session: &Session,
-        segmented: bool,
-    ) -> (RecordingMeta, Intent) {
-        session
-            .persist_local_complete(
-                cap_project::InstantRecordingMeta::Complete {
-                    fps: 30,
-                    sample_rate: Some(48000),
-                },
-                cap_project::SharingMeta {
-                    id: "owned-video".into(),
-                    link: "https://example.invalid/s/owned-video".into(),
-                    content_hash: None,
-                },
-            )
-            .unwrap();
-        session.mark_ready(false).unwrap();
-        let request = if segmented {
-            std::fs::create_dir_all(directory.join("content/display")).unwrap();
-            UploadVerification::segments(b"manifest", true)
-        } else {
-            UploadVerification::mp4(4096, 10.0, true, "\"old-object\"".into()).unwrap()
-        };
-        session.set_verification(&request).unwrap();
-        session
-            .record_receipt(&request, &receipt(&request))
-            .unwrap();
-        let mut meta = RecordingMeta::load_for_project(directory).unwrap();
-        meta.upload = Some(UploadMeta::Complete);
-        meta.save_for_project().unwrap();
-        (meta, read(directory).unwrap().unwrap())
-    }
-
-    #[test]
-    fn explicit_reupload_reuses_original_identity_and_clears_completed_proof() {
-        for segmented in [false, true] {
-            let (directory, session) = project();
-            let (mut meta, mut intent) =
-                completed_retry_fixture(directory.path(), &session, segmented);
-            prepare_retry_state(directory.path(), &mut meta, &mut intent, |meta| {
-                meta.save_for_project().map_err(|error| error.to_string())
-            })
-            .unwrap();
-            let pending = RecordingMeta::load_for_project(directory.path()).unwrap();
-            assert_eq!(upload_video_id(&pending.upload), Some("owned-video"));
-            assert_eq!(
-                matches!(pending.upload, Some(UploadMeta::SegmentUpload { .. })),
-                segmented
-            );
-            let retained = read(directory.path()).unwrap().unwrap();
-            assert!(retained.verification.is_none());
-            assert!(retained.receipt.is_none());
-            assert_eq!(retained.owner_id.as_deref(), Some("owner"));
-            assert!(directory.path().join("retained-media").exists());
-        }
-    }
-
-    #[test]
-    fn interrupted_reupload_metadata_write_remains_recoverable_without_stale_proof() {
-        for segmented in [false, true] {
-            let (directory, session) = project();
-            let (mut meta, mut intent) =
-                completed_retry_fixture(directory.path(), &session, segmented);
-            assert!(
-                prepare_retry_state(directory.path(), &mut meta, &mut intent, |_| Err(
-                    "injected metadata replacement failure".into()
-                ))
-                .is_err()
-            );
-            let mut original = RecordingMeta::load_for_project(directory.path()).unwrap();
-            assert!(matches!(original.upload, Some(UploadMeta::Complete)));
-            assert!(
-                read(directory.path())
-                    .unwrap()
-                    .unwrap()
-                    .verification
-                    .is_none()
-            );
-            reconcile_reupload(&mut original).unwrap();
-            assert_eq!(upload_video_id(&original.upload), Some("owned-video"));
-            assert_eq!(
-                matches!(original.upload, Some(UploadMeta::SegmentUpload { .. })),
-                segmented
-            );
-            assert!(directory.path().join("retained-media").exists());
-        }
-    }
-}
diff --git a/apps/desktop/src-tauri/src/upload/preparation.rs b/apps/desktop/src-tauri/src/upload/preparation.rs
deleted file mode 100644
index f8a5025a28f..00000000000
--- a/apps/desktop/src-tauri/src/upload/preparation.rs
+++ /dev/null
@@ -1,96 +0,0 @@
-use super::{SegmentUploadState, lifecycle};
-use crate::{api, web_api::inherit_upload_context};
-use cap_recording::upload_preparation::Preparation;
-pub(crate) use cap_recording::upload_preparation::Segment;
-use std::{
-    sync::{Arc, Mutex},
-    time::Duration,
-};
-use tauri::AppHandle;
-
-pub(super) struct Task(tokio::task::JoinHandle<()>);
-
-impl Task {
-    pub(super) async fn stop(mut self) {
-        self.0.abort();
-        if let Err(error) = (&mut self.0).await
-            && !error.is_cancelled()
-        {
-            tracing::warn!(%error, "Optional recording preparation stopped");
-        }
-    }
-}
-
-impl Drop for Task {
-    fn drop(&mut self) {
-        self.0.abort();
-    }
-}
-
-pub(super) fn start(
-    app: AppHandle,
-    video_id: String,
-    state: Arc>,
-    session: Arc,
-) -> Task {
-    let context = session.context();
-    Task(tokio::spawn(inherit_upload_context(context, async move {
-        let mut preparation = Preparation::default();
-        let mut next_request = tokio::time::Instant::now();
-        let mut interval = tokio::time::interval(Duration::from_secs(30));
-        interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
-        loop {
-            tokio::select! {
-                _ = session.cancelled() => return,
-                _ = interval.tick() => {}
-            }
-            if tokio::time::Instant::now() < next_request {
-                continue;
-            }
-            let batch = {
-                let state = state.lock().unwrap_or_else(|error| error.into_inner());
-                preparation.next_batch(
-                    state.uploaded_video_segments.keys().copied(),
-                    state.uploaded_audio_segments.keys().copied(),
-                )
-            };
-            if batch.is_empty() {
-                continue;
-            }
-            let result = tokio::select! {
-                _ = session.cancelled() => return,
-                result = api::prepare_recording_segments(&app, &video_id, &batch) => result,
-            };
-            match result {
-                Ok(Some(prepared)) => {
-                    preparation.acknowledge(&batch, &prepared);
-                }
-                Ok(None) => return,
-                Err(error) => {
-                    preparation.request_failed();
-                    tracing::debug!(%error, "Optional recording preparation unavailable");
-                }
-            }
-            next_request = tokio::time::Instant::now() + preparation.retry_delay();
-        }
-    })))
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[tokio::test]
-    async fn stopping_preparation_cancels_an_in_flight_request() {
-        let (started, ready) = tokio::sync::oneshot::channel();
-        let handle = tokio::spawn(async move {
-            started.send(()).unwrap();
-            std::future::pending::<()>().await;
-        });
-        let abort = handle.abort_handle();
-        let task = Task(handle);
-        ready.await.unwrap();
-        task.stop().await;
-        assert!(abort.is_finished());
-    }
-}
diff --git a/apps/desktop/src-tauri/src/upload/recovery_age.rs b/apps/desktop/src-tauri/src/upload/recovery_age.rs
deleted file mode 100644
index 2bc2e4ae3a8..00000000000
--- a/apps/desktop/src-tauri/src/upload/recovery_age.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-use std::{path::Path, time::SystemTime};
-
-const MAX_AUTOMATIC_RECOVERY_AGE: std::time::Duration =
-    std::time::Duration::from_secs(24 * 60 * 60);
-
-pub(crate) fn eligible(project: &Path, now: SystemTime) -> bool {
-    project
-        .metadata()
-        .and_then(|metadata| metadata.created())
-        .ok()
-        .and_then(|created| now.duration_since(created).ok())
-        .is_some_and(|age| age <= MAX_AUTOMATIC_RECOVERY_AGE)
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use std::{fs, time::Duration};
-
-    #[test]
-    fn recovery_expires_even_when_old_recording_metadata_changes() {
-        let project = std::env::temp_dir().join(format!("cap-recovery-age-{}", std::process::id()));
-        fs::create_dir(&project).unwrap();
-        let created = project.metadata().unwrap().created().unwrap();
-        assert!(eligible(&project, created));
-        assert!(eligible(&project, created + MAX_AUTOMATIC_RECOVERY_AGE));
-        fs::write(project.join("recording-meta.json"), b"{}").unwrap();
-        assert!(!eligible(
-            &project,
-            created + MAX_AUTOMATIC_RECOVERY_AGE + Duration::from_secs(1)
-        ));
-        assert!(!eligible(&project, SystemTime::UNIX_EPOCH));
-        fs::remove_dir_all(&project).unwrap();
-        assert!(!eligible(&project, created));
-    }
-}
diff --git a/apps/desktop/src-tauri/src/upload/resume.rs b/apps/desktop/src-tauri/src/upload/resume.rs
deleted file mode 100644
index 30dd92cfca9..00000000000
--- a/apps/desktop/src-tauri/src/upload/resume.rs
+++ /dev/null
@@ -1 +0,0 @@
-pub(crate) use cap_recording::upload_resume::collect_segment_events;
diff --git a/apps/desktop/src-tauri/src/web_api.rs b/apps/desktop/src-tauri/src/web_api.rs
deleted file mode 100644
index b15d334648d..00000000000
--- a/apps/desktop/src-tauri/src/web_api.rs
+++ /dev/null
@@ -1,325 +0,0 @@
-use reqwest::StatusCode;
-use tauri::{Emitter, Manager, Runtime};
-use thiserror::Error;
-use tracing::{debug, error, warn};
-
-use crate::{
-    ArcLock,
-    auth::{AuthSecret, AuthStore},
-    http_client,
-};
-
-#[derive(Error, Debug)]
-pub enum AuthedApiError {
-    #[error("User is not authenticated or credentials have expired!")]
-    InvalidAuthentication,
-    #[error("User needs to upgrade their account to use this feature!")]
-    UpgradeRequired,
-    #[error("App state is still initializing")]
-    AppStateUnavailable,
-    #[error("AuthedApiError/AuthStore: {0}")]
-    AuthStore(String),
-    #[error("AuthedApiError/Request: {0}")]
-    Request(reqwest::Error),
-    #[error("AuthedApiError/Deserialization: {0}")]
-    Deserialization(#[from] serde_json::Error),
-    #[error("The request has timed out")]
-    Timeout,
-    #[error(
-        "Cloud verification rejected the uploaded recording; local data must be uploaded again"
-    )]
-    ReuploadRequired,
-    #[error("Recording is awaiting cloud verification; local files are retained")]
-    VerificationPending,
-    #[error("AuthedApiError/Other: {0}")]
-    Other(String),
-}
-
-impl From for AuthedApiError {
-    fn from(err: reqwest::Error) -> Self {
-        match err {
-            err if err.is_timeout() => AuthedApiError::Timeout,
-            err => AuthedApiError::Request(err.without_url()),
-        }
-    }
-}
-
-impl From<&'static str> for AuthedApiError {
-    fn from(value: &'static str) -> Self {
-        AuthedApiError::Other(value.into())
-    }
-}
-
-impl From for AuthedApiError {
-    fn from(value: String) -> Self {
-        AuthedApiError::Other(value)
-    }
-}
-
-fn apply_env_headers(req: reqwest::RequestBuilder) -> reqwest::RequestBuilder {
-    let mut req = req
-        .header("X-Cap-Desktop-Version", env!("CARGO_PKG_VERSION"))
-        .header("X-Cap-Desktop-Features", "googleDriveUpload");
-
-    if let Ok(s) = std::env::var("VITE_VERCEL_AUTOMATION_BYPASS_SECRET") {
-        req = req.header("x-vercel-protection-bypass", s);
-    }
-
-    req
-}
-
-fn default_server_url() -> String {
-    option_env!("VITE_SERVER_URL")
-        .unwrap_or("https://cap.so")
-        .to_string()
-}
-
-async fn current_server_url(manager: &T) -> Result
-where
-    T: Manager + ?Sized,
-    R: Runtime,
-{
-    let Some(app_state) = manager.try_state::>() else {
-        return Err(AuthedApiError::AppStateUnavailable);
-    };
-
-    Ok(app_state.read().await.server_url.clone())
-}
-
-#[derive(Clone)]
-pub(crate) struct UploadRequestContext {
-    server_url: String,
-    owner_id: String,
-}
-
-tokio::task_local! {
-    static UPLOAD_REQUEST: UploadRequestContext;
-}
-
-impl UploadRequestContext {
-    pub(crate) fn new(server_url: String, owner_id: String) -> Result {
-        if server_url.is_empty() || owner_id.is_empty() {
-            return Err(AuthedApiError::InvalidAuthentication);
-        }
-        Ok(Self {
-            server_url,
-            owner_id,
-        })
-    }
-
-    fn check_identity(
-        &self,
-        server_url: &str,
-        owner_id: Option<&str>,
-    ) -> Result<(), AuthedApiError> {
-        if server_url != self.server_url || owner_id != Some(self.owner_id.as_str()) {
-            return Err(AuthedApiError::InvalidAuthentication);
-        }
-        Ok(())
-    }
-
-    pub(crate) async fn check(&self, app: &tauri::AppHandle) -> Result<(), AuthedApiError> {
-        let auth = AuthStore::get(app)
-            .map_err(AuthedApiError::AuthStore)?
-            .ok_or(AuthedApiError::InvalidAuthentication)?;
-        self.check_identity(¤t_server_url(app).await?, auth.user_id.as_deref())
-    }
-
-    pub(crate) async fn run(self, future: F) -> F::Output {
-        UPLOAD_REQUEST.scope(self, future).await
-    }
-
-    pub(crate) fn current() -> Option {
-        UPLOAD_REQUEST.try_with(Clone::clone).ok()
-    }
-}
-
-pub(crate) fn inherit_upload_context(
-    context: Option,
-    future: F,
-) -> impl std::future::Future {
-    let scope = crate::upload::lifecycle::UploadScope::current();
-    async move {
-        let request = async move {
-            match context {
-                Some(context) => context.run(future).await,
-                None => future.await,
-            }
-        };
-        match scope {
-            Some(scope) => scope.bind(request).await,
-            None => request.await,
-        }
-    }
-}
-
-async fn do_authed_request(
-    client: &reqwest::Client,
-    auth: &AuthStore,
-    build: impl FnOnce(&reqwest::Client, String) -> reqwest::RequestBuilder,
-    url: String,
-) -> Result {
-    let req = build(client, url).header(
-        "Authorization",
-        format!(
-            "Bearer {}",
-            match &auth.secret {
-                AuthSecret::ApiKey { api_key } => api_key,
-                AuthSecret::Session { token, .. } => token,
-            }
-        ),
-    );
-
-    apply_env_headers(req).send().await
-}
-
-#[allow(async_fn_in_trait)]
-pub trait ManagerExt: Manager {
-    async fn authed_api_request(
-        &self,
-        path: impl Into,
-        build: impl FnOnce(&reqwest::Client, String) -> reqwest::RequestBuilder,
-    ) -> Result;
-
-    async fn api_request(
-        &self,
-        path: impl Into,
-        build: impl FnOnce(&reqwest::Client, String) -> reqwest::RequestBuilder,
-    ) -> Result;
-
-    async fn make_app_url(&self, pathname: impl AsRef) -> String;
-
-    async fn is_server_url_custom(&self) -> bool;
-}
-
-impl + Emitter, R: Runtime> ManagerExt for T {
-    async fn authed_api_request(
-        &self,
-        path: impl Into,
-        build: impl FnOnce(&reqwest::Client, String) -> reqwest::RequestBuilder,
-    ) -> Result {
-        let Some(auth) = AuthStore::get(self.app_handle()).map_err(AuthedApiError::AuthStore)?
-        else {
-            debug!("Skipping authenticated API request because user is not logged in");
-            return Err(AuthedApiError::InvalidAuthentication);
-        };
-
-        let path = path.into();
-        let server_url = crate::upload::lifecycle::cancellable(current_server_url(self)).await??;
-        let server_url = if let Some(context) = UploadRequestContext::current() {
-            context.check_identity(&server_url, auth.user_id.as_deref())?;
-            context.server_url
-        } else {
-            server_url
-        };
-        let url = format!("{server_url}{path}");
-        let response = crate::upload::lifecycle::cancellable(do_authed_request(
-            &self.state::(),
-            &auth,
-            build,
-            url,
-        ))
-        .await??;
-
-        if response.status() == StatusCode::UNAUTHORIZED {
-            error!("Authentication expired. Please log in again.");
-            return Err(AuthedApiError::InvalidAuthentication);
-        }
-
-        Ok(response)
-    }
-
-    async fn api_request(
-        &self,
-        path: impl Into,
-        build: impl FnOnce(&reqwest::Client, String) -> reqwest::RequestBuilder,
-    ) -> Result {
-        let url = self.make_app_url(path.into()).await;
-
-        apply_env_headers(build(&self.state::(), url))
-            .send()
-            .await
-    }
-
-    async fn make_app_url(&self, pathname: impl AsRef) -> String {
-        let pathname = pathname.as_ref();
-        match current_server_url(self).await {
-            Ok(server_url) => format!("{server_url}{pathname}"),
-            Err(err) => {
-                warn!("App state unavailable while building app URL: {err}");
-                format!("{}{}", default_server_url(), pathname)
-            }
-        }
-    }
-
-    async fn is_server_url_custom(&self) -> bool {
-        match current_server_url(self).await {
-            Ok(server_url) => {
-                if let Some(env_url) = std::option_env!("VITE_SERVER_URL") {
-                    return server_url != env_url;
-                }
-
-                false
-            }
-            Err(err) => {
-                warn!("App state unavailable while reading server URL settings: {err}");
-                false
-            }
-        }
-    }
-}
-
-#[cfg(test)]
-mod upload_context_tests {
-    use super::*;
-
-    #[test]
-    fn upload_request_errors_do_not_expose_signed_urls() {
-        let url = reqwest::Url::parse(
-            "https://storage.invalid/object?X-Amz-Signature=private-signature&upload_id=private-session",
-        )
-        .unwrap();
-        let error = reqwest::Client::new()
-            .put(url.clone())
-            .header("invalid\nheader", "value")
-            .build()
-            .unwrap_err()
-            .with_url(url);
-        assert!(error.url().is_some());
-        let error = AuthedApiError::from(error);
-        assert!(
-            matches!(&error, AuthedApiError::Request(inner) if inner.is_builder() && inner.url().is_none())
-        );
-        for diagnostic in [error.to_string(), format!("{error:?}")] {
-            assert!(!diagnostic.contains("private-signature"));
-            assert!(!diagnostic.contains("private-session"));
-            assert!(!diagnostic.contains("storage.invalid"));
-        }
-    }
-
-    #[test]
-    fn upload_request_identity_cannot_follow_a_changed_account_or_server() {
-        let context =
-            UploadRequestContext::new("https://original.invalid".into(), "owner".into()).unwrap();
-        assert!(
-            context
-                .check_identity("https://original.invalid", Some("owner"))
-                .is_ok()
-        );
-        assert!(
-            context
-                .check_identity("https://changed.invalid", Some("owner"))
-                .is_err()
-        );
-        assert!(
-            context
-                .check_identity("https://original.invalid", Some("another-owner"))
-                .is_err()
-        );
-        assert!(
-            context
-                .check_identity("https://original.invalid", None)
-                .is_err()
-        );
-    }
-}
diff --git a/apps/desktop/src-tauri/src/window_exclusion.rs b/apps/desktop/src-tauri/src/window_exclusion.rs
deleted file mode 100644
index 8bdf228afc6..00000000000
--- a/apps/desktop/src-tauri/src/window_exclusion.rs
+++ /dev/null
@@ -1,407 +0,0 @@
-#[cfg(target_os = "macos")]
-use scap_targets::{Window, WindowId};
-use serde::{Deserialize, Serialize};
-use specta::Type;
-#[cfg(target_os = "macos")]
-use tracing::{debug, info, warn};
-
-#[derive(Debug, Clone, Serialize, Deserialize, Type, PartialEq, Eq)]
-#[serde(rename_all = "camelCase")]
-pub struct WindowExclusion {
-    #[serde(default, skip_serializing_if = "Option::is_none")]
-    pub bundle_identifier: Option,
-    #[serde(default, skip_serializing_if = "Option::is_none")]
-    pub owner_name: Option,
-    #[serde(default, skip_serializing_if = "Option::is_none")]
-    pub window_title: Option,
-}
-
-impl WindowExclusion {
-    pub fn matches(
-        &self,
-        bundle_identifier: Option<&str>,
-        owner_name: Option<&str>,
-        window_title: Option<&str>,
-    ) -> bool {
-        if let Some(identifier) = self.bundle_identifier.as_deref()
-            && bundle_identifier
-                .map(|candidate| candidate == identifier)
-                .unwrap_or(false)
-        {
-            return true;
-        }
-
-        if let Some(expected_owner) = self.owner_name.as_deref() {
-            let owner_matches = owner_name
-                .map(|candidate| candidate == expected_owner)
-                .unwrap_or(false);
-
-            if self.window_title.is_some() {
-                return owner_matches
-                    && self
-                        .window_title
-                        .as_deref()
-                        .map(|expected_title| {
-                            window_title
-                                .map(|candidate| candidate == expected_title)
-                                .unwrap_or(false)
-                        })
-                        .unwrap_or(false);
-            }
-
-            if owner_matches {
-                return true;
-            }
-        }
-
-        if let Some(expected_title) = self.window_title.as_deref() {
-            return window_title
-                .map(|candidate| candidate == expected_title)
-                .unwrap_or(false);
-        }
-
-        false
-    }
-}
-
-#[cfg_attr(not(any(target_os = "macos", test)), allow(dead_code))]
-pub fn filter_for_instant_mode(
-    mut exclusions: Vec,
-    camera_title: &str,
-) -> Vec {
-    exclusions.retain(|e| e.window_title.as_deref() != Some(camera_title));
-    exclusions
-}
-
-#[cfg_attr(not(any(target_os = "macos", test)), allow(dead_code))]
-fn matches_window_title(exclusions: &[WindowExclusion], title: &str) -> bool {
-    exclusions
-        .iter()
-        .any(|entry| entry.matches(None, None, Some(title)))
-}
-
-#[cfg(any(target_os = "macos", test))]
-fn excludes_own_window(
-    exclusions: &[WindowExclusion],
-    window: &crate::windows::CapWindowId,
-) -> bool {
-    matches!(window, crate::windows::CapWindowId::RecordingControls)
-        || matches_window_title(exclusions, &window.title())
-}
-
-#[cfg(target_os = "macos")]
-fn append_native_window_id(ids: &mut Vec, native_id: &WindowId) -> bool {
-    if ids.contains(native_id) {
-        return false;
-    }
-    ids.push(native_id.clone());
-    true
-}
-
-#[cfg(target_os = "macos")]
-pub fn resolve_window_ids(exclusions: &[WindowExclusion]) -> Vec {
-    if exclusions.is_empty() {
-        return Vec::new();
-    }
-
-    Window::list()
-        .into_iter()
-        .filter_map(|window| {
-            let owner_name = window.owner_name();
-            let window_title = window.name();
-            let bundle_identifier = window.raw_handle().bundle_identifier();
-            let matches = exclusions.iter().any(|entry| {
-                entry.matches(
-                    bundle_identifier.as_deref(),
-                    owner_name.as_deref(),
-                    window_title.as_deref(),
-                )
-            });
-
-            if !matches {
-                return None;
-            }
-
-            let window_id = window.id();
-            info!(
-                %window_id,
-                owner_name = ?owner_name,
-                window_title = ?window_title,
-                bundle_identifier = ?bundle_identifier,
-                "Resolved excluded macOS window"
-            );
-            Some(window_id)
-        })
-        .collect()
-}
-
-#[cfg(target_os = "macos")]
-pub fn append_matching_webview_window_ids(
-    ids: &mut Vec,
-    app: &tauri::AppHandle,
-    exclusions: &[WindowExclusion],
-) {
-    use crate::windows::CapWindowId;
-    use std::str::FromStr;
-    use tauri::Manager;
-
-    for (label, window) in app.webview_windows() {
-        let Ok(window_id) = CapWindowId::from_str(&label) else {
-            continue;
-        };
-        let title = window_id.title();
-        if !excludes_own_window(exclusions, &window_id) {
-            continue;
-        }
-        let Some(native_id) = webview_window_id(&window) else {
-            warn!(
-                label = %label,
-                title = %title,
-                "Excluded Tauri webview window has no native window id"
-            );
-            continue;
-        };
-        if !append_native_window_id(ids, &native_id) {
-            debug!(
-                window_id = %native_id,
-                label = %label,
-                title = %title,
-                "Excluded Tauri webview window id already resolved"
-            );
-            continue;
-        }
-        info!(
-            window_id = %native_id,
-            label = %label,
-            title = %title,
-            "Resolved excluded Tauri webview window"
-        );
-    }
-}
-
-#[cfg(target_os = "macos")]
-fn webview_window_id(window: &tauri::WebviewWindow) -> Option {
-    let ns_window = window.ns_window().ok()? as *const objc2_app_kit::NSWindow;
-    let ns_window = unsafe { ns_window.as_ref() }?;
-    let number = unsafe { ns_window.windowNumber() };
-
-    if number <= 0 {
-        return None;
-    }
-
-    number.to_string().parse().ok()
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    fn title_exclusion(title: &str) -> WindowExclusion {
-        WindowExclusion {
-            bundle_identifier: None,
-            owner_name: None,
-            window_title: Some(title.to_string()),
-        }
-    }
-
-    fn bundle_exclusion(bundle_id: &str) -> WindowExclusion {
-        WindowExclusion {
-            bundle_identifier: Some(bundle_id.to_string()),
-            owner_name: None,
-            window_title: None,
-        }
-    }
-
-    fn owner_exclusion(owner: &str) -> WindowExclusion {
-        WindowExclusion {
-            bundle_identifier: None,
-            owner_name: Some(owner.to_string()),
-            window_title: None,
-        }
-    }
-
-    #[test]
-    fn matches_by_window_title() {
-        let exclusion = title_exclusion("Cap Camera");
-        assert!(exclusion.matches(None, None, Some("Cap Camera")));
-        assert!(!exclusion.matches(None, None, Some("Other Window")));
-        assert!(!exclusion.matches(None, None, None));
-    }
-
-    #[test]
-    fn matches_by_bundle_identifier() {
-        let exclusion = bundle_exclusion("com.cap.desktop");
-        assert!(exclusion.matches(Some("com.cap.desktop"), None, None));
-        assert!(!exclusion.matches(Some("com.other.app"), None, None));
-        assert!(!exclusion.matches(None, None, None));
-    }
-
-    #[test]
-    fn matches_by_owner_name() {
-        let exclusion = owner_exclusion("Cap");
-        assert!(exclusion.matches(None, Some("Cap"), None));
-        assert!(!exclusion.matches(None, Some("Other"), None));
-        assert!(!exclusion.matches(None, None, None));
-    }
-
-    #[test]
-    fn matches_owner_and_title_requires_both() {
-        let exclusion = WindowExclusion {
-            bundle_identifier: None,
-            owner_name: Some("Cap".to_string()),
-            window_title: Some("Cap Camera".to_string()),
-        };
-        assert!(exclusion.matches(None, Some("Cap"), Some("Cap Camera")));
-        assert!(!exclusion.matches(None, Some("Cap"), Some("Wrong Title")));
-        assert!(!exclusion.matches(None, Some("Wrong Owner"), Some("Cap Camera")));
-        assert!(!exclusion.matches(None, None, Some("Cap Camera")));
-    }
-
-    #[test]
-    fn empty_exclusion_matches_nothing() {
-        let exclusion = WindowExclusion {
-            bundle_identifier: None,
-            owner_name: None,
-            window_title: None,
-        };
-        assert!(!exclusion.matches(None, None, None));
-        assert!(!exclusion.matches(Some("any"), Some("any"), Some("any")));
-    }
-
-    #[test]
-    fn bundle_identifier_takes_priority() {
-        let exclusion = WindowExclusion {
-            bundle_identifier: Some("com.cap.desktop".to_string()),
-            owner_name: None,
-            window_title: Some("Cap Camera".to_string()),
-        };
-        assert!(exclusion.matches(Some("com.cap.desktop"), None, None));
-        assert!(exclusion.matches(Some("com.cap.desktop"), None, Some("Wrong")));
-    }
-
-    #[test]
-    fn instant_mode_removes_camera_exclusion() {
-        let exclusions = vec![
-            title_exclusion("Cap"),
-            title_exclusion("Cap Camera"),
-            title_exclusion("Cap Settings"),
-            title_exclusion("Cap Recording Controls"),
-        ];
-
-        let filtered = filter_for_instant_mode(exclusions, "Cap Camera");
-
-        assert_eq!(filtered.len(), 3);
-        assert!(
-            filtered
-                .iter()
-                .all(|e| e.window_title.as_deref() != Some("Cap Camera"))
-        );
-        assert!(
-            filtered
-                .iter()
-                .any(|e| e.window_title.as_deref() == Some("Cap"))
-        );
-        assert!(
-            filtered
-                .iter()
-                .any(|e| e.window_title.as_deref() == Some("Cap Settings"))
-        );
-        assert!(
-            filtered
-                .iter()
-                .any(|e| e.window_title.as_deref() == Some("Cap Recording Controls"))
-        );
-    }
-
-    #[test]
-    fn instant_mode_noop_when_camera_absent() {
-        let exclusions = vec![title_exclusion("Cap"), title_exclusion("Cap Settings")];
-
-        let filtered = filter_for_instant_mode(exclusions, "Cap Camera");
-        assert_eq!(filtered.len(), 2);
-    }
-
-    #[test]
-    fn instant_mode_handles_empty_list() {
-        let filtered = filter_for_instant_mode(vec![], "Cap Camera");
-        assert!(filtered.is_empty());
-    }
-
-    #[test]
-    fn matches_webview_title_using_exclusion_rules() {
-        let exclusions = vec![title_exclusion("Cap Camera")];
-
-        assert!(matches_window_title(&exclusions, "Cap Camera"));
-        assert!(!matches_window_title(&exclusions, "Cap Recording Controls"));
-    }
-
-    #[test]
-    fn own_controls_are_excluded_with_empty_or_custom_rules() {
-        use crate::windows::CapWindowId;
-
-        assert!(excludes_own_window(&[], &CapWindowId::RecordingControls));
-        assert!(excludes_own_window(
-            &[title_exclusion("Unrelated window")],
-            &CapWindowId::RecordingControls,
-        ));
-        assert!(!excludes_own_window(&[], &CapWindowId::Camera));
-    }
-
-    #[test]
-    fn own_window_exclusions_preserve_default_and_instant_camera_rules() {
-        use crate::windows::CapWindowId;
-
-        let defaults = crate::general_settings::default_excluded_windows();
-        assert!(excludes_own_window(
-            &defaults,
-            &CapWindowId::RecordingControls
-        ));
-        assert!(excludes_own_window(&defaults, &CapWindowId::Camera));
-        let instant = filter_for_instant_mode(defaults, &CapWindowId::Camera.title());
-        assert!(!excludes_own_window(&instant, &CapWindowId::Camera));
-        assert!(excludes_own_window(
-            &instant,
-            &CapWindowId::RecordingControls
-        ));
-    }
-
-    #[cfg(target_os = "macos")]
-    #[test]
-    fn native_exclusion_ids_do_not_require_a_visible_cg_window() {
-        let native_id: WindowId = "4294967294".parse().unwrap();
-        let mut ids = Vec::new();
-        assert!(append_native_window_id(&mut ids, &native_id));
-        assert_eq!(ids, vec![native_id.clone()]);
-        assert!(!append_native_window_id(&mut ids, &native_id));
-        assert_eq!(ids.len(), 1);
-    }
-
-    #[test]
-    fn default_exclusions_contain_camera() {
-        let defaults = crate::general_settings::default_excluded_windows();
-        assert!(
-            defaults
-                .iter()
-                .any(|e| e.window_title.as_deref() == Some("Cap Camera")),
-            "Default exclusions must include 'Cap Camera' — instant mode filtering depends on this"
-        );
-    }
-
-    #[test]
-    fn default_exclusions_only_match_camera_by_title() {
-        let defaults = crate::general_settings::default_excluded_windows();
-        let camera = defaults
-            .iter()
-            .find(|e| e.window_title.as_deref() == Some("Cap Camera"))
-            .expect("Cap Camera must be in default exclusions");
-
-        assert!(
-            camera.bundle_identifier.is_none(),
-            "Default camera exclusion should match by title only"
-        );
-        assert!(
-            camera.owner_name.is_none(),
-            "Default camera exclusion should match by title only"
-        );
-    }
-}
diff --git a/apps/desktop/src-tauri/src/window_position_persistence.rs b/apps/desktop/src-tauri/src/window_position_persistence.rs
deleted file mode 100644
index 2831a1bb5af..00000000000
--- a/apps/desktop/src-tauri/src/window_position_persistence.rs
+++ /dev/null
@@ -1,126 +0,0 @@
-use scap_targets::DisplayId;
-use std::sync::{Arc, Mutex};
-use std::time::Duration;
-use tauri::{AppHandle, Manager};
-use tokio::sync::Notify;
-
-use crate::general_settings::{GeneralSettingsStore, WindowPosition};
-
-#[derive(Default)]
-struct PendingState {
-    main: Option,
-    camera_position: Option<(f64, f64, Option)>,
-}
-
-pub struct WindowPositionPersistence {
-    pending: Mutex,
-    notify: Arc,
-}
-
-impl WindowPositionPersistence {
-    fn new() -> Arc {
-        Arc::new(Self {
-            pending: Mutex::new(PendingState::default()),
-            notify: Arc::new(Notify::new()),
-        })
-    }
-
-    pub fn queue_main(&self, position: WindowPosition) {
-        {
-            let mut guard = self.pending.lock().unwrap_or_else(|e| e.into_inner());
-            guard.main = Some(position);
-        }
-        self.notify.notify_one();
-    }
-
-    pub fn queue_camera(&self, x: f64, y: f64, display_id: Option) {
-        {
-            let mut guard = self.pending.lock().unwrap_or_else(|e| e.into_inner());
-            guard.camera_position = Some((x, y, display_id));
-        }
-        self.notify.notify_one();
-    }
-
-    fn take_pending(&self) -> PendingState {
-        let mut guard = self.pending.lock().unwrap_or_else(|e| e.into_inner());
-        std::mem::take(&mut *guard)
-    }
-}
-
-pub fn install(app: &AppHandle) {
-    let persistence = WindowPositionPersistence::new();
-    app.manage(persistence.clone());
-
-    let app_handle = app.clone();
-    let notify = persistence.notify.clone();
-    tokio::spawn(async move {
-        const DEBOUNCE: Duration = Duration::from_millis(350);
-        const MIN_INTERVAL: Duration = Duration::from_millis(150);
-
-        let mut last_flush = std::time::Instant::now()
-            .checked_sub(MIN_INTERVAL)
-            .unwrap_or_else(std::time::Instant::now);
-
-        loop {
-            notify.notified().await;
-
-            if crate::app_is_exiting(&app_handle) {
-                break;
-            }
-
-            tokio::time::sleep(DEBOUNCE).await;
-
-            if crate::app_is_exiting(&app_handle) {
-                break;
-            }
-
-            let elapsed = last_flush.elapsed();
-            let remaining = MIN_INTERVAL.saturating_sub(elapsed);
-            if !remaining.is_zero() {
-                tokio::time::sleep(remaining).await;
-            }
-
-            let Some(persistence) = app_handle.try_state::>() else {
-                break;
-            };
-            let pending = persistence.take_pending();
-
-            if pending.main.is_none() && pending.camera_position.is_none() {
-                continue;
-            }
-
-            let write_app = app_handle.clone();
-            let write_result = tokio::task::spawn_blocking(move || {
-                GeneralSettingsStore::update(&write_app, |settings| {
-                    if let Some(main) = pending.main {
-                        settings.main_window_position = Some(main);
-                    }
-                    if let Some((x, y, display_id)) = pending.camera_position {
-                        crate::update_camera_window_position_settings(settings, x, y, display_id);
-                    }
-                })
-            })
-            .await;
-
-            match write_result {
-                Ok(Ok(())) => {}
-                Ok(Err(err)) => tracing::warn!("Failed to persist window position: {err}"),
-                Err(err) => tracing::warn!("Window position persistence task panicked: {err}"),
-            }
-
-            last_flush = std::time::Instant::now();
-        }
-    });
-}
-
-pub fn queue_main_position(app: &AppHandle, position: WindowPosition) {
-    if let Some(persistence) = app.try_state::>() {
-        persistence.queue_main(position);
-    }
-}
-
-pub fn queue_camera_position(app: &AppHandle, x: f64, y: f64, display_id: Option) {
-    if let Some(persistence) = app.try_state::>() {
-        persistence.queue_camera(x, y, display_id);
-    }
-}
diff --git a/apps/desktop/src-tauri/src/windows.rs b/apps/desktop/src-tauri/src/windows.rs
deleted file mode 100644
index 8e25dc422a0..00000000000
--- a/apps/desktop/src-tauri/src/windows.rs
+++ /dev/null
@@ -1,4483 +0,0 @@
-#![allow(unused_mut)]
-#![allow(unused_imports)]
-
-use anyhow::anyhow;
-use futures::pin_mut;
-use scap_targets::{Display, DisplayId};
-use serde::Deserialize;
-use specta::Type;
-use std::{
-    collections::HashMap,
-    ops::Deref,
-    path::{Path, PathBuf},
-    str::FromStr,
-    sync::{
-        Arc, Mutex, Weak,
-        atomic::{AtomicU32, AtomicU64, Ordering},
-    },
-    time::Duration,
-};
-use tauri::{
-    AppHandle, LogicalPosition, LogicalSize, Manager, Monitor, PhysicalPosition, PhysicalSize,
-    WebviewUrl, WebviewWindow, WebviewWindowBuilder, Wry,
-};
-use tauri_specta::Event;
-use tokio::sync::RwLock;
-use tracing::{debug, error, info, instrument, warn};
-
-#[cfg(target_os = "macos")]
-use crate::panel_manager::{PanelManager, PanelState, PanelWindowType, is_window_handle_valid};
-
-use crate::{
-    App, ArcLock, CameraWindowCloseGate, CameraWindowPositionGuard, MainWindowReadyState,
-    NewNotification, RequestSetTargetMode, camera_preview_error_message,
-    editor_window::{EditorInstances, PendingEditorInstances},
-    emit_camera_preview_clear, emit_camera_preview_error, fake_window,
-    general_settings::{self, AppTheme, GeneralSettingsStore},
-    permissions,
-    recording::{RecordingEvent, RecordingInputKind},
-    recording_settings::RecordingTargetMode,
-    screenshot_editor::{PendingScreenshotEditorInstances, ScreenshotEditorInstances},
-    target_select_overlay::WindowFocusManager,
-    window_exclusion::WindowExclusion,
-};
-use cap_recording::{feeds, sources::screen_capture::ScreenCaptureTarget};
-
-#[cfg(target_os = "macos")]
-const DEFAULT_TRAFFIC_LIGHTS_INSET: LogicalPosition = LogicalPosition::new(12.0, 12.0);
-
-#[cfg(target_os = "macos")]
-const TELEPROMPTER_PANEL_LEVEL: objc2_app_kit::NSWindowLevel = 101;
-
-const DEFAULT_FALLBACK_DISPLAY_WIDTH: f64 = 1920.0;
-const DEFAULT_FALLBACK_DISPLAY_HEIGHT: f64 = 1080.0;
-
-#[tauri::command]
-#[specta::specta]
-pub(crate) async fn restore_main_window_geometry(window: WebviewWindow) -> Result {
-    if window.label() != "main" {
-        return Err("Only the main window can restore its geometry".into());
-    }
-    let (tx, rx) = tokio::sync::oneshot::channel();
-    let handle = window.app_handle().clone();
-    handle
-        .run_on_main_thread(move || {
-            let result = restore_main_window_bounds(&window).map(|()| false);
-            let _ = tx.send(result.map_err(|error| error.to_string()));
-        })
-        .map_err(|error| error.to_string())?;
-    rx.await.map_err(|error| error.to_string())?
-}
-
-fn restore_main_window_bounds(window: &WebviewWindow) -> tauri::Result<()> {
-    let inner = window.inner_size()?;
-    let outer = window.outer_size()?;
-    let scale = window.scale_factor()?;
-    let before = window.outer_position().ok();
-    let monitor = window.current_monitor().ok().flatten();
-    let frame = (
-        (f64::from(outer.width) - f64::from(inner.width)).max(0.0) / scale,
-        (f64::from(outer.height) - f64::from(inner.height)).max(0.0) / scale,
-    );
-    let (width, height) = crate::main_window_geometry::SIZE;
-    if (width - f64::from(inner.width) / scale).abs() > 0.5
-        || (height - f64::from(inner.height) / scale).abs() > 0.5
-    {
-        window.set_size(LogicalSize::new(width, height))?;
-    }
-    if let Some((before, monitor)) = before.zip(monitor)
-        && let Ok(after) = window.outer_position()
-    {
-        let area = monitor.work_area();
-        let (x, y) = crate::main_window_geometry::restored_position(
-            (f64::from(before.x), f64::from(before.y)),
-            ((width + frame.0) * scale, (height + frame.1) * scale),
-            (f64::from(area.position.x), f64::from(area.position.y)),
-            (f64::from(area.size.width), f64::from(area.size.height)),
-            scale,
-        );
-        if x != f64::from(after.x) || y != f64::from(after.y) {
-            let _ = window.set_position(PhysicalPosition::new(
-                (x + 0.5).floor() as i32,
-                (y + 0.5).floor() as i32,
-            ));
-        }
-    }
-    Ok(())
-}
-
-#[cfg(windows)]
-const WINDOWS_WEBVIEW2_BROWSER_ARGS: &str = "--disable-features=msWebOOUI,msPdfOOUI,msSmartScreenProtection --autoplay-policy=no-user-gesture-required --disable-vulkan --use-angle=d3d11";
-
-#[cfg(windows)]
-fn windows_webview2_browser_args() -> String {
-    let mut args = WINDOWS_WEBVIEW2_BROWSER_ARGS.to_string();
-    if cap_rendering::force_software_wgpu_adapter()
-        || std::env::args_os().any(|arg| arg.to_str() == Some("--disable-gpu"))
-    {
-        args.push_str(" --disable-gpu");
-    }
-    args
-}
-
-#[cfg(target_os = "macos")]
-fn is_system_dark_mode() -> bool {
-    use cocoa::base::{id, nil};
-    use cocoa::foundation::NSString;
-    use objc::{class, msg_send, sel, sel_impl};
-
-    unsafe {
-        let app: id = msg_send![class!(NSApplication), sharedApplication];
-        let appearance: id = msg_send![app, effectiveAppearance];
-        if appearance == nil {
-            return false;
-        }
-        let name: id = msg_send![appearance, name];
-        if name == nil {
-            return false;
-        }
-        let dark_appearance = NSString::alloc(nil).init_str("NSAppearanceNameDarkAqua");
-        let vibrant_dark = NSString::alloc(nil).init_str("NSAppearanceNameVibrantDark");
-        let is_dark: bool = msg_send![name, isEqualToString: dark_appearance];
-        let is_vibrant_dark: bool = msg_send![name, isEqualToString: vibrant_dark];
-        is_dark || is_vibrant_dark
-    }
-}
-
-#[cfg(target_os = "windows")]
-fn is_system_dark_mode() -> bool {
-    use winreg::RegKey;
-    use winreg::enums::HKEY_CURRENT_USER;
-
-    let hkcu = RegKey::predef(HKEY_CURRENT_USER);
-    if let Ok(key) =
-        hkcu.open_subkey("Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize")
-        && let Ok(value) = key.get_value::("AppsUseLightTheme")
-    {
-        return value == 0;
-    }
-    false
-}
-
-#[cfg(target_os = "linux")]
-fn is_system_dark_mode() -> bool {
-    let output = std::process::Command::new("gsettings")
-        .args(["get", "org.gnome.desktop.interface", "color-scheme"])
-        .output();
-    if let Ok(output) = output
-        && output.status.success()
-    {
-        return String::from_utf8_lossy(&output.stdout).contains("dark");
-    }
-    false
-}
-
-pub fn hide_overlay(window: &WebviewWindow) {
-    if let Some(state) = window.app_handle().try_state::() {
-        state.suspend_overlay(window.label());
-    }
-    let _ = window.set_ignore_cursor_events(true);
-    if let Err(error) = window.hide() {
-        warn!(%error, label = window.label(), "Failed to hide overlay; destroying it");
-        let _ = window.destroy();
-    }
-}
-
-pub fn show_overlay(window: &WebviewWindow) {
-    if let Some(session) = window
-        .app_handle()
-        .state::()
-        .picker_session()
-    {
-        crate::target_select_overlay::restore_overlay_reveal(window, session);
-    }
-}
-
-fn emit_app_event(app: &AppHandle, event: E)
-where
-    E: Event + serde::Serialize + Clone,
-{
-    let event_name = std::any::type_name::();
-    match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| event.emit(app))) {
-        Ok(Ok(())) => {}
-        Ok(Err(error)) => warn!(event = event_name, %error, "Failed to emit app event"),
-        Err(panic) => {
-            let message = crate::panic_payload_message(&panic);
-            error!(event = event_name, panic = %message, "Suppressed panic while emitting app event");
-        }
-    }
-}
-
-fn hide_recording_windows(app: &AppHandle, restore_target_select_overlays: bool) {
-    let focus_manager = app.try_state::();
-    if let Some(focus_manager) = focus_manager.as_ref() {
-        focus_manager.suspend_all_overlays();
-    }
-
-    for (label, window) in app.webview_windows() {
-        if let Ok(id) = CapWindowId::from_str(&label)
-            && matches!(
-                id,
-                CapWindowId::TargetSelectOverlay { .. } | CapWindowId::Main | CapWindowId::Camera
-            )
-        {
-            if matches!(id, CapWindowId::TargetSelectOverlay { .. }) {
-                if restore_target_select_overlays
-                    && window.is_visible().unwrap_or(false)
-                    && let Some(focus_manager) = focus_manager.as_ref()
-                {
-                    focus_manager.remember_overlay_for_restore(label);
-                }
-                hide_overlay(&window);
-            } else if matches!(id, CapWindowId::Main) {
-                crate::hide_main_window(app);
-            } else {
-                let _ = window.hide();
-            }
-        }
-    }
-}
-
-/// Release the live camera preview feed after `hide_recording_windows` when a
-/// foreground window (Settings, an editor) takes over. Hiding the camera window
-/// alone leaves the capture session running, so the OS camera-in-use indicator
-/// stays lit while the user is in the editor. `restore_main_window_inputs`
-/// re-attaches the feed when the main window comes back.
-fn release_camera_preview_if_idle(app: &AppHandle) {
-    let is_recording = app
-        .try_state::>()
-        .and_then(|state| {
-            state
-                .try_read()
-                .ok()
-                .map(|state| state.is_recording_active_or_pending())
-        })
-        .unwrap_or(true);
-
-    if is_recording {
-        return;
-    }
-
-    let app = app.clone();
-    tokio::spawn(async move {
-        if let Some(state) = app.try_state::>() {
-            let app_state = &mut *state.write().await;
-            app_state.camera_preview.pause();
-            let _ = app_state.camera_feed.ask(feeds::camera::RemoveInput).await;
-            app_state.camera_in_use = false;
-        } else {
-            warn!("App state unavailable while pausing camera preview");
-        }
-    });
-}
-
-fn bump_camera_window_session(app: &AppHandle) -> u64 {
-    app.state::>().fetch_add(1, Ordering::AcqRel) + 1
-}
-
-fn camera_window_label_for_session(session_id: u64) -> String {
-    format!("camera-{session_id}")
-}
-
-fn is_camera_window_label(label: &str) -> bool {
-    label == "camera"
-        || label
-            .strip_prefix("camera-")
-            .is_some_and(|suffix| suffix.parse::().is_ok())
-}
-
-fn camera_window_rank(label: &str) -> u64 {
-    if label == "camera" {
-        return 0;
-    }
-
-    label
-        .strip_prefix("camera-")
-        .and_then(|suffix| suffix.parse::().ok())
-        .unwrap_or(0)
-}
-
-#[cfg(target_os = "macos")]
-fn camera_window_labels(app: &AppHandle) -> Vec {
-    app.webview_windows()
-        .into_keys()
-        .filter(|label| is_camera_window_label(label))
-        .collect()
-}
-
-fn camera_webview_window_entries(app: &AppHandle) -> Vec<(String, WebviewWindow)> {
-    app.webview_windows()
-        .into_iter()
-        .filter(|(label, _)| is_camera_window_label(label))
-        .collect()
-}
-
-fn camera_webview_windows(app: &AppHandle) -> Vec {
-    camera_webview_window_entries(app)
-        .into_iter()
-        .map(|(_, window)| window)
-        .collect()
-}
-
-fn current_camera_window(app: &AppHandle) -> Option {
-    #[cfg(target_os = "macos")]
-    {
-        camera_webview_window_entries(app)
-            .into_iter()
-            .filter(|(_, window)| is_window_handle_valid(window))
-            .max_by_key(|(label, _)| camera_window_rank(label))
-            .map(|(_, window)| window)
-    }
-
-    #[cfg(not(target_os = "macos"))]
-    {
-        camera_webview_window_entries(app)
-            .into_iter()
-            .max_by_key(|(label, _)| camera_window_rank(label))
-            .map(|(_, window)| window)
-    }
-}
-
-fn destroy_camera_window_handle(
-    app: &AppHandle,
-    window: WebviewWindow,
-) -> tokio::sync::oneshot::Receiver<()> {
-    let (destroy_tx, destroy_rx) = tokio::sync::oneshot::channel();
-    let _ = window.as_ref().close();
-    app.run_on_main_thread({
-        let window = window.clone();
-        move || {
-            let _ = window.destroy();
-            let _ = destroy_tx.send(());
-        }
-    })
-    .ok();
-    destroy_rx
-}
-
-async fn init_native_camera_preview(
-    app_state: &mut App,
-    window: WebviewWindow,
-) -> Result<(), String> {
-    let camera_feed = app_state.camera_feed.clone();
-    let init_result = app_state
-        .camera_preview
-        .init_window(window, camera_feed.clone())
-        .await;
-
-    match init_result {
-        Ok(()) => {
-            #[allow(deprecated)]
-            let camera_ws_sender = app_state.camera_ws_sender.clone();
-            #[allow(deprecated)]
-            if let Err(err) = camera_feed
-                .ask(feeds::camera::RemoveSender(camera_ws_sender))
-                .await
-            {
-                warn!(error = %err, "Failed to remove legacy camera preview sender");
-            }
-            Ok(())
-        }
-        Err(err) => {
-            #[allow(deprecated)]
-            let camera_ws_sender = app_state.camera_ws_sender.clone();
-            #[allow(deprecated)]
-            if let Err(add_err) = camera_feed
-                .ask(feeds::camera::AddSender(camera_ws_sender))
-                .await
-            {
-                warn!(error = %add_err, "Failed to restore legacy camera preview sender");
-            }
-            Err(err.to_string())
-        }
-    }
-}
-
-pub(crate) async fn ensure_camera_input_active(app_state: &mut App) {
-    let app_handle = app_state.handle.clone();
-    let requested = app_handle.state::();
-    let snapshot = requested.snapshot();
-    if snapshot.camera.pending
-        || snapshot.camera.error.is_some()
-        || snapshot.camera.value != app_state.selected_camera_id
-        || app_state.is_recording_active_or_pending()
-    {
-        return;
-    }
-    if let Some(id) = app_state.selected_camera_id.clone()
-        && !app_state.camera_in_use
-    {
-        if let Err(error) = crate::permissions::check_camera_access() {
-            warn!(%error, "Camera preview requires permission before restoring input");
-            return;
-        }
-        let settings = crate::recording_settings::RecordingSettingsStore::camera_settings_for(
-            &app_state.handle,
-            &id,
-        );
-        match app_state
-            .camera_feed
-            .ask(feeds::camera::SetInput { id, settings })
-            .await
-        {
-            Ok(ready_future) => {
-                if let Err(err) = ready_future.await {
-                    error!("Camera failed to initialize: {err}");
-                    return;
-                }
-            }
-            Err(err) => {
-                error!("Failed to send SetInput to camera feed: {err}");
-                return;
-            }
-        }
-
-        requested.publish_camera_if_current(snapshot.camera.revision, || {
-            app_state.camera_in_use = true;
-            app_state.camera_cleanup_done = false;
-        });
-    }
-}
-
-pub(crate) async fn restore_main_window_inputs(app: &AppHandle) {
-    crate::restore_requested_inputs(app).await;
-}
-
-pub(crate) async fn cleanup_camera_window(
-    app: &AppHandle,
-    window: Option<&WebviewWindow>,
-    #[allow(unused_variables)] reset_panel: bool,
-    wait_for_removal: bool,
-) -> bool {
-    use crate::CameraWindowCloseGate;
-
-    #[cfg(target_os = "macos")]
-    if reset_panel {
-        let panel_manager = app.state::();
-        panel_manager.force_reset(PanelWindowType::Camera).await;
-    }
-
-    app.state::().set_allow_close(true);
-
-    #[cfg(target_os = "macos")]
-    {
-        let panel_labels = window
-            .map(|window| vec![window.label().to_string()])
-            .unwrap_or_else(|| camera_window_labels(app));
-        let (panel_close_tx, panel_close_rx) = tokio::sync::oneshot::channel();
-        let app_for_close = app.clone();
-        app.run_on_main_thread(move || {
-            use tauri_nspanel::ManagerExt;
-            for label in panel_labels {
-                if let Ok(panel) = app_for_close.get_webview_panel(&label) {
-                    panel.released_when_closed(false);
-                    panel.close();
-                }
-            }
-            let _ = panel_close_tx.send(());
-        })
-        .ok();
-        let _ = tokio::time::timeout(std::time::Duration::from_millis(500), panel_close_rx).await;
-    }
-
-    let windows = window
-        .cloned()
-        .map(|window| vec![window])
-        .unwrap_or_else(|| camera_webview_windows(app));
-    for window in windows {
-        let destroy_rx = destroy_camera_window_handle(app, window);
-        let _ = tokio::time::timeout(std::time::Duration::from_millis(500), destroy_rx).await;
-    }
-
-    if wait_for_removal {
-        let start = std::time::Instant::now();
-        let timeout = std::time::Duration::from_millis(2000);
-        while start.elapsed() < timeout && !camera_webview_windows(app).is_empty() {
-            tokio::time::sleep(std::time::Duration::from_millis(100)).await;
-        }
-    }
-
-    let still_exists = !camera_webview_windows(app).is_empty();
-    app.state::().set_allow_close(false);
-
-    !still_exists
-}
-
-struct CursorMonitorInfo {
-    x: f64,
-    y: f64,
-    width: f64,
-    height: f64,
-    // On Windows each monitor's "logical" rect is its physical rect divided by
-    // its own scale, so logical rects of mixed-DPI monitors overlap and tao's
-    // LogicalPosition conversion (which uses whatever monitor the window
-    // currently occupies) can land a window on the wrong monitor. Positioning
-    // must go through this monitor's own scale, as a physical position.
-    #[cfg(windows)]
-    scale: f64,
-}
-
-impl CursorMonitorInfo {
-    fn get() -> Self {
-        Self::from_display(&Display::get_containing_cursor().unwrap_or_else(Display::primary))
-    }
-
-    fn from_display(display: &Display) -> Self {
-        let bounds = display.raw_handle().logical_bounds();
-
-        #[cfg(windows)]
-        let scale = bounds
-            .as_ref()
-            .map(|b| b.size().width())
-            .filter(|width| *width > 0.0)
-            .and_then(|logical_width| {
-                display
-                    .physical_size()
-                    .map(|physical| physical.width() / logical_width)
-            })
-            .filter(|scale| scale.is_finite() && *scale > 0.0)
-            .unwrap_or(1.0);
-
-        let (x, y, width, height) = bounds
-            .map(|b| {
-                (
-                    b.position().x(),
-                    b.position().y(),
-                    b.size().width(),
-                    b.size().height(),
-                )
-            })
-            .unwrap_or((
-                0.0,
-                0.0,
-                DEFAULT_FALLBACK_DISPLAY_WIDTH,
-                DEFAULT_FALLBACK_DISPLAY_HEIGHT,
-            ));
-
-        Self {
-            x,
-            y,
-            width,
-            height,
-            #[cfg(windows)]
-            scale,
-        }
-    }
-
-    /// Converts a global-logical point on this monitor into a `Position` that
-    /// lands exactly there regardless of which monitor the window currently
-    /// occupies. Logical on macOS/Linux (a true global space there), physical
-    /// on Windows.
-    fn position(&self, x: f64, y: f64) -> tauri::Position {
-        #[cfg(windows)]
-        return tauri::Position::Physical(tauri::PhysicalPosition::new(
-            (x * self.scale).round() as i32,
-            (y * self.scale).round() as i32,
-        ));
-
-        #[cfg(not(windows))]
-        tauri::Position::Logical(tauri::LogicalPosition::new(x, y))
-    }
-
-    fn center_position(&self, window_width: f64, window_height: f64) -> (f64, f64) {
-        let pos_x = self.x + (self.width - window_width) / 2.0;
-        let pos_y = self.y + (self.height - window_height) / 2.0;
-        (pos_x, pos_y)
-    }
-
-    fn bottom_center_position(
-        &self,
-        window_width: f64,
-        window_height: f64,
-        offset_y: f64,
-    ) -> (f64, f64) {
-        let pos_x = self.x + (self.width - window_width) / 2.0;
-        let pos_y = self.y + self.height - window_height - offset_y;
-        (pos_x, pos_y)
-    }
-
-    fn from_window(window: &tauri::WebviewWindow) -> Self {
-        let Ok(window_pos) = window.outer_position() else {
-            return Self::get();
-        };
-
-        // outer_position is physical. On Windows, resolve the display in
-        // physical space (per-monitor logical rects overlap in mixed-DPI
-        // layouts). On macOS, convert to logical points, a true global space.
-        // On Linux scap reports logical bounds in unscaled physical units, so
-        // the raw position compares directly.
-        #[cfg(windows)]
-        {
-            let (pos_x, pos_y) = (window_pos.x as f64, window_pos.y as f64);
-            for display in Display::list() {
-                if let Some(bounds) = display.raw_handle().physical_bounds() {
-                    let (x, y, width, height) = (
-                        bounds.position().x(),
-                        bounds.position().y(),
-                        bounds.size().width(),
-                        bounds.size().height(),
-                    );
-
-                    if pos_x >= x && pos_x < x + width && pos_y >= y && pos_y < y + height {
-                        return Self::from_display(&display);
-                    }
-                }
-            }
-
-            Self::get()
-        }
-
-        #[cfg(target_os = "macos")]
-        {
-            let scale = window.scale_factor().unwrap_or(1.0);
-            let pos = window_pos.to_logical::(scale);
-
-            for display in Display::list() {
-                if display_contains_logical(&display, pos.x, pos.y) {
-                    return Self::from_display(&display);
-                }
-            }
-
-            Self::get()
-        }
-
-        #[cfg(target_os = "linux")]
-        {
-            let (pos_x, pos_y) = (window_pos.x as f64, window_pos.y as f64);
-
-            for display in Display::list() {
-                if display_contains_logical(&display, pos_x, pos_y) {
-                    return Self::from_display(&display);
-                }
-            }
-
-            Self::get()
-        }
-    }
-}
-
-fn display_contains_logical(display: &Display, pos_x: f64, pos_y: f64) -> bool {
-    display
-        .raw_handle()
-        .logical_bounds()
-        .map(|bounds| {
-            let (x, y, width, height) = (
-                bounds.position().x(),
-                bounds.position().y(),
-                bounds.size().width(),
-                bounds.size().height(),
-            );
-
-            pos_x >= x && pos_x < x + width && pos_y >= y && pos_y < y + height
-        })
-        .unwrap_or(false)
-}
-
-fn display_containing_logical(pos_x: f64, pos_y: f64) -> Option {
-    Display::list()
-        .into_iter()
-        .find(|display| display_contains_logical(display, pos_x, pos_y))
-}
-
-/// Resolves the display a persisted window position belongs to, preferring the
-/// display it was saved on. On Windows the saved logical coordinates are only
-/// meaningful relative to that display (mixed-DPI logical rects overlap), so
-/// restores must convert through its scale rather than the window's current one.
-fn display_for_saved_position(
-    pos_x: f64,
-    pos_y: f64,
-    display_id: Option<&DisplayId>,
-) -> Option {
-    display_id
-        .and_then(Display::from_id)
-        .filter(|display| display_contains_logical(display, pos_x, pos_y))
-        .or_else(|| display_containing_logical(pos_x, pos_y))
-}
-
-/// Converts a global-logical point into a `Position` that lands exactly there,
-/// resolving the owning display by containment when the caller doesn't know it.
-/// Falls back to a plain logical position when no display contains the point.
-pub fn logical_point_position(pos_x: f64, pos_y: f64) -> tauri::Position {
-    #[cfg(windows)]
-    if let Some(display) = display_containing_logical(pos_x, pos_y) {
-        return CursorMonitorInfo::from_display(&display).position(pos_x, pos_y);
-    }
-
-    tauri::Position::Logical(tauri::LogicalPosition::new(pos_x, pos_y))
-}
-
-fn center_camera_window(app: &AppHandle, window: &WebviewWindow) {
-    let camera_state = match app.try_state::>() {
-        Some(state) => state
-            .try_read()
-            .ok()
-            .and_then(|guard| guard.camera_preview.get_state().ok())
-            .unwrap_or_default(),
-        None => crate::camera::CameraPreviewState::default(),
-    };
-
-    let toolbar_height = 56.0;
-    let size = camera_state.size as f64;
-    let is_full = camera_state.shape == crate::camera::CameraPreviewShape::Full;
-    let aspect_ratio = crate::camera::WIDE_CAMERA_ASPECT_RATIO as f64;
-
-    let window_width = if is_full { size * aspect_ratio } else { size };
-    let window_height = size + toolbar_height;
-
-    let monitor_info = CursorMonitorInfo::get();
-    let (pos_x, pos_y) = monitor_info.center_position(window_width, window_height);
-
-    let _ = window.set_size(tauri::LogicalSize::new(window_width, window_height));
-    if let Some(guard) = app.try_state::() {
-        guard.ignore_for(1000);
-    }
-    let _ = window.set_position(monitor_info.position(pos_x, pos_y));
-
-    if let Some(state) = app.try_state::>()
-        && let Ok(guard) = state.try_read()
-    {
-        guard
-            .camera_preview
-            .notify_window_resized(window_width as u32, window_height as u32);
-    }
-}
-
-fn is_position_on_display(display_id: &DisplayId, pos_x: f64, pos_y: f64) -> bool {
-    Display::from_id(display_id)
-        .and_then(|display| display.raw_handle().logical_bounds())
-        .map(|bounds| {
-            let (x, y, width, height) = (
-                bounds.position().x(),
-                bounds.position().y(),
-                bounds.size().width(),
-                bounds.size().height(),
-            );
-
-            pos_x >= x && pos_x < x + width && pos_y >= y && pos_y < y + height
-        })
-        .unwrap_or(false)
-}
-
-fn display_name_for_position(pos_x: f64, pos_y: f64) -> Option {
-    Display::list().into_iter().find_map(|display| {
-        let bounds = display.raw_handle().logical_bounds()?;
-        let (x, y, width, height) = (
-            bounds.position().x(),
-            bounds.position().y(),
-            bounds.size().width(),
-            bounds.size().height(),
-        );
-
-        if pos_x >= x && pos_x < x + width && pos_y >= y && pos_y < y + height {
-            display.name().filter(|name| !name.trim().is_empty())
-        } else {
-            None
-        }
-    })
-}
-
-fn is_position_on_monitor_name(monitor_name: &str, pos_x: f64, pos_y: f64) -> bool {
-    Display::list().into_iter().any(|display| {
-        if display.name().as_deref() != Some(monitor_name) {
-            return false;
-        }
-
-        display
-            .raw_handle()
-            .logical_bounds()
-            .map(|bounds| {
-                let (x, y, width, height) = (
-                    bounds.position().x(),
-                    bounds.position().y(),
-                    bounds.size().width(),
-                    bounds.size().height(),
-                );
-
-                pos_x >= x && pos_x < x + width && pos_y >= y && pos_y < y + height
-            })
-            .unwrap_or(false)
-    })
-}
-
-fn is_position_on_any_screen(pos_x: f64, pos_y: f64) -> bool {
-    for display in Display::list() {
-        if let Some(bounds) = display.raw_handle().logical_bounds() {
-            let (x, y, width, height) = (
-                bounds.position().x(),
-                bounds.position().y(),
-                bounds.size().width(),
-                bounds.size().height(),
-            );
-
-            if pos_x >= x && pos_x < x + width && pos_y >= y && pos_y < y + height {
-                return true;
-            }
-        }
-    }
-    false
-}
-
-// Recovers a window that ended up entirely off every connected display (e.g. the
-// monitor it was on got disconnected), which otherwise leaves it open but unreachable.
-fn recenter_window_if_offscreen(window: &WebviewWindow) {
-    let Ok(position) = window.outer_position() else {
-        return;
-    };
-    let Ok(size) = window.outer_size() else {
-        return;
-    };
-    let scale = window.scale_factor().unwrap_or(1.0);
-
-    let on_screen = Display::list()
-        .iter()
-        .any(|display| display.intersects(position, size, scale));
-    if on_screen {
-        return;
-    }
-
-    let monitor = CursorMonitorInfo::get();
-    let (pos_x, pos_y) =
-        monitor.center_position(size.width as f64 / scale, size.height as f64 / scale);
-    let _ = window.set_position(monitor.position(pos_x, pos_y));
-}
-
-#[derive(Clone, Copy, Debug, PartialEq)]
-struct ContentWindowRect {
-    x: f64,
-    y: f64,
-    width: f64,
-    height: f64,
-}
-
-#[derive(Debug, PartialEq)]
-struct ContentWindowFit {
-    frame: ContentWindowRect,
-    inner: (f64, f64),
-    minimum: (f64, f64),
-}
-
-fn fit_content_window(
-    work_area: ContentWindowRect,
-    frame: ContentWindowRect,
-    inner: (f64, f64),
-    minimum: (f64, f64),
-    preferred: Option<(f64, f64)>,
-) -> Option {
-    let requested = preferred.unwrap_or(inner);
-    if ![work_area.x, work_area.y, frame.x, frame.y]
-        .into_iter()
-        .all(f64::is_finite)
-        || ![
-            work_area.width,
-            work_area.height,
-            frame.width,
-            frame.height,
-            inner.0,
-            inner.1,
-            minimum.0,
-            minimum.1,
-            requested.0,
-            requested.1,
-        ]
-        .into_iter()
-        .all(|value| value.is_finite() && value > 0.0)
-    {
-        return None;
-    }
-
-    let decoration = (
-        (frame.width - inner.0).max(0.0),
-        (frame.height - inner.1).max(0.0),
-    );
-    let available = (
-        work_area.width - 32.0 - decoration.0,
-        work_area.height - 32.0 - decoration.1,
-    );
-    if available.0 <= 0.0 || available.1 <= 0.0 {
-        return None;
-    }
-    let minimum = (minimum.0.min(available.0), minimum.1.min(available.1));
-    let inner = (
-        requested.0.clamp(minimum.0, available.0),
-        requested.1.clamp(minimum.1, available.1),
-    );
-    let width = inner.0 + decoration.0;
-    let height = inner.1 + decoration.1;
-    let left = work_area.x + 16.0;
-    let bottom = work_area.y + 16.0;
-    let right = (work_area.x + work_area.width - width - 16.0).max(left);
-    let top = (work_area.y + work_area.height - height - 16.0).max(bottom);
-    let (x, y) = if preferred.is_some() {
-        (
-            work_area.x + (work_area.width - width) / 2.0,
-            work_area.y + (work_area.height - height) / 2.0,
-        )
-    } else {
-        (frame.x.clamp(left, right), frame.y.clamp(bottom, top))
-    };
-    Some(ContentWindowFit {
-        frame: ContentWindowRect {
-            x,
-            y,
-            width,
-            height,
-        },
-        inner,
-        minimum,
-    })
-}
-
-fn monitor_work_area(monitor: &Monitor) -> Option<(ContentWindowRect, f64)> {
-    let scale = monitor.scale_factor();
-    let area = monitor.work_area();
-    Some((logical_work_area(area.position, area.size, scale)?, scale))
-}
-
-fn logical_work_area(
-    position: PhysicalPosition,
-    size: PhysicalSize,
-    scale: f64,
-) -> Option {
-    if !scale.is_finite() || scale <= 0.0 {
-        return None;
-    }
-    Some(ContentWindowRect {
-        x: position.x as f64 / scale,
-        y: position.y as f64 / scale,
-        width: size.width as f64 / scale,
-        height: size.height as f64 / scale,
-    })
-}
-
-fn initial_content_window_fit(
-    app: &AppHandle,
-    id: &CapWindowId,
-) -> Option<(ContentWindowFit, f64)> {
-    let preferred = id.preferred_content_size()?;
-    let monitor = app
-        .cursor_position()
-        .ok()
-        .and_then(|position| {
-            app.monitor_from_point(position.x, position.y)
-                .ok()
-                .flatten()
-        })
-        .or_else(|| app.primary_monitor().ok().flatten())?;
-    let (area, scale) = monitor_work_area(&monitor)?;
-    let frame = ContentWindowRect {
-        width: preferred.0,
-        height: preferred.1,
-        ..area
-    };
-    Some((
-        fit_content_window(area, frame, preferred, id.min_size()?, Some(preferred))?,
-        scale,
-    ))
-}
-
-async fn fit_content_window_bounds(window: &WebviewWindow, id: &CapWindowId, initial: bool) {
-    let Some(preferred) = id.preferred_content_size() else {
-        return;
-    };
-    let Some(minimum) = id.min_size() else {
-        return;
-    };
-    if window.is_maximized().unwrap_or(false) || window.is_fullscreen().unwrap_or(false) {
-        return;
-    }
-    #[cfg(target_os = "macos")]
-    {
-        let (tx, rx) = tokio::sync::oneshot::channel();
-        let result = window.run_on_main_thread({
-            let window = window.clone();
-            move || {
-                if tx.is_closed() {
-                    return;
-                }
-                let result =
-                    fit_macos_content_window(&window, minimum, initial.then_some(preferred));
-                let _ = tx.send(result);
-            }
-        });
-        if let Err(error) = result {
-            warn!(%error, "Failed to schedule content window bounds update");
-        } else if let Err(error) =
-            await_window_operation(rx, "Content window bounds update", Duration::from_secs(5)).await
-        {
-            warn!(%error, "Failed to fit content window bounds");
-        }
-    }
-    #[cfg(not(target_os = "macos"))]
-    {
-        let initial_monitor = initial
-            .then(|| {
-                window
-                    .app_handle()
-                    .cursor_position()
-                    .ok()
-                    .and_then(|position| {
-                        window
-                            .monitor_from_point(position.x, position.y)
-                            .ok()
-                            .flatten()
-                    })
-            })
-            .flatten();
-        let Some((area, scale)) = initial_monitor
-            .or_else(|| window.current_monitor().ok().flatten())
-            .or_else(|| window.primary_monitor().ok().flatten())
-            .as_ref()
-            .and_then(monitor_work_area)
-        else {
-            return;
-        };
-        let (Ok(position), Ok(outer), Ok(inner), Ok(current_scale)) = (
-            window.outer_position(),
-            window.outer_size(),
-            window.inner_size(),
-            window.scale_factor(),
-        ) else {
-            return;
-        };
-        if !current_scale.is_finite() || current_scale <= 0.0 {
-            return;
-        }
-        let frame = ContentWindowRect {
-            x: position.x as f64 / current_scale,
-            y: position.y as f64 / current_scale,
-            width: outer.width as f64 / current_scale,
-            height: outer.height as f64 / current_scale,
-        };
-        let Some(fit) = fit_content_window(
-            area,
-            frame,
-            (
-                inner.width as f64 / current_scale,
-                inner.height as f64 / current_scale,
-            ),
-            minimum,
-            initial.then_some(preferred),
-        ) else {
-            return;
-        };
-        let _ = window.set_min_size(Some(LogicalSize::new(fit.minimum.0, fit.minimum.1)));
-        #[cfg(windows)]
-        {
-            let _ = window.set_position(PhysicalPosition::new(
-                (fit.frame.x * scale).round() as i32,
-                (fit.frame.y * scale).round() as i32,
-            ));
-            let _ = window.set_size(PhysicalSize::new(
-                (fit.inner.0 * scale).round() as u32,
-                (fit.inner.1 * scale).round() as u32,
-            ));
-        }
-        #[cfg(target_os = "linux")]
-        {
-            let _ = scale;
-            let _ = window.set_size(LogicalSize::new(fit.inner.0, fit.inner.1));
-            let _ = window.set_position(LogicalPosition::new(fit.frame.x, fit.frame.y));
-        }
-    }
-}
-
-#[cfg(target_os = "macos")]
-fn fit_macos_content_window(
-    window: &WebviewWindow,
-    minimum: (f64, f64),
-    preferred: Option<(f64, f64)>,
-) -> Result<(), String> {
-    use objc2::{MainThreadMarker, runtime::NSObjectProtocol, sel};
-    use objc2_app_kit::{NSEvent, NSScreen, NSWindow};
-    use objc2_foundation::{NSPoint, NSRect, NSSize};
-
-    let main_thread = MainThreadMarker::new().ok_or("Window bounds require the main thread")?;
-    let native = window.ns_window().map_err(|error| error.to_string())? as *const NSWindow;
-    let native = unsafe { native.as_ref() }.ok_or("Content window is unavailable")?;
-    let cursor_screen = preferred.and_then(|_| {
-        let cursor = unsafe { NSEvent::mouseLocation() };
-        NSScreen::screens(main_thread).iter().find(|screen| {
-            let frame = screen.frame();
-            cursor.x >= frame.origin.x
-                && cursor.x < frame.origin.x + frame.size.width
-                && cursor.y >= frame.origin.y
-                && cursor.y < frame.origin.y + frame.size.height
-        })
-    });
-    let screen = cursor_screen
-        .or_else(|| native.screen())
-        .or_else(|| NSScreen::mainScreen(main_thread))
-        .ok_or("Content window screen is unavailable")?;
-    let visible = screen.visibleFrame();
-    let screen_frame = screen.frame();
-    let safe_top = if screen.respondsToSelector(sel!(safeAreaInsets)) {
-        unsafe { screen.safeAreaInsets().top }
-    } else {
-        0.0
-    };
-    let top = (visible.origin.y + visible.size.height)
-        .min(screen_frame.origin.y + screen_frame.size.height - safe_top);
-    let area = ContentWindowRect {
-        x: visible.origin.x,
-        y: visible.origin.y,
-        width: visible.size.width,
-        height: top - visible.origin.y,
-    };
-    let frame = native.frame();
-    let content = native
-        .contentView()
-        .ok_or("Content view is unavailable")?
-        .frame();
-    let Some(fit) = fit_content_window(
-        area,
-        ContentWindowRect {
-            x: frame.origin.x,
-            y: frame.origin.y,
-            width: frame.size.width,
-            height: frame.size.height,
-        },
-        (content.size.width, content.size.height),
-        minimum,
-        preferred,
-    ) else {
-        return Ok(());
-    };
-    native.setMinSize(NSSize::new(
-        fit.minimum.0 + fit.frame.width - fit.inner.0,
-        fit.minimum.1 + fit.frame.height - fit.inner.1,
-    ));
-    native.setFrame_display(
-        NSRect::new(
-            NSPoint::new(fit.frame.x, fit.frame.y),
-            NSSize::new(fit.frame.width, fit.frame.height),
-        ),
-        true,
-    );
-    Ok(())
-}
-
-#[cfg(any(target_os = "macos", test))]
-async fn await_window_operation(
-    receiver: tokio::sync::oneshot::Receiver>,
-    operation: &str,
-    timeout: Duration,
-) -> Result<(), String> {
-    tokio::time::timeout(timeout, receiver)
-        .await
-        .map_err(|_| format!("{operation} timed out"))?
-        .map_err(|_| format!("{operation} was cancelled"))?
-}
-
-#[cfg(target_os = "macos")]
-struct PendingControlsWindow(Option);
-
-#[cfg(target_os = "macos")]
-impl Drop for PendingControlsWindow {
-    fn drop(&mut self) {
-        if let Some(window) = self.0.take() {
-            let _ = window.destroy();
-        }
-    }
-}
-
-#[derive(Clone, Deserialize, Type)]
-pub enum CapWindowId {
-    Main,
-    Settings,
-    Editor { id: u32 },
-    RecordingsOverlay,
-    WindowCaptureOccluder { screen_id: DisplayId },
-    TargetSelectOverlay { display_id: DisplayId },
-    CaptureArea,
-    Camera,
-    RecordingControls,
-    Upgrade,
-    ModeSelect,
-    Debug,
-    ScreenshotEditor { id: u32 },
-    Onboarding,
-    Teleprompter,
-}
-
-impl FromStr for CapWindowId {
-    type Err = String;
-
-    fn from_str(s: &str) -> Result {
-        Ok(match s {
-            "main" => Self::Main,
-            "settings" => Self::Settings,
-            s if is_camera_window_label(s) => Self::Camera,
-            "capture-area" => Self::CaptureArea,
-            // legacy identifier
-            "in-progress-recording" => Self::RecordingControls,
-            "recordings-overlay" => Self::RecordingsOverlay,
-            "upgrade" => Self::Upgrade,
-            "mode-select" => Self::ModeSelect,
-            "debug" => Self::Debug,
-            "onboarding" => Self::Onboarding,
-            "teleprompter" => Self::Teleprompter,
-            s if s.starts_with("editor-") => Self::Editor {
-                id: s
-                    .replace("editor-", "")
-                    .parse::()
-                    .map_err(|e| e.to_string())?,
-            },
-            s if s.starts_with("screenshot-editor-") => Self::ScreenshotEditor {
-                id: s
-                    .replace("screenshot-editor-", "")
-                    .parse::()
-                    .map_err(|e| e.to_string())?,
-            },
-            s if s.starts_with("window-capture-occluder-") => Self::WindowCaptureOccluder {
-                screen_id: s
-                    .replace("window-capture-occluder-", "")
-                    .parse::()
-                    .map_err(|e| e.to_string())?,
-            },
-            s if s.starts_with("target-select-overlay-") => Self::TargetSelectOverlay {
-                display_id: s
-                    .replace("target-select-overlay-", "")
-                    .parse::()
-                    .map_err(|e| e.to_string())?,
-            },
-            _ => return Err(format!("unknown window label: {s}")),
-        })
-    }
-}
-
-impl std::fmt::Display for CapWindowId {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            Self::Main => write!(f, "main"),
-            Self::Settings => write!(f, "settings"),
-            Self::Camera => write!(f, "camera"),
-            Self::WindowCaptureOccluder { screen_id } => {
-                write!(f, "window-capture-occluder-{screen_id}")
-            }
-            Self::CaptureArea => write!(f, "capture-area"),
-            Self::TargetSelectOverlay { display_id } => {
-                write!(f, "target-select-overlay-{display_id}")
-            }
-            Self::RecordingControls => write!(f, "in-progress-recording"), // legacy identifier
-            Self::RecordingsOverlay => write!(f, "recordings-overlay"),
-            Self::Upgrade => write!(f, "upgrade"),
-            Self::ModeSelect => write!(f, "mode-select"),
-            Self::Editor { id } => write!(f, "editor-{id}"),
-            Self::Debug => write!(f, "debug"),
-            Self::ScreenshotEditor { id } => write!(f, "screenshot-editor-{id}"),
-            Self::Onboarding => write!(f, "onboarding"),
-            Self::Teleprompter => write!(f, "teleprompter"),
-        }
-    }
-}
-
-impl CapWindowId {
-    fn preferred_content_size(&self) -> Option<(f64, f64)> {
-        match self {
-            Self::Settings => Some((782.0, 775.0)),
-            Self::Editor { .. } => Some((1275.0, 800.0)),
-            Self::ScreenshotEditor { .. } => Some((1240.0, 800.0)),
-            _ => None,
-        }
-    }
-    pub fn label(&self) -> String {
-        self.to_string()
-    }
-
-    pub fn title(&self) -> String {
-        match self {
-            Self::Settings => "Cap Settings".to_string(),
-            Self::WindowCaptureOccluder { .. } => "Cap Window Capture Occluder".to_string(),
-            Self::CaptureArea => "Cap Capture Area".to_string(),
-            Self::RecordingControls => "Cap Recording Controls".to_string(),
-            Self::Editor { .. } => "Cap Editor".to_string(),
-            Self::ScreenshotEditor { .. } => "Cap Screenshot Editor".to_string(),
-            Self::ModeSelect => "Cap Mode Selection".to_string(),
-            Self::Onboarding => "Welcome to Cap".to_string(),
-            Self::Camera => "Cap Camera".to_string(),
-            Self::RecordingsOverlay => "Cap Recordings Overlay".to_string(),
-            Self::TargetSelectOverlay { .. } => "Cap Target Select".to_string(),
-            Self::Teleprompter => "Cap Teleprompter".to_string(),
-            _ => "Cap".to_string(),
-        }
-    }
-
-    #[cfg(target_os = "macos")]
-    pub fn activates_dock(&self) -> bool {
-        matches!(
-            self,
-            Self::Main
-                | Self::Editor { .. }
-                | Self::ScreenshotEditor { .. }
-                | Self::Settings
-                | Self::Upgrade
-                | Self::ModeSelect
-                | Self::Onboarding
-        )
-    }
-
-    pub fn is_transparent(&self) -> bool {
-        if matches!(self, Self::Settings) {
-            return cfg!(target_os = "macos");
-        }
-
-        matches!(
-            self,
-            Self::Main
-                | Self::Onboarding
-                | Self::Camera
-                | Self::WindowCaptureOccluder { .. }
-                | Self::CaptureArea
-                | Self::RecordingControls
-                | Self::RecordingsOverlay
-                | Self::TargetSelectOverlay { .. }
-        )
-    }
-
-    pub fn get(&self, app: &AppHandle) -> Option {
-        if matches!(self, Self::Camera) {
-            return current_camera_window(app);
-        }
-
-        let label = self.label();
-        app.get_webview_window(&label)
-    }
-
-    #[cfg(target_os = "macos")]
-    pub fn traffic_lights_position(&self) -> Option>> {
-        match self {
-            Self::Editor { .. } | Self::ScreenshotEditor { .. } => {
-                Some(Some(LogicalPosition::new(20.0, 32.0)))
-            }
-            Self::Camera
-            | Self::Main
-            | Self::Onboarding
-            | Self::WindowCaptureOccluder { .. }
-            | Self::CaptureArea
-            | Self::RecordingsOverlay
-            | Self::RecordingControls
-            | Self::TargetSelectOverlay { .. } => None,
-            Self::Settings => Some(Some(LogicalPosition::new(22.0, 22.0))),
-            Self::Teleprompter => Some(Some(LogicalPosition::new(14.0, 14.0))),
-            _ => Some(None),
-        }
-    }
-
-    pub fn min_size(&self) -> Option<(f64, f64)> {
-        Some(match self {
-            Self::Main => crate::main_window_geometry::SIZE,
-            Self::Editor { .. } => (1275.0, 800.0),
-            Self::ScreenshotEditor { .. } => (800.0, 600.0),
-            Self::Settings => (780.0, 560.0),
-            Self::Camera => (200.0, 200.0),
-            Self::Upgrade => (950.0, 850.0),
-            Self::ModeSelect => (580.0, 340.0),
-            Self::Onboarding => (860.0, 690.0),
-            _ => return None,
-        })
-    }
-}
-
-#[derive(Debug, Clone, Type, Deserialize)]
-pub enum ShowCapWindow {
-    Main {
-        init_target_mode: Option,
-    },
-    Settings {
-        page: Option,
-    },
-    Editor {
-        project_path: PathBuf,
-    },
-    RecordingsOverlay,
-    WindowCaptureOccluder {
-        screen_id: DisplayId,
-    },
-    TargetSelectOverlay {
-        display_id: DisplayId,
-        target_mode: Option,
-    },
-    CaptureArea {
-        screen_id: DisplayId,
-    },
-    Camera {
-        centered: bool,
-    },
-    InProgressRecording {
-        countdown: Option,
-        #[serde(default)]
-        capture_target: Option,
-    },
-    Upgrade,
-    ModeSelect,
-    ScreenshotEditor {
-        path: PathBuf,
-    },
-    Onboarding,
-}
-
-impl ShowCapWindow {
-    pub fn show<'a>(
-        &'a self,
-        app: &'a AppHandle,
-    ) -> futures::future::BoxFuture<'a, tauri::Result> {
-        let picker_session = matches!(self, Self::TargetSelectOverlay { .. })
-            .then(|| app.state::().picker_session())
-            .flatten();
-        Box::pin(self.show_inner(app, picker_session))
-    }
-
-    pub(crate) fn show_for_picker<'a>(
-        &'a self,
-        app: &'a AppHandle,
-        session: u32,
-    ) -> futures::future::BoxFuture<'a, tauri::Result> {
-        Box::pin(self.show_inner(app, Some(session)))
-    }
-
-    async fn show_inner(
-        &self,
-        app: &AppHandle,
-        picker_session: Option,
-    ) -> tauri::Result {
-        let picker = app.state::();
-        let _picker_creation = if matches!(self, Self::TargetSelectOverlay { .. }) {
-            let guard = picker.creation.lock().await;
-            if picker_session.is_none_or(|session| !picker.picker_is_current(session)) {
-                return Err(tauri::Error::WindowNotFound);
-            }
-            Some(guard)
-        } else {
-            None
-        };
-        let reveal_generation = crate::clean_capture::generation(app);
-        if matches!(self, Self::Main { .. }) && crate::clean_capture::phase(app).is_some() {
-            crate::clean_capture::show_main_controls(app)
-                .await
-                .map_err(|error| tauri::Error::Io(std::io::Error::other(error)))?;
-        }
-        #[cfg(target_os = "linux")]
-        crate::clean_capture::admit_wayland_window_creation(app)
-            .map_err(|error| tauri::Error::Io(std::io::Error::other(error)))?;
-        let mut project_opening = match self {
-            Self::Editor { project_path } => {
-                let state = app.state::();
-                Some(
-                    ProjectWindowOpening::acquire(
-                        app,
-                        project_path,
-                        state.ids.clone(),
-                        &state.counter,
-                        &state.open_gates,
-                        |id| CapWindowId::Editor { id },
-                    )
-                    .await?,
-                )
-            }
-            Self::ScreenshotEditor { path } => {
-                let state = app.state::();
-                Some(
-                    ProjectWindowOpening::acquire(
-                        app,
-                        path,
-                        state.ids.clone(),
-                        &state.counter,
-                        &state.open_gates,
-                        |id| CapWindowId::ScreenshotEditor { id },
-                    )
-                    .await?,
-                )
-            }
-            _ => None,
-        };
-        let window_id = project_opening
-            .as_ref()
-            .map(|opening| opening.id.clone())
-            .unwrap_or_else(|| self.id(app));
-
-        let camera_window_label = if matches!(self, Self::Camera { .. }) {
-            Some(camera_window_label_for_session(bump_camera_window_session(
-                app,
-            )))
-        } else {
-            None
-        };
-
-        if let Self::Camera { centered } = self {
-            #[cfg(target_os = "macos")]
-            {
-                let panel_manager = app.state::();
-                let mut panel_state = panel_manager.get_state(PanelWindowType::Camera).await;
-
-                if panel_state == PanelState::Destroying {
-                    debug!("Camera window is being destroyed, waiting...");
-                    let wait_result = panel_manager
-                        .wait_for_state(
-                            PanelWindowType::Camera,
-                            &[PanelState::None],
-                            std::time::Duration::from_millis(500),
-                        )
-                        .await;
-
-                    if !wait_result {
-                        warn!("Camera destroy wait timed out, force resetting state");
-                        panel_manager.force_reset(PanelWindowType::Camera).await;
-                    }
-                    panel_state = panel_manager.get_state(PanelWindowType::Camera).await;
-                }
-
-                if panel_state == PanelState::Creating {
-                    debug!("Camera window is being created, waiting...");
-                    panel_manager
-                        .wait_for_state(
-                            PanelWindowType::Camera,
-                            &[PanelState::Ready],
-                            std::time::Duration::from_millis(500),
-                        )
-                        .await;
-                }
-            }
-
-            if let Some(window) = self.id(app).get(app) {
-                if crate::clean_capture::phase(app)
-                    .is_some_and(|phase| phase != crate::clean_capture::Phase::Restoring)
-                {
-                    return Ok(window);
-                }
-                #[cfg(target_os = "macos")]
-                {
-                    use crate::panel_manager::is_window_handle_valid;
-
-                    let handle_valid = is_window_handle_valid(&window);
-
-                    if !handle_valid {
-                        warn!(
-                            "Camera window exists but handle is invalid, destroying and recreating..."
-                        );
-                        let cleanup_success =
-                            cleanup_camera_window(app, Some(&window), true, true).await;
-                        if !cleanup_success {
-                            warn!(
-                                "Camera window still in registry after cleanup attempts, will retry later"
-                            );
-                            return Err(tauri::Error::WindowNotFound);
-                        }
-                        debug!("Camera window successfully removed from registry");
-                    } else {
-                        let panel_manager = app.state::();
-                        let mut panel_state =
-                            panel_manager.get_state(PanelWindowType::Camera).await;
-
-                        if panel_state == PanelState::Creating {
-                            debug!(
-                                "Camera window valid but state is Creating, waiting for completion"
-                            );
-                            panel_manager
-                                .wait_for_state(
-                                    PanelWindowType::Camera,
-                                    &[PanelState::Ready, PanelState::None],
-                                    std::time::Duration::from_millis(1000),
-                                )
-                                .await;
-                            panel_state = panel_manager.get_state(PanelWindowType::Camera).await;
-                        }
-
-                        if panel_state != PanelState::Ready {
-                            debug!(
-                                "Camera window exists but panel state is {:?}, updating to Ready",
-                                panel_state
-                            );
-                            panel_manager.force_reset(PanelWindowType::Camera).await;
-                            panel_manager.mark_ready(PanelWindowType::Camera, 0).await;
-                        }
-
-                        let Some(state) = app.try_state::>() else {
-                            warn!("App state unavailable while showing camera window");
-                            return Err(tauri::Error::WindowNotFound);
-                        };
-                        let mut app_state = state.write().await;
-
-                        let enable_native_camera_preview =
-                            GeneralSettingsStore::native_camera_preview_enabled(app);
-
-                        let shutdown_preview = if !enable_native_camera_preview {
-                            app_state.camera_preview.begin_shutdown()
-                        } else {
-                            None
-                        };
-
-                        ensure_camera_input_active(&mut app_state).await;
-
-                        if enable_native_camera_preview
-                            && let Err(err) =
-                                init_native_camera_preview(&mut app_state, window.clone()).await
-                        {
-                            error!(
-                                "Error reinitializing camera preview for existing window: {err}"
-                            );
-                        }
-
-                        drop(app_state);
-
-                        if let Some(rx) = shutdown_preview {
-                            let _ = tokio::time::timeout(Duration::from_millis(500), rx).await;
-                        }
-
-                        let (show_tx, show_rx) = tokio::sync::oneshot::channel();
-                        app.run_on_main_thread({
-                            let window = window.clone();
-                            move || {
-                                use crate::panel_manager::try_to_panel;
-
-                                // IMPORTANT: We intentionally use window.show() + set_focus() here
-                                // instead of panel.order_front_regardless().
-                                //
-                                // order_front_regardless() was found to cause a crash after ~4-5
-                                // camera toggle cycles due to macOS internal state accumulation.
-                                // The crash manifested as a hard crash in the Metal/CAMetalLayer
-                                // subsystem, not in our Rust code.
-                                //
-                                // Using standard Tauri window APIs avoids this macOS-specific issue
-                                // while still properly showing and focusing the camera preview window.
-                                let _ = window.show();
-                                let _ = window.set_focus();
-                                let _ = show_tx.send(true);
-                            }
-                        })
-                        .ok();
-
-                        let show_result = show_rx.await.unwrap_or(false);
-
-                        if show_result {
-                            if *centered {
-                                center_camera_window(app, &window);
-                            }
-                            return Ok(window);
-                        } else {
-                            warn!("Camera panel show failed, will recreate window");
-                            let cleanup_success =
-                                cleanup_camera_window(app, Some(&window), true, true).await;
-                            if !cleanup_success {
-                                warn!(
-                                    "Camera window still in registry after show failure, will retry later"
-                                );
-                                return Err(tauri::Error::WindowNotFound);
-                            }
-                            debug!("Camera window successfully removed after show failure");
-                        }
-                    }
-                }
-
-                #[cfg(not(target_os = "macos"))]
-                {
-                    let Some(state) = app.try_state::>() else {
-                        warn!("App state unavailable while showing camera window");
-                        return Err(tauri::Error::WindowNotFound);
-                    };
-                    let mut app_state = state.write().await;
-
-                    let enable_native_camera_preview =
-                        GeneralSettingsStore::native_camera_preview_enabled(app);
-
-                    let shutdown_preview = if !enable_native_camera_preview {
-                        app_state.camera_preview.begin_shutdown()
-                    } else {
-                        None
-                    };
-
-                    ensure_camera_input_active(&mut app_state).await;
-
-                    if enable_native_camera_preview
-                        && let Err(err) =
-                            init_native_camera_preview(&mut app_state, window.clone()).await
-                    {
-                        error!("Error reinitializing camera preview for existing window: {err}");
-                    }
-
-                    drop(app_state);
-
-                    if let Some(rx) = shutdown_preview {
-                        let _ = tokio::time::timeout(Duration::from_millis(500), rx).await;
-                    }
-
-                    if *centered {
-                        center_camera_window(app, &window);
-                    }
-                    crate::clean_capture::guarded_show(
-                        window.clone(),
-                        reveal_generation,
-                        true,
-                        false,
-                    )
-                    .await?;
-                    return Ok(window);
-                }
-            }
-        }
-
-        if matches!(self, Self::Settings { .. }) {
-            hide_recording_windows(app, true);
-            release_camera_preview_if_idle(app);
-        }
-
-        #[cfg(target_os = "macos")]
-        if let Self::InProgressRecording { capture_target, .. } = self
-            && let Some(window) = self.id(app).get(app)
-        {
-            use crate::panel_manager::is_window_handle_valid;
-
-            if is_window_handle_valid(&window) {
-                debug!("InProgressRecording: reusing existing window");
-                let width = 320.0;
-                let height = 150.0;
-                let (pos_x, pos_y) = capture_target
-                    .as_ref()
-                    .and_then(fake_window::calculate_recording_controls_position_for_target)
-                    .unwrap_or_else(|| {
-                        CursorMonitorInfo::get().bottom_center_position(width, height, 120.0)
-                    });
-                let _ = window.set_position(tauri::LogicalPosition::new(pos_x, pos_y));
-
-                let label = window.label().to_string();
-                let (show_tx, show_rx) = tokio::sync::oneshot::channel();
-                app.run_on_main_thread({
-                    let app = app.clone();
-                    move || {
-                        if show_tx.is_closed() {
-                            return;
-                        }
-                        use tauri_nspanel::ManagerExt;
-                        let result = app
-                            .get_webview_panel(&label)
-                            .map(|panel| {
-                                panel.order_front_regardless();
-                                panel.show();
-                            })
-                            .map_err(|error| {
-                                format!("Recording controls panel is unavailable: {error:?}")
-                            });
-                        let _ = show_tx.send(result);
-                    }
-                })?;
-                await_window_operation(
-                    show_rx,
-                    "Showing recording controls",
-                    Duration::from_secs(5),
-                )
-                .await
-                .map_err(|error| tauri::Error::Anyhow(anyhow!(error)))?;
-                fake_window::spawn_fake_window_listener(app.clone(), window.clone());
-                return Ok(window);
-            } else {
-                warn!("InProgressRecording window handle invalid, destroying and recreating...");
-                let _ = window.destroy();
-
-                let window_id = self.id(app);
-                let max_wait = std::time::Duration::from_millis(500);
-                let poll_interval = std::time::Duration::from_millis(25);
-                let start = std::time::Instant::now();
-                while start.elapsed() < max_wait {
-                    if window_id.get(app).is_none() {
-                        debug!(
-                            "InProgressRecording window removed from registry after {:?}",
-                            start.elapsed()
-                        );
-                        break;
-                    }
-                    tokio::time::sleep(poll_interval).await;
-                }
-
-                if window_id.get(app).is_some() {
-                    error!("InProgressRecording window STILL in registry, cannot recreate");
-                    return Err(tauri::Error::WindowNotFound);
-                }
-                debug!("InProgressRecording window cleaned up, will recreate");
-            }
-        }
-
-        #[cfg(not(target_os = "macos"))]
-        if let Self::InProgressRecording { capture_target, .. } = self
-            && let Some(window) = self.id(app).get(app)
-        {
-            let width = 320.0;
-            let height = 150.0;
-            let (pos_x, pos_y) = capture_target
-                .as_ref()
-                .and_then(fake_window::calculate_recording_controls_position_for_target)
-                .unwrap_or_else(|| {
-                    CursorMonitorInfo::get().bottom_center_position(width, height, 120.0)
-                });
-            let _ = window.set_position(logical_point_position(pos_x, pos_y));
-            crate::clean_capture::guarded_show(window.clone(), reveal_generation, true, false)
-                .await?;
-            fake_window::spawn_fake_window_listener(app.clone(), window.clone());
-            return Ok(window);
-        }
-
-        let existing_window = match project_opening.as_ref() {
-            Some(opening) => opening.existing_window.clone(),
-            None if !matches!(self, Self::Camera { .. } | Self::InProgressRecording { .. }) => {
-                window_id.get(app)
-            }
-            None => None,
-        };
-        if !matches!(self, Self::Camera { .. } | Self::InProgressRecording { .. })
-            && let Some(window) = existing_window
-        {
-            if let Some(session) = picker_session {
-                crate::target_select_overlay::request_overlay_reveal(&window, session, false);
-                return Ok(window);
-            }
-            if matches!(self, Self::WindowCaptureOccluder { .. })
-                && let Err(error) = window.set_ignore_cursor_events(true)
-            {
-                hide_overlay(&window);
-                let _ = window.destroy();
-                return Err(error);
-            }
-            if matches!(self, Self::Main { .. }) && crate::should_show_onboarding(app) {
-                return Box::pin(Self::Onboarding.show(app)).await;
-            }
-
-            #[cfg(target_os = "macos")]
-            if matches!(self, Self::Main { .. }) && !app.state::().is_ready()
-            {
-                return Ok(window);
-            }
-
-            let cursor_display_id = if let Self::Main { init_target_mode } = self {
-                if init_target_mode.is_some() {
-                    Display::get_containing_cursor()
-                        .map(|d| d.id().to_string())
-                        .or_else(|| Some(Display::primary().id().to_string()))
-                } else {
-                    None
-                }
-            } else {
-                None
-            };
-
-            if let Self::Main {
-                init_target_mode: Some(target_mode),
-            } = self
-            {
-                crate::hide_main_window(app);
-                emit_app_event(
-                    app,
-                    RequestSetTargetMode {
-                        target_mode: Some(*target_mode),
-                        display_id: cursor_display_id,
-                    },
-                );
-            } else {
-                let should_restore_main_window_inputs = matches!(self, Self::Main { .. });
-
-                if let Self::Onboarding = self {
-                    let _ = window.set_ignore_cursor_events(false);
-                }
-
-                if matches!(self, Self::Main { .. }) {
-                    recenter_window_if_offscreen(&window);
-                }
-                fit_content_window_bounds(&window, &window_id, false).await;
-
-                crate::clean_capture::guarded_show(window.clone(), reveal_generation, true, true)
-                    .await?;
-
-                if let Self::Main { init_target_mode } = self {
-                    emit_app_event(
-                        app,
-                        RequestSetTargetMode {
-                            target_mode: *init_target_mode,
-                            display_id: cursor_display_id,
-                        },
-                    );
-                }
-
-                if should_restore_main_window_inputs {
-                    let app = app.clone();
-                    tokio::spawn(async move {
-                        restore_main_window_inputs(&app).await;
-                    });
-                }
-            }
-
-            #[cfg(target_os = "macos")]
-            if window_id.activates_dock() {
-                crate::permissions::sync_macos_dock_visibility(app);
-            }
-
-            return Ok(window);
-        }
-
-        let _id = window_id;
-        let cursor_monitor = CursorMonitorInfo::get();
-
-        let window = match self {
-            Self::Main { init_target_mode } => {
-                if !permissions::do_permissions_check(false).necessary_granted() {
-                    return Box::pin(Self::Onboarding.show(app)).await;
-                }
-
-                let title = CapWindowId::Main.title();
-                let should_protect = should_protect_window(app, &title);
-
-                #[cfg(target_os = "macos")]
-                let panel_activation_guard = permissions::prepare_macos_panel_window(app);
-
-                let window = self
-                    .window_builder(app, "/")
-                    .resizable(false)
-                    .maximized(false)
-                    .maximizable(false)
-                    .minimizable(false)
-                    .always_on_top(true)
-                    .visible_on_all_workspaces(true)
-                    .content_protected(should_protect)
-                    .transparent(true)
-                    .visible(false)
-                    .initialization_script(format!(
-                        "
-                        window.__CAP__ = window.__CAP__ ?? {{}};
-                        window.__CAP__.initialTargetMode = {}
-                    ",
-                        serde_json::to_string(init_target_mode)
-                            .expect("Failed to serialize initial target mode")
-                    ))
-                    .build()?;
-                lock_window_text_scale(&window);
-
-                let saved_position = GeneralSettingsStore::get(app)
-                    .ok()
-                    .flatten()
-                    .and_then(|s| s.main_window_position)
-                    .filter(|pos| is_position_on_any_screen(pos.x, pos.y));
-
-                let main_position = if let Some(pos) = saved_position {
-                    match display_for_saved_position(pos.x, pos.y, pos.display_id.as_ref()) {
-                        Some(display) => {
-                            CursorMonitorInfo::from_display(&display).position(pos.x, pos.y)
-                        }
-                        None => tauri::Position::Logical(tauri::LogicalPosition::new(pos.x, pos.y)),
-                    }
-                } else {
-                    let (pos_x, pos_y) = cursor_monitor.center_position(330.0, 395.0);
-                    cursor_monitor.position(pos_x, pos_y)
-                };
-
-                #[cfg(target_os = "macos")]
-                {
-                    app.run_on_main_thread({
-                        let window = window.clone();
-                        let app = app.clone();
-                        let panel_activation_guard = panel_activation_guard;
-                        move || {
-                            let _panel_activation_guard = panel_activation_guard;
-                            use tauri_nspanel::cocoa::appkit::NSWindowCollectionBehavior;
-                            use crate::panel_manager::try_to_panel;
-
-                            // Tao's delegate carries the native events from queued AppKit resizes.
-                            let panel = match try_to_panel(&window) {
-                                Ok(p) => p,
-                                Err(e) => {
-                                    tracing::error!("Failed to convert main window to panel: {}", e);
-                                    crate::permissions::sync_macos_dock_visibility(&app);
-                                    return;
-                                }
-                            };
-
-                            panel.set_collection_behaviour(
-                                NSWindowCollectionBehavior::NSWindowCollectionBehaviorCanJoinAllSpaces
-                                    | NSWindowCollectionBehavior::NSWindowCollectionBehaviorFullScreenPrimary,
-                            );
-
-                            let resized_window = window.clone();
-                            window.on_window_event(move |event| {
-                                if matches!(event, tauri::WindowEvent::Resized(_) | tauri::WindowEvent::ScaleFactorChanged { .. })
-                                    && let Err(error) = crate::platform::constrain_main_window_to_visible_frame(
-                                        &resized_window.as_ref().window(),
-                                    )
-                                {
-                                    warn!(%error, "Failed to fit resized Main window to its visible screen area");
-                                }
-                            });
-
-                            let _ = window.set_position(main_position);
-
-                            crate::platform::apply_squircle_corners(&window, 16.0);
-
-                            crate::permissions::schedule_macos_dock_visibility_sync(&app);
-                        }
-                    })
-                    .ok();
-                }
-
-                #[cfg(not(target_os = "macos"))]
-                {
-                    let _ = window.set_position(main_position);
-
-                    #[cfg(windows)]
-                    {
-                        if let Err(e) = window.set_size(LogicalSize::new(330.0, 395.0)) {
-                            warn!("Failed to set Main window size on Windows: {}", e);
-                        }
-                        if let Err(e) = window.set_position(main_position) {
-                            warn!("Failed to position Main window on Windows: {}", e);
-                        }
-                    }
-
-                    crate::clean_capture::guarded_show(
-                        window.clone(),
-                        reveal_generation,
-                        false,
-                        false,
-                    )
-                    .await?;
-                }
-
-                window
-            }
-            Self::TargetSelectOverlay {
-                display_id,
-                target_mode,
-            } => {
-                let picker_session = picker_session.ok_or(tauri::Error::WindowNotFound)?;
-                let overlay_instance = picker
-                    .register_overlay(&self.id(app).label(), picker_session)
-                    .ok_or(tauri::Error::WindowNotFound)?;
-                let Some(display) = scap_targets::Display::from_id(display_id) else {
-                    return Err(tauri::Error::WindowNotFound);
-                };
-                let is_hovered_display = scap_targets::Display::get_containing_cursor()
-                    .map(|d| d.id())
-                    == Some(display.id());
-
-                let title = CapWindowId::TargetSelectOverlay {
-                    display_id: display_id.clone(),
-                }
-                .title();
-                let should_protect = should_protect_window(app, &title);
-
-                let target_mode_param = match target_mode {
-                    Some(RecordingTargetMode::Display) => "&targetMode=display",
-                    Some(RecordingTargetMode::Window) => "&targetMode=window",
-                    Some(RecordingTargetMode::Area) => "&targetMode=area",
-                    Some(RecordingTargetMode::Camera) => "&targetMode=camera",
-                    None => "",
-                };
-
-                let camera_ws_port = {
-                    let Some(state) = app.try_state::>() else {
-                        warn!("App state unavailable during target select overlay creation");
-                        return Err(tauri::Error::WindowNotFound);
-                    };
-                    let state = state.read().await;
-                    state.camera_ws_port
-                };
-
-                #[cfg(target_os = "macos")]
-                let panel_activation_guard = permissions::prepare_macos_panel_window(app);
-
-                let mut window_builder = self
-                    .window_builder(
-                        app,
-                        format!("/target-select-overlay?displayId={display_id}&isHoveredDisplay={is_hovered_display}&overlayInstance={overlay_instance}{target_mode_param}"),
-                    )
-                    .maximized(false)
-                    .resizable(false)
-                    .fullscreen(false)
-                    .shadow(false)
-                    .content_protected(should_protect)
-                    .always_on_top(true)
-                    .visible_on_all_workspaces(true)
-                    .skip_taskbar(true)
-                    .transparent(true)
-                    .visible(false)
-                    .initialization_script(format!(
-                        "window.__CAP__ = window.__CAP__ ?? {{}}; window.__CAP__.cameraWsPort = {camera_ws_port};"
-                    ));
-
-                #[cfg(all(target_os = "macos", debug_assertions))]
-                {
-                    window_builder = window_builder.background_throttling(
-                        tauri::utils::config::BackgroundThrottlingPolicy::Disabled,
-                    );
-                }
-
-                #[cfg(debug_assertions)]
-                if crate::picker_benchmark::enabled() {
-                    window_builder =
-                        window_builder.initialization_script(crate::picker_benchmark::SCRIPT);
-                }
-
-                #[cfg(target_os = "macos")]
-                {
-                    let position = display.raw_handle().logical_position();
-                    let size = display.logical_size().unwrap();
-
-                    window_builder = window_builder
-                        .inner_size(size.width(), size.height())
-                        .position(position.x(), position.y());
-                }
-
-                #[cfg(windows)]
-                {
-                    window_builder = window_builder.inner_size(100.0, 100.0).position(0.0, 0.0);
-                }
-
-                #[cfg(target_os = "linux")]
-                if cap_recording::screenshot::uses_wayland_portal() {
-                    let Some(bounds) = display.raw_handle().logical_bounds() else {
-                        return Err(tauri::Error::WindowNotFound);
-                    };
-                    window_builder = window_builder
-                        .inner_size(bounds.size().width(), bounds.size().height())
-                        .position(bounds.position().x(), bounds.position().y());
-                } else {
-                    let position = display.raw_handle().physical_position().unwrap();
-                    let size = display.physical_size().unwrap();
-                    window_builder = window_builder
-                        .inner_size(size.width(), size.height())
-                        .position(position.x(), position.y());
-                }
-
-                if !picker.picker_is_current(picker_session) {
-                    return Err(tauri::Error::WindowNotFound);
-                }
-                let window = window_builder.build()?;
-                lock_window_text_scale(&window);
-                if !picker.picker_is_current(picker_session) {
-                    let _ = window.destroy();
-                    return Err(tauri::Error::WindowNotFound);
-                }
-
-                if let Err(error) = window.set_ignore_cursor_events(true) {
-                    hide_overlay(&window);
-                    let _ = window.destroy();
-                    return Err(error);
-                }
-
-                #[cfg(target_os = "linux")]
-                if cap_recording::screenshot::uses_wayland_portal() {
-                    use tauri::{LogicalPosition, LogicalSize};
-                    let Some(bounds) = display.raw_handle().logical_bounds() else {
-                        return Err(tauri::Error::WindowNotFound);
-                    };
-                    let _ = window.set_position(LogicalPosition::new(
-                        bounds.position().x(),
-                        bounds.position().y(),
-                    ));
-                    let _ = window.set_size(LogicalSize::new(
-                        bounds.size().width(),
-                        bounds.size().height(),
-                    ));
-                } else {
-                    use tauri::{LogicalSize, PhysicalPosition};
-                    let position = display.raw_handle().physical_position().unwrap();
-                    let size = display.physical_size().unwrap();
-                    let _ = window.set_position(PhysicalPosition::new(position.x(), position.y()));
-                    let _ = window.set_size(LogicalSize::new(size.width(), size.height()));
-                }
-
-                #[cfg(windows)]
-                {
-                    let Some(position) = display.raw_handle().physical_position() else {
-                        warn!(display_id = %display_id, "Missing display position for target select overlay");
-                        return Err(tauri::Error::WindowNotFound);
-                    };
-                    let Some(logical_size) = display.logical_size() else {
-                        warn!(display_id = %display_id, "Missing display logical size for target select overlay");
-                        return Err(tauri::Error::WindowNotFound);
-                    };
-                    let Some(physical_size) = display.physical_size() else {
-                        warn!(display_id = %display_id, "Missing display physical size for target select overlay");
-                        return Err(tauri::Error::WindowNotFound);
-                    };
-                    use tauri::{LogicalSize, PhysicalPosition, PhysicalSize};
-                    let _ = window.set_size(LogicalSize::new(
-                        logical_size.width(),
-                        logical_size.height(),
-                    ));
-                    let _ = window.set_position(PhysicalPosition::new(position.x(), position.y()));
-                    tokio::time::sleep(std::time::Duration::from_millis(5)).await;
-
-                    match window.inner_size() {
-                        Ok(actual_physical_size)
-                            if physical_size.width() != actual_physical_size.width as f64 =>
-                        {
-                            let _ = window.set_size(LogicalSize::new(
-                                logical_size.width(),
-                                logical_size.height(),
-                            ));
-                        }
-                        Ok(_) => {}
-                        Err(err) => {
-                            warn!(%err, "Failed to read target select overlay inner size");
-                        }
-                    }
-                }
-
-                app.state::()
-                    .spawn(display_id, window.clone(), picker_session);
-
-                #[cfg(target_os = "macos")]
-                {
-                    app.run_on_main_thread({
-                        let window = window.clone();
-                        let app = app.clone();
-                        let panel_activation_guard = panel_activation_guard;
-                        move || {
-                            let _panel_activation_guard = panel_activation_guard;
-                            use tauri_nspanel::cocoa::appkit::NSWindowCollectionBehavior;
-                            use tauri_nspanel::WebviewWindowExt as NSPanelWebviewWindowExt;
-
-                            #[link(name = "CoreGraphics", kind = "framework")]
-                            unsafe extern "C" {
-                                fn CGWindowLevelForKey(key: i32) -> i32;
-                            }
-
-                            #[allow(non_upper_case_globals)]
-                            const kCGMaximumWindowLevelKey: i32 = 10;
-
-                            let panel = match window.to_panel() {
-                                Ok(p) => p,
-                                Err(e) => {
-                                    tracing::error!("Failed to convert target select overlay to panel: {:?}", e);
-                                    hide_overlay(&window);
-                                    let _ = window.destroy();
-                                    crate::permissions::sync_macos_dock_visibility(&app);
-                                    return;
-                                }
-                            };
-
-                            panel.set_collection_behaviour(
-                                NSWindowCollectionBehavior::NSWindowCollectionBehaviorCanJoinAllSpaces
-                                    | NSWindowCollectionBehavior::NSWindowCollectionBehaviorFullScreenPrimary,
-                            );
-
-                            #[allow(non_upper_case_globals)]
-                            const NSWindowStyleMaskNonActivatingPanel: i32 = 1 << 7;
-                            panel.set_style_mask(NSWindowStyleMaskNonActivatingPanel);
-
-                            let max_level = unsafe { CGWindowLevelForKey(kCGMaximumWindowLevelKey) };
-                            panel.set_level(max_level - 1);
-
-                            crate::target_select_overlay::mark_overlay_native_ready(&window, overlay_instance);
-
-                            crate::permissions::schedule_macos_dock_visibility_sync(&app);
-                        }
-                    })
-                    .ok();
-                }
-
-                #[cfg(not(target_os = "macos"))]
-                {
-                    crate::target_select_overlay::mark_overlay_native_ready(
-                        &window,
-                        overlay_instance,
-                    );
-                }
-
-                window
-            }
-            Self::Settings { page } => {
-                let mut builder = self
-                    .window_builder(
-                        app,
-                        format!("/settings/{}", page.clone().unwrap_or_default()),
-                    )
-                    .resizable(true)
-                    .maximized(false)
-                    .focused(true);
-
-                #[cfg(target_os = "macos")]
-                {
-                    builder = builder.transparent(true);
-                }
-
-                let window = builder.build()?;
-                lock_window_text_scale(&window);
-
-                fit_content_window_bounds(&window, &_id, true).await;
-
-                window
-            }
-            Self::Editor { project_path } => {
-                let open_started = std::time::Instant::now();
-                hide_recording_windows(app, false);
-                release_camera_preview_if_idle(app);
-
-                PendingEditorInstances::start_prewarm(app, _id.label(), project_path.clone()).await;
-
-                let builder = self
-                    .window_builder_with_id(app, "/editor", &_id, _id.label())
-                    .maximizable(true)
-                    .focused(true);
-                #[cfg(debug_assertions)]
-                let builder = if crate::stop_editor_benchmark::enabled() {
-                    builder.initialization_script(crate::stop_editor_benchmark::SCRIPT)
-                } else {
-                    builder
-                };
-                #[cfg(debug_assertions)]
-                let builder = if crate::stop_editor_benchmark::dom_capture_requested() {
-                    builder.initialization_script(crate::stop_editor_benchmark::DOM_SCRIPT)
-                } else {
-                    builder
-                };
-                let window = builder.build()?;
-                if let Some(opening) = project_opening.as_mut() {
-                    opening.own_window(&window);
-                }
-                lock_window_text_scale(&window);
-
-                fit_content_window_bounds(&window, &_id, true).await;
-
-                // Show immediately: the native background color is already
-                // themed, so the window can appear before the webview loads and
-                // the editor skeleton takes over. When window transparency is
-                // enabled we keep the old behaviour (the frontend reveals the
-                // window after applying the HudWindow effects) to avoid an
-                // opaque-to-transparent pop.
-                let transparency_enabled = GeneralSettingsStore::get(app)
-                    .ok()
-                    .flatten()
-                    .map(|s| s.window_transparency)
-                    .unwrap_or(false);
-                if !transparency_enabled {
-                    window.show().ok();
-                    window.set_focus().ok();
-                }
-
-                info!(
-                    window_built_and_shown_ms = open_started.elapsed().as_millis() as u64,
-                    shown_from_rust = !transparency_enabled,
-                    "Editor open: window ready"
-                );
-
-                window
-            }
-            Self::ScreenshotEditor { path } => {
-                hide_recording_windows(app, false);
-                release_camera_preview_if_idle(app);
-
-                PendingScreenshotEditorInstances::start_prewarm(app, _id.label(), path.clone())
-                    .await;
-
-                let window = self
-                    .window_builder_with_id(app, "/screenshot-editor", &_id, _id.label())
-                    .maximizable(true)
-                    .focused(true)
-                    .build()?;
-                if let Some(opening) = project_opening.as_mut() {
-                    opening.own_window(&window);
-                }
-                lock_window_text_scale(&window);
-
-                fit_content_window_bounds(&window, &_id, true).await;
-
-                window.show().ok();
-                window.set_focus().ok();
-
-                window
-            }
-            Self::Upgrade => {
-                crate::hide_main_window(app);
-
-                let window = self
-                    .window_builder(app, "/upgrade")
-                    .inner_size(950.0, 850.0)
-                    .min_inner_size(950.0, 850.0)
-                    .resizable(false)
-                    .focused(true)
-                    .always_on_top(true)
-                    .maximized(false)
-                    .shadow(true)
-                    .build()?;
-                lock_window_text_scale(&window);
-
-                let (pos_x, pos_y) = cursor_monitor.center_position(950.0, 850.0);
-                let _ = window.set_position(cursor_monitor.position(pos_x, pos_y));
-
-                #[cfg(windows)]
-                {
-                    use tauri::LogicalSize;
-                    if let Err(e) = window.set_size(LogicalSize::new(950.0, 850.0)) {
-                        warn!("Failed to set Upgrade window size on Windows: {}", e);
-                    }
-                    if let Err(e) = window.set_position(cursor_monitor.position(pos_x, pos_y)) {
-                        warn!("Failed to position Upgrade window on Windows: {}", e);
-                    }
-                }
-
-                window.show().ok();
-                window.set_focus().ok();
-
-                window
-            }
-            Self::ModeSelect => {
-                crate::hide_main_window(app);
-
-                let window = self
-                    .window_builder(app, "/mode-select")
-                    .inner_size(580.0, 340.0)
-                    .min_inner_size(580.0, 340.0)
-                    .resizable(false)
-                    .maximized(false)
-                    .maximizable(false)
-                    .focused(true)
-                    .shadow(true)
-                    .build()?;
-                lock_window_text_scale(&window);
-
-                let (pos_x, pos_y) = cursor_monitor.center_position(580.0, 340.0);
-                let _ = window.set_position(cursor_monitor.position(pos_x, pos_y));
-
-                #[cfg(windows)]
-                {
-                    use tauri::LogicalSize;
-                    if let Err(e) = window.set_size(LogicalSize::new(580.0, 340.0)) {
-                        warn!("Failed to set ModeSelect window size on Windows: {}", e);
-                    }
-                    if let Err(e) = window.set_position(cursor_monitor.position(pos_x, pos_y)) {
-                        warn!("Failed to position ModeSelect window on Windows: {}", e);
-                    }
-                }
-
-                window.show().ok();
-                window.set_focus().ok();
-
-                window
-            }
-            Self::Onboarding => {
-                crate::hide_main_window(app);
-
-                let width = (cursor_monitor.width * 0.58).clamp(860.0, 1080.0);
-                let height = (width * 0.72).clamp(690.0, 780.0);
-
-                let window = self
-                    .window_builder(app, "/onboarding")
-                    .inner_size(width, height)
-                    .min_inner_size(860.0, 690.0)
-                    .resizable(false)
-                    .maximized(false)
-                    .maximizable(false)
-                    .transparent(true)
-                    .focused(true)
-                    .shadow(true)
-                    .build()?;
-                lock_window_text_scale(&window);
-
-                let (pos_x, pos_y) = cursor_monitor.center_position(width, height);
-                let _ = window.set_position(cursor_monitor.position(pos_x, pos_y));
-                let _ = window.set_ignore_cursor_events(false);
-
-                #[cfg(windows)]
-                {
-                    use tauri::LogicalSize;
-                    if let Err(e) = window.set_size(LogicalSize::new(width, height)) {
-                        warn!("Failed to set Onboarding window size on Windows: {}", e);
-                    }
-                    if let Err(e) = window.set_position(cursor_monitor.position(pos_x, pos_y)) {
-                        warn!("Failed to position Onboarding window on Windows: {}", e);
-                    }
-                }
-
-                window.show().ok();
-                window.set_focus().ok();
-
-                window
-            }
-            Self::Camera { centered } => {
-                const DEFAULT_WINDOW_SIZE: f64 = 230.0 * 2.0;
-                const CENTERED_WINDOW_SIZE: f64 = 400.0;
-
-                #[cfg(target_os = "macos")]
-                let create_guard = {
-                    let panel_manager = app.state::();
-                    panel_manager
-                        .try_begin_create(PanelWindowType::Camera)
-                        .await
-                };
-
-                #[cfg(target_os = "macos")]
-                let Some(mut create_guard) = create_guard else {
-                    let panel_manager = app.state::();
-                    let state = panel_manager.get_state(PanelWindowType::Camera).await;
-                    warn!("Camera window creation blocked, current state: {:?}", state);
-                    if state == PanelState::Ready
-                        && let Some(window) = CapWindowId::Camera.get(app)
-                    {
-                        if *centered {
-                            center_camera_window(app, &window);
-                        }
-                        return Ok(window);
-                    }
-                    panel_manager
-                        .wait_for_state(
-                            PanelWindowType::Camera,
-                            &[PanelState::Ready, PanelState::None],
-                            std::time::Duration::from_millis(500),
-                        )
-                        .await;
-                    if let Some(window) = CapWindowId::Camera.get(app) {
-                        if *centered {
-                            center_camera_window(app, &window);
-                        }
-                        return Ok(window);
-                    }
-                    return Err(tauri::Error::WindowNotFound);
-                };
-
-                let enable_native_camera_preview =
-                    GeneralSettingsStore::native_camera_preview_enabled(app);
-
-                {
-                    let Some(state) = app.try_state::>() else {
-                        warn!("App state unavailable while creating camera window");
-                        return Err(tauri::Error::WindowNotFound);
-                    };
-                    let mut state = state.write().await;
-
-                    let shutdown_preview =
-                        if !enable_native_camera_preview && state.camera_preview.is_initialized() {
-                            state.camera_preview.begin_shutdown()
-                        } else {
-                            None
-                        };
-
-                    if enable_native_camera_preview && state.camera_preview.is_initialized() {
-                        warn!("Detected existing camera preview, will reuse it");
-                    }
-
-                    // Camera protection is applied per recording mode in `start_recording`;
-                    // protecting at creation hides the live preview on virtual/mirrored displays.
-                    let should_protect = false;
-
-                    #[cfg(target_os = "macos")]
-                    let panel_activation_guard = permissions::prepare_macos_panel_window(app);
-
-                    let label = camera_window_label
-                        .clone()
-                        .unwrap_or_else(|| CapWindowId::Camera.label());
-                    let mut window_builder = self
-                        .window_builder_with_label(app, "/camera", label)
-                        .maximized(false)
-                        .resizable(false)
-                        .shadow(false)
-                        .fullscreen(false)
-                        .always_on_top(true)
-                        .visible_on_all_workspaces(true)
-                        .skip_taskbar(true)
-                        .initialization_script(format!(
-                            "
-			                window.__CAP__ = window.__CAP__ ?? {{}};
-			                window.__CAP__.cameraWsPort = {};
-			                window.__CAP__.cameraOnlyMode = {};
-			                window.__CAP__.enableNativeCameraPreview = {};
-                            window.__CAP__.cleanCaptureGeneration = {};
-		                ",
-                            state.camera_ws_port,
-                            centered,
-                            enable_native_camera_preview,
-                            reveal_generation
-                        ))
-                        .content_protected(should_protect)
-                        .transparent(true)
-                        .visible(false);
-
-                    let window = match window_builder.build() {
-                        Ok(w) => w,
-                        Err(e) => {
-                            let is_label_exists = e.to_string().contains("already exists");
-                            if is_label_exists {
-                                warn!(
-                                    "Camera webview label already exists, cleaning up for next attempt"
-                                );
-                                cleanup_camera_window(app, None, false, false).await;
-                            }
-
-                            #[cfg(target_os = "macos")]
-                            {
-                                let panel_manager = app.state::();
-                                panel_manager.force_reset(PanelWindowType::Camera).await;
-                            }
-                            return Err(e);
-                        }
-                    };
-                    lock_window_text_scale(&window);
-
-                    #[cfg(target_os = "windows")]
-                    log_window_content_protection(
-                        &window,
-                        should_protect,
-                        &CapWindowId::Camera.title(),
-                    );
-
-                    let camera_monitor = CapWindowId::Main
-                        .get(app)
-                        .map(|w| CursorMonitorInfo::from_window(&w))
-                        .unwrap_or(cursor_monitor);
-
-                    let preferred_monitor_name = display_name_for_position(
-                        camera_monitor.x + camera_monitor.width / 2.0,
-                        camera_monitor.y + camera_monitor.height / 2.0,
-                    );
-
-                    let saved_position =
-                        GeneralSettingsStore::get(app)
-                            .ok()
-                            .flatten()
-                            .and_then(|settings| {
-                                if let Some(monitor_name) = preferred_monitor_name.as_deref() {
-                                    settings
-                                        .camera_window_positions_by_monitor_name
-                                        .get(monitor_name)
-                                        .cloned()
-                                        .filter(|pos| {
-                                            is_position_on_monitor_name(monitor_name, pos.x, pos.y)
-                                        })
-                                        .or_else(|| {
-                                            settings.camera_window_position.filter(|pos| {
-                                                is_position_on_monitor_name(
-                                                    monitor_name,
-                                                    pos.x,
-                                                    pos.y,
-                                                )
-                                            })
-                                        })
-                                } else {
-                                    settings.camera_window_position.filter(|pos| {
-                                        if let Some(display_id) = &pos.display_id {
-                                            is_position_on_display(display_id, pos.x, pos.y)
-                                        } else {
-                                            is_position_on_any_screen(pos.x, pos.y)
-                                        }
-                                    })
-                                }
-                            });
-
-                    let camera_position = if let Some(pos) = saved_position {
-                        match display_for_saved_position(pos.x, pos.y, pos.display_id.as_ref()) {
-                            Some(display) => {
-                                CursorMonitorInfo::from_display(&display).position(pos.x, pos.y)
-                            }
-                            None => {
-                                tauri::Position::Logical(tauri::LogicalPosition::new(pos.x, pos.y))
-                            }
-                        }
-                    } else if *centered {
-                        let aspect_ratio = crate::camera::WIDE_CAMERA_ASPECT_RATIO as f64;
-                        let toolbar_height = 56.0;
-                        let window_width = CENTERED_WINDOW_SIZE * aspect_ratio;
-                        let window_height = CENTERED_WINDOW_SIZE + toolbar_height;
-                        let (camera_pos_x, camera_pos_y) =
-                            camera_monitor.center_position(window_width, window_height);
-                        camera_monitor.position(camera_pos_x, camera_pos_y)
-                    } else {
-                        let camera_pos_x =
-                            camera_monitor.x + camera_monitor.width - DEFAULT_WINDOW_SIZE - 100.0;
-                        let camera_pos_y =
-                            camera_monitor.y + camera_monitor.height - DEFAULT_WINDOW_SIZE - 100.0;
-                        camera_monitor.position(camera_pos_x, camera_pos_y)
-                    };
-
-                    #[cfg(not(target_os = "macos"))]
-                    {
-                        if let Some(guard) = app.try_state::() {
-                            guard.ignore_for(1000);
-                        }
-                        let _ = window.set_position(camera_position);
-                    }
-
-                    ensure_camera_input_active(&mut state).await;
-
-                    #[cfg(target_os = "macos")]
-                    {
-                        let panel_manager = app.state::();
-                        let operation_id = create_guard.operation_id;
-
-                        let (panel_tx, panel_rx) = tokio::sync::oneshot::channel();
-                        app.run_on_main_thread({
-                            let window = window.clone();
-                            let app = app.clone();
-                            let panel_activation_guard = panel_activation_guard;
-                            move || {
-                                let _panel_activation_guard = panel_activation_guard;
-                                use tauri_nspanel::cocoa::appkit::NSWindowCollectionBehavior;
-                                use crate::panel_manager::try_to_panel;
-
-                                #[link(name = "CoreGraphics", kind = "framework")]
-                                unsafe extern "C" {
-                                    fn CGWindowLevelForKey(key: i32) -> i32;
-                                }
-
-                                #[allow(non_upper_case_globals)]
-                                const kCGMaximumWindowLevelKey: i32 = 10;
-
-                                let panel = match try_to_panel(&window) {
-                                    Ok(p) => p,
-                                    Err(e) => {
-                                        tracing::error!("Failed to convert camera to panel: {}", e);
-                                        crate::permissions::sync_macos_dock_visibility(&app);
-                                        let _ = panel_tx.send(false);
-                                        return;
-                                    }
-                                };
-
-                                panel.set_collection_behaviour(
-                                    NSWindowCollectionBehavior::NSWindowCollectionBehaviorCanJoinAllSpaces
-                                        | NSWindowCollectionBehavior::NSWindowCollectionBehaviorFullScreenPrimary,
-                                );
-
-                                let max_level =
-                                    unsafe { CGWindowLevelForKey(kCGMaximumWindowLevelKey) };
-                                panel.set_level(max_level);
-
-                                if let Some(guard) = app.try_state::() {
-                                    guard.ignore_for(1000);
-                                }
-                                let _ = window.set_position(camera_position);
-
-                                panel.order_front_regardless();
-                                panel.show();
-                                crate::permissions::schedule_macos_dock_visibility_sync(&app);
-                                let _ = panel_tx.send(true);
-                            }
-                        })
-                        .ok();
-
-                        if panel_rx.await.unwrap_or(false) {
-                            panel_manager
-                                .mark_ready(PanelWindowType::Camera, operation_id)
-                                .await;
-                            create_guard.mark_completed();
-                        } else {
-                            warn!("Camera panel creation failed");
-                            panel_manager.force_reset(PanelWindowType::Camera).await;
-                        }
-                    }
-
-                    if enable_native_camera_preview
-                        && let Err(err) =
-                            init_native_camera_preview(&mut state, window.clone()).await
-                    {
-                        error!(
-                            "Error initializing camera preview, falling back to WebSocket preview: {err}"
-                        );
-                    }
-
-                    #[cfg(not(target_os = "macos"))]
-                    {
-                        crate::clean_capture::guarded_show(
-                            window.clone(),
-                            reveal_generation,
-                            false,
-                            false,
-                        )
-                        .await?;
-                    }
-
-                    drop(state);
-
-                    if let Some(rx) = shutdown_preview {
-                        let _ = tokio::time::timeout(Duration::from_millis(500), rx).await;
-                    }
-
-                    window
-                }
-            }
-            Self::WindowCaptureOccluder { screen_id } => {
-                let Some(display) = Display::from_id(screen_id) else {
-                    return Err(tauri::Error::WindowNotFound);
-                };
-
-                let title = CapWindowId::WindowCaptureOccluder {
-                    screen_id: screen_id.clone(),
-                }
-                .title();
-                let should_protect = should_protect_window(app, &title);
-
-                let mut window_builder = self
-                    .window_builder(app, "/window-capture-occluder")
-                    .maximized(false)
-                    .resizable(false)
-                    .fullscreen(false)
-                    .shadow(false)
-                    .always_on_top(true)
-                    .visible_on_all_workspaces(true)
-                    .content_protected(should_protect)
-                    .skip_taskbar(true)
-                    .transparent(true);
-
-                #[cfg(target_os = "macos")]
-                {
-                    let position = display.raw_handle().logical_position();
-                    let Some(size) = display.logical_size() else {
-                        warn!(screen_id = %screen_id, "Missing display logical size for window capture occluder");
-                        return Err(tauri::Error::WindowNotFound);
-                    };
-
-                    window_builder = window_builder
-                        .inner_size(size.width(), size.height())
-                        .position(position.x(), position.y());
-                }
-
-                // On Windows a window's DPI scale isn't known until it's placed on a
-                // monitor, so sizing/positioning from display bounds at build time is
-                // unreliable across monitors with different DPIs. Build a placeholder
-                // and fix the geometry up after the window exists (below), mirroring
-                // the TargetSelectOverlay path.
-                #[cfg(windows)]
-                {
-                    window_builder = window_builder.inner_size(100.0, 100.0).position(0.0, 0.0);
-                }
-
-                #[cfg(target_os = "linux")]
-                if cap_recording::screenshot::uses_wayland_portal() {
-                    let Some(bounds) = display.raw_handle().logical_bounds() else {
-                        return Err(tauri::Error::WindowNotFound);
-                    };
-                    window_builder = window_builder
-                        .inner_size(bounds.size().width(), bounds.size().height())
-                        .position(bounds.position().x(), bounds.position().y());
-                } else {
-                    let position = display.raw_handle().physical_position().unwrap();
-                    let Some(size) = display.physical_size() else {
-                        warn!(screen_id = %screen_id, "Missing display size for window capture occluder");
-                        return Err(tauri::Error::WindowNotFound);
-                    };
-                    window_builder = window_builder
-                        .inner_size(size.width(), size.height())
-                        .position(position.x(), position.y());
-                }
-
-                let window = window_builder.build()?;
-                lock_window_text_scale(&window);
-
-                #[cfg(target_os = "linux")]
-                if cap_recording::screenshot::uses_wayland_portal() {
-                    use tauri::{LogicalPosition, LogicalSize};
-                    let Some(bounds) = display.raw_handle().logical_bounds() else {
-                        return Err(tauri::Error::WindowNotFound);
-                    };
-                    let _ = window.set_position(LogicalPosition::new(
-                        bounds.position().x(),
-                        bounds.position().y(),
-                    ));
-                    let _ = window.set_size(LogicalSize::new(
-                        bounds.size().width(),
-                        bounds.size().height(),
-                    ));
-                } else {
-                    use tauri::{LogicalSize, PhysicalPosition};
-                    let position = display.raw_handle().physical_position().unwrap();
-                    if let Some(size) = display.physical_size() {
-                        let _ =
-                            window.set_position(PhysicalPosition::new(position.x(), position.y()));
-                        let _ = window.set_size(LogicalSize::new(size.width(), size.height()));
-                    }
-                }
-
-                // Fix up the occluder geometry now that the window exists and its real
-                // per-monitor DPI is known: position with physical coordinates (which
-                // are unambiguous across monitors), then set the logical size so the
-                // window covers the full display. Verify the resulting physical size
-                // matches the display and re-apply once if the initial placement raced
-                // the DPI change.
-                #[cfg(windows)]
-                {
-                    let Some(position) = display.raw_handle().physical_position() else {
-                        warn!(screen_id = %screen_id, "Missing display position for window capture occluder");
-                        return Err(tauri::Error::WindowNotFound);
-                    };
-                    let Some(logical_size) = display.logical_size() else {
-                        warn!(screen_id = %screen_id, "Missing display logical size for window capture occluder");
-                        return Err(tauri::Error::WindowNotFound);
-                    };
-                    let Some(physical_size) = display.physical_size() else {
-                        warn!(screen_id = %screen_id, "Missing display physical size for window capture occluder");
-                        return Err(tauri::Error::WindowNotFound);
-                    };
-                    use tauri::{LogicalSize, PhysicalPosition};
-                    let _ = window.set_size(LogicalSize::new(
-                        logical_size.width(),
-                        logical_size.height(),
-                    ));
-                    let _ = window.set_position(PhysicalPosition::new(position.x(), position.y()));
-                    tokio::time::sleep(std::time::Duration::from_millis(5)).await;
-
-                    match window.inner_size() {
-                        Ok(actual_physical_size)
-                            if physical_size.width() != actual_physical_size.width as f64 =>
-                        {
-                            let _ = window.set_size(LogicalSize::new(
-                                logical_size.width(),
-                                logical_size.height(),
-                            ));
-                        }
-                        Ok(_) => {}
-                        Err(err) => {
-                            warn!(%err, "Failed to read window capture occluder inner size");
-                        }
-                    }
-                }
-
-                if let Err(err) = window.set_ignore_cursor_events(true) {
-                    warn!(%err, "Failed to ignore cursor events for window capture occluder");
-                    hide_overlay(&window);
-                    let _ = window.destroy();
-                    return Err(err);
-                }
-
-                #[cfg(target_os = "macos")]
-                {
-                    crate::platform::set_window_level(window.as_ref().window(), 900);
-                }
-
-                crate::clean_capture::guarded_show(window.clone(), reveal_generation, false, false)
-                    .await?;
-
-                window
-            }
-            Self::CaptureArea { screen_id } => {
-                let title = CapWindowId::CaptureArea.title();
-                let should_protect = should_protect_window(app, &title);
-
-                let mut window_builder = self
-                    .window_builder(app, "/capture-area")
-                    .maximized(false)
-                    .fullscreen(false)
-                    .shadow(false)
-                    .resizable(false)
-                    .always_on_top(true)
-                    .content_protected(should_protect)
-                    .skip_taskbar(true)
-                    .closable(true)
-                    .decorations(false)
-                    .transparent(true);
-
-                let Some(display) = Display::from_id(screen_id) else {
-                    return Err(tauri::Error::WindowNotFound);
-                };
-
-                #[cfg(target_os = "macos")]
-                if let Some(bounds) = display.raw_handle().logical_bounds() {
-                    window_builder = window_builder
-                        .inner_size(bounds.size().width(), bounds.size().height())
-                        .position(bounds.position().x(), bounds.position().y());
-                }
-
-                // On Windows a window's DPI scale isn't known until it's placed on a
-                // monitor, so sizing/positioning from logical bounds at build time is
-                // unreliable across monitors with different DPIs — the overlay ends up
-                // sized for the wrong monitor and no longer covers the target display,
-                // which truncates area selections on HiDPI secondary monitors. Build a
-                // placeholder and fix the geometry up after the window exists (below),
-                // mirroring the TargetSelectOverlay path.
-                #[cfg(windows)]
-                {
-                    window_builder = window_builder.inner_size(100.0, 100.0).position(0.0, 0.0);
-                }
-
-                #[cfg(target_os = "linux")]
-                if cap_recording::screenshot::uses_wayland_portal() {
-                    let Some(bounds) = display.raw_handle().logical_bounds() else {
-                        return Err(tauri::Error::WindowNotFound);
-                    };
-                    window_builder = window_builder
-                        .inner_size(bounds.size().width(), bounds.size().height())
-                        .position(bounds.position().x(), bounds.position().y());
-                } else if let Some(bounds) = display.raw_handle().physical_bounds() {
-                    window_builder = window_builder
-                        .inner_size(bounds.size().width(), bounds.size().height())
-                        .position(bounds.position().x(), bounds.position().y());
-                }
-
-                let window = window_builder.build()?;
-                lock_window_text_scale(&window);
-
-                // Fix up the overlay geometry now that the window exists and its real
-                // per-monitor DPI is known: position with physical coordinates (which are
-                // unambiguous across monitors), then set the logical size so the window
-                // covers the full display. Verify the resulting physical size matches the
-                // display and re-apply once if the initial placement raced the DPI change.
-                #[cfg(windows)]
-                {
-                    let Some(position) = display.raw_handle().physical_position() else {
-                        warn!(display_id = %screen_id, "Missing display position for capture area overlay");
-                        return Err(tauri::Error::WindowNotFound);
-                    };
-                    let Some(logical_size) = display.logical_size() else {
-                        warn!(display_id = %screen_id, "Missing display logical size for capture area overlay");
-                        return Err(tauri::Error::WindowNotFound);
-                    };
-                    let Some(physical_size) = display.physical_size() else {
-                        warn!(display_id = %screen_id, "Missing display physical size for capture area overlay");
-                        return Err(tauri::Error::WindowNotFound);
-                    };
-                    use tauri::{LogicalSize, PhysicalPosition};
-                    let _ = window.set_size(LogicalSize::new(
-                        logical_size.width(),
-                        logical_size.height(),
-                    ));
-                    let _ = window.set_position(PhysicalPosition::new(position.x(), position.y()));
-                    tokio::time::sleep(std::time::Duration::from_millis(5)).await;
-
-                    match window.inner_size() {
-                        Ok(actual_physical_size)
-                            if physical_size.width() != actual_physical_size.width as f64 =>
-                        {
-                            let _ = window.set_size(LogicalSize::new(
-                                logical_size.width(),
-                                logical_size.height(),
-                            ));
-                        }
-                        Ok(_) => {}
-                        Err(err) => {
-                            warn!(%err, "Failed to read capture area overlay inner size");
-                        }
-                    }
-                }
-
-                #[cfg(target_os = "linux")]
-                if cap_recording::screenshot::uses_wayland_portal() {
-                    use tauri::{LogicalPosition, LogicalSize};
-                    let Some(bounds) = display.raw_handle().logical_bounds() else {
-                        return Err(tauri::Error::WindowNotFound);
-                    };
-                    let _ = window.set_position(LogicalPosition::new(
-                        bounds.position().x(),
-                        bounds.position().y(),
-                    ));
-                    let _ = window.set_size(LogicalSize::new(
-                        bounds.size().width(),
-                        bounds.size().height(),
-                    ));
-                } else if let Some(bounds) = display.raw_handle().physical_bounds() {
-                    use tauri::{LogicalSize, PhysicalPosition};
-                    let _ = window.set_position(PhysicalPosition::new(
-                        bounds.position().x(),
-                        bounds.position().y(),
-                    ));
-                    let _ = window.set_size(LogicalSize::new(
-                        bounds.size().width(),
-                        bounds.size().height(),
-                    ));
-                }
-
-                #[cfg(target_os = "macos")]
-                crate::platform::set_window_level(
-                    window.as_ref().window(),
-                    objc2_app_kit::NSPopUpMenuWindowLevel,
-                );
-
-                // Hide the main window if the target monitor is the same
-                if let Some(main_window) = CapWindowId::Main.get(app)
-                    && let (Ok(outer_pos), Ok(outer_size)) =
-                        (main_window.outer_position(), main_window.outer_size())
-                    && let Ok(scale_factor) = main_window.scale_factor()
-                    && display.intersects(outer_pos, outer_size, scale_factor)
-                {
-                    let _ = main_window.minimize();
-                };
-
-                window
-            }
-            Self::InProgressRecording {
-                countdown,
-                capture_target,
-            } => {
-                let width = 320.0;
-                let height = 150.0;
-
-                let title = CapWindowId::RecordingControls.title();
-                let should_protect = should_protect_window(app, &title);
-
-                #[cfg(target_os = "macos")]
-                let panel_activation_guard = permissions::prepare_macos_panel_window(app);
-
-                #[cfg(target_os = "macos")]
-                let window = {
-                    self.window_builder(app, "/in-progress-recording")
-                        .maximized(false)
-                        .resizable(false)
-                        .fullscreen(false)
-                        .shadow(false)
-                        .always_on_top(true)
-                        .transparent(true)
-                        .visible_on_all_workspaces(true)
-                        .content_protected(should_protect)
-                        .inner_size(width, height)
-                        .skip_taskbar(true)
-                        .visible(false)
-                        .initialization_script(format!(
-                            "window.COUNTDOWN = {};",
-                            countdown.unwrap_or_default()
-                        ))
-                        .build()?
-                };
-
-                #[cfg(windows)]
-                let window = self
-                    .window_builder(app, "/in-progress-recording")
-                    .maximized(false)
-                    .resizable(false)
-                    .fullscreen(false)
-                    .shadow(false)
-                    .always_on_top(true)
-                    .transparent(true)
-                    .visible_on_all_workspaces(true)
-                    .content_protected(should_protect)
-                    .inner_size(width, height)
-                    .skip_taskbar(false)
-                    .initialization_script(format!(
-                        "window.COUNTDOWN = {};",
-                        countdown.unwrap_or_default()
-                    ))
-                    .build()?;
-
-                #[cfg(target_os = "linux")]
-                let window = self
-                    .window_builder(app, "/in-progress-recording")
-                    .maximized(false)
-                    .resizable(false)
-                    .fullscreen(false)
-                    .shadow(false)
-                    .always_on_top(true)
-                    .transparent(true)
-                    .visible_on_all_workspaces(true)
-                    .content_protected(should_protect)
-                    .inner_size(width, height)
-                    .skip_taskbar(false)
-                    .initialization_script(format!(
-                        "window.COUNTDOWN = {};",
-                        countdown.unwrap_or_default()
-                    ))
-                    .build()?;
-
-                lock_window_text_scale(&window);
-
-                #[cfg(target_os = "windows")]
-                log_window_content_protection(&window, should_protect, &title);
-
-                let (pos_x, pos_y) = capture_target
-                    .as_ref()
-                    .and_then(fake_window::calculate_recording_controls_position_for_target)
-                    .unwrap_or_else(|| cursor_monitor.bottom_center_position(width, height, 120.0));
-                let _ = window.set_position(logical_point_position(pos_x, pos_y));
-
-                debug!(
-                    "InProgressRecording window: cursor_monitor=({}, {}, {}, {}), pos=({}, {})",
-                    cursor_monitor.x,
-                    cursor_monitor.y,
-                    cursor_monitor.width,
-                    cursor_monitor.height,
-                    pos_x,
-                    pos_y
-                );
-
-                debug!(
-                    "InProgressRecording window created: label={}, inner_size={:?}, outer_position={:?}",
-                    window.label(),
-                    window.inner_size(),
-                    window.outer_position()
-                );
-
-                #[cfg(target_os = "macos")]
-                {
-                    let mut pending_window = PendingControlsWindow(Some(window.clone()));
-                    let (show_tx, show_rx) = tokio::sync::oneshot::channel();
-                    let scheduled = app.run_on_main_thread({
-                        let window = window.clone();
-                        let app = app.clone();
-                        let panel_activation_guard = panel_activation_guard;
-                        move || {
-                            let _panel_activation_guard = panel_activation_guard;
-                            if show_tx.is_closed() {
-                                crate::permissions::sync_macos_dock_visibility(&app);
-                                return;
-                            }
-                            use tauri_nspanel::cocoa::appkit::NSWindowCollectionBehavior;
-                            use tauri_nspanel::WebviewWindowExt as NSPanelWebviewWindowExt;
-
-                            #[link(name = "CoreGraphics", kind = "framework")]
-                            unsafe extern "C" {
-                                fn CGWindowLevelForKey(key: i32) -> i32;
-                            }
-
-                            #[allow(non_upper_case_globals)]
-                            const kCGMaximumWindowLevelKey: i32 = 10;
-
-                            let panel = match window.to_panel() {
-                                Ok(p) => p,
-                                Err(e) => {
-                                    tracing::error!("Failed to convert recording controls to panel: {:?}", e);
-                                    crate::permissions::sync_macos_dock_visibility(&app);
-                                    let _ = show_tx.send(Err(format!("Failed to prepare recording controls: {e:?}")));
-                                    return;
-                                }
-                            };
-
-                            panel.set_collection_behaviour(
-                                NSWindowCollectionBehavior::NSWindowCollectionBehaviorCanJoinAllSpaces
-                                    | NSWindowCollectionBehavior::NSWindowCollectionBehaviorFullScreenPrimary,
-                            );
-
-                            let max_level = unsafe { CGWindowLevelForKey(kCGMaximumWindowLevelKey) };
-                            panel.set_level(max_level);
-
-                            panel.order_front_regardless();
-                            panel.show();
-
-                            crate::permissions::schedule_macos_dock_visibility_sync(&app);
-                            let _ = show_tx.send(Ok(()));
-                        }
-                    });
-                    let shown = match scheduled {
-                        Ok(()) => await_window_operation(
-                            show_rx,
-                            "Showing recording controls",
-                            Duration::from_secs(5),
-                        )
-                        .await
-                        .map_err(|error| tauri::Error::Anyhow(anyhow!(error))),
-                        Err(error) => Err(error),
-                    };
-                    shown?;
-                    pending_window.0 = None;
-
-                    fake_window::spawn_fake_window_listener(app.clone(), window.clone());
-                }
-
-                #[cfg(windows)]
-                {
-                    tokio::time::sleep(std::time::Duration::from_millis(100)).await;
-                    let show_result = window.show();
-                    debug!(
-                        "InProgressRecording window.show() result: {:?}",
-                        show_result
-                    );
-                    window.set_focus().ok();
-                    fake_window::spawn_fake_window_listener(app.clone(), window.clone());
-                }
-
-                window
-            }
-            Self::RecordingsOverlay => {
-                let title = CapWindowId::RecordingsOverlay.title();
-                let should_protect = should_protect_window(app, &title);
-
-                let window = self
-                    .window_builder(app, "/recordings-overlay")
-                    .maximized(false)
-                    .resizable(false)
-                    .fullscreen(false)
-                    .shadow(false)
-                    .always_on_top(true)
-                    .visible_on_all_workspaces(true)
-                    .accept_first_mouse(true)
-                    .content_protected(should_protect)
-                    .inner_size(cursor_monitor.width, cursor_monitor.height)
-                    .skip_taskbar(true)
-                    .transparent(true)
-                    .build()?;
-                lock_window_text_scale(&window);
-
-                let _ = window
-                    .set_position(cursor_monitor.position(cursor_monitor.x, cursor_monitor.y));
-
-                // The build-time inner_size above was interpreted with the DPI of
-                // whatever monitor the window materialized on; now that it sits on the
-                // cursor monitor, re-apply the logical size so it converts with that
-                // monitor's scale, then verify against the expected physical size.
-                #[cfg(windows)]
-                {
-                    let _ = window.set_size(LogicalSize::new(
-                        cursor_monitor.width,
-                        cursor_monitor.height,
-                    ));
-                    tokio::time::sleep(std::time::Duration::from_millis(5)).await;
-
-                    let expected_physical_width =
-                        (cursor_monitor.width * cursor_monitor.scale).round();
-                    match window.inner_size() {
-                        Ok(actual_physical_size)
-                            if expected_physical_width != actual_physical_size.width as f64 =>
-                        {
-                            let _ = window.set_size(LogicalSize::new(
-                                cursor_monitor.width,
-                                cursor_monitor.height,
-                            ));
-                        }
-                        Ok(_) => {}
-                        Err(err) => {
-                            warn!(%err, "Failed to read recordings overlay inner size");
-                        }
-                    }
-                }
-
-                #[cfg(target_os = "macos")]
-                {
-                    app.run_on_main_thread({
-                        let window = window.clone();
-                        move || {
-                            use tauri_nspanel::cocoa::appkit::NSWindowCollectionBehavior;
-                            use crate::panel_manager::try_to_panel;
-
-                            let panel = match try_to_panel(&window) {
-                                Ok(p) => p,
-                                Err(e) => {
-                                    tracing::error!("Failed to convert recordings overlay to panel: {}", e);
-                                    return;
-                                }
-                            };
-
-                            panel.set_level(cocoa::appkit::NSMainMenuWindowLevel);
-
-                            panel.set_collection_behaviour(
-                                NSWindowCollectionBehavior::NSWindowCollectionBehaviorTransient
-                                    | NSWindowCollectionBehavior::NSWindowCollectionBehaviorMoveToActiveSpace
-                                    | NSWindowCollectionBehavior::NSWindowCollectionBehaviorFullScreenAuxiliary
-                                    | NSWindowCollectionBehavior::NSWindowCollectionBehaviorIgnoresCycle,
-                            );
-
-                            #[allow(non_upper_case_globals)]
-                            const NSWindowStyleMaskNonActivatingPanel: i32 = 1 << 7;
-                            panel.set_style_mask(NSWindowStyleMaskNonActivatingPanel);
-                        }
-                    })
-                    .ok();
-                }
-
-                fake_window::spawn_fake_window_listener(app.clone(), window.clone());
-
-                window
-            }
-        };
-
-        // removing this for now as it causes windows to just stay hidden sometimes -_-
-        // window.hide().ok();
-
-        #[cfg(target_os = "macos")]
-        if let Some(position) = _id.traffic_lights_position() {
-            add_traffic_lights(&window, position);
-        }
-
-        #[cfg(target_os = "macos")]
-        if _id.activates_dock() {
-            crate::permissions::sync_macos_dock_visibility(app);
-        }
-
-        if let Some(opening) = project_opening.as_mut() {
-            opening.commit();
-        }
-        Ok(window)
-    }
-
-    fn window_builder<'a>(
-        &'a self,
-        app: &'a AppHandle,
-        url: impl Into,
-    ) -> WebviewWindowBuilder<'a, Wry, AppHandle> {
-        let id = self.id(app);
-        self.window_builder_with_id(app, url, &id, id.label())
-    }
-
-    fn window_builder_with_label<'a>(
-        &'a self,
-        app: &'a AppHandle,
-        url: impl Into,
-        label: impl Into,
-    ) -> WebviewWindowBuilder<'a, Wry, AppHandle> {
-        let id = self.id(app);
-
-        self.window_builder_with_id(app, url, &id, label)
-    }
-
-    fn window_builder_with_id<'a>(
-        &'a self,
-        app: &'a AppHandle,
-        url: impl Into,
-        id: &CapWindowId,
-        label: impl Into,
-    ) -> WebviewWindowBuilder<'a, Wry, AppHandle> {
-        let settings = GeneralSettingsStore::get(app).ok().flatten();
-        let window_transparency_enabled = settings
-            .as_ref()
-            .map(|s| s.window_transparency)
-            .unwrap_or(false);
-        let theme = settings
-            .map(|s| match s.theme {
-                AppTheme::System => None,
-                AppTheme::Light => Some(tauri::Theme::Light),
-                AppTheme::Dark => Some(tauri::Theme::Dark),
-            })
-            .unwrap_or(None);
-
-        let mut builder = WebviewWindow::builder(app, label, WebviewUrl::App(url.into()))
-            .title(id.title())
-            .visible(false)
-            .accept_first_mouse(true)
-            .shadow(true)
-            .theme(theme)
-            .devtools(cfg!(debug_assertions));
-
-        #[cfg(all(target_os = "macos", debug_assertions))]
-        if matches!(id, CapWindowId::Main) {
-            // Main stays hidden until its frontend mounts; WebKit must finish loading Vite first.
-            builder = builder
-                .background_throttling(tauri::utils::config::BackgroundThrottlingPolicy::Disabled);
-        }
-
-        if !id.is_transparent() {
-            let is_dark = match theme {
-                Some(tauri::Theme::Dark) => true,
-                Some(tauri::Theme::Light) => false,
-                None | Some(_) => is_system_dark_mode(),
-            };
-
-            let bg_color = if is_dark { "#141414" } else { "#ffffff" };
-            let init_script = format!(
-                r#"(function(){{var s=document.createElement('style');s.textContent='html,body{{background-color:{bg_color}}}';document.documentElement.appendChild(s);}})();"#
-            );
-            builder = builder.initialization_script(&init_script);
-
-            // Native backing color so the window is themed before the webview's
-            // first paint, allowing windows to be shown immediately without a
-            // white/black flash. Skipped when the user has window transparency
-            // enabled: an opaque native background would sit behind the
-            // translucent webview content and defeat the effect.
-            if !window_transparency_enabled {
-                let native_bg = if is_dark {
-                    tauri::window::Color(0x14, 0x14, 0x14, 0xff)
-                } else {
-                    tauri::window::Color(0xff, 0xff, 0xff, 0xff)
-                };
-                builder = builder.background_color(native_bg);
-            }
-        }
-
-        if let Some(min) = id.min_size() {
-            let preferred = id.preferred_content_size().unwrap_or(min);
-            let (inner, minimum) = initial_content_window_fit(app, id)
-                .map(|(fit, _)| (fit.inner, fit.minimum))
-                .unwrap_or((preferred, min));
-            builder = builder
-                .inner_size(inner.0, inner.1)
-                .min_inner_size(minimum.0, minimum.1);
-        }
-
-        #[cfg(target_os = "macos")]
-        {
-            if id.traffic_lights_position().is_some() {
-                builder = builder
-                    .hidden_title(true)
-                    .title_bar_style(tauri::TitleBarStyle::Overlay);
-            } else {
-                builder = builder.decorations(false)
-            }
-        }
-
-        #[cfg(windows)]
-        {
-            let browser_args = windows_webview2_browser_args();
-            let browser_args_json = serde_json::to_string(&browser_args)
-                .expect("Failed to serialize Windows WebView2 browser arguments");
-            builder = builder
-                .decorations(false)
-                .zoom_hotkeys_enabled(false)
-                .additional_browser_args(&browser_args)
-                .initialization_script(format!(
-                    "window.__CAP__ = window.__CAP__ ?? {{}}; window.__CAP__.windowsWebview2BrowserArgs = {browser_args_json};"
-                ));
-        }
-
-        // Linux has no native macOS-style traffic lights, so we drop the window
-        // manager decorations and draw our own chrome (matching the macOS layout).
-        #[cfg(target_os = "linux")]
-        {
-            builder = builder.decorations(false);
-        }
-
-        builder
-    }
-
-    pub fn id(&self, app: &AppHandle) -> CapWindowId {
-        match self {
-            ShowCapWindow::Main { .. } => CapWindowId::Main,
-            ShowCapWindow::Settings { .. } => CapWindowId::Settings,
-            ShowCapWindow::Editor { project_path } => {
-                let state = app.state::();
-                let id = project_window_id_for_key(&state.ids, &project_window_key(project_path))
-                    .expect("editor window is not reserved");
-                CapWindowId::Editor { id }
-            }
-            ShowCapWindow::RecordingsOverlay => CapWindowId::RecordingsOverlay,
-            ShowCapWindow::TargetSelectOverlay { display_id, .. } => {
-                CapWindowId::TargetSelectOverlay {
-                    display_id: display_id.clone(),
-                }
-            }
-            ShowCapWindow::WindowCaptureOccluder { screen_id } => {
-                CapWindowId::WindowCaptureOccluder {
-                    screen_id: screen_id.clone(),
-                }
-            }
-            ShowCapWindow::CaptureArea { .. } => CapWindowId::CaptureArea,
-            ShowCapWindow::Camera { .. } => CapWindowId::Camera,
-            ShowCapWindow::InProgressRecording { .. } => CapWindowId::RecordingControls,
-            ShowCapWindow::Upgrade => CapWindowId::Upgrade,
-            ShowCapWindow::ModeSelect => CapWindowId::ModeSelect,
-            ShowCapWindow::Onboarding => CapWindowId::Onboarding,
-            ShowCapWindow::ScreenshotEditor { path } => {
-                let state = app.state::();
-                let id = project_window_id_for_key(&state.ids, &project_window_key(path))
-                    .expect("screenshot editor window is not reserved");
-                CapWindowId::ScreenshotEditor { id }
-            }
-        }
-    }
-}
-
-fn lock_window_text_scale(_window: &WebviewWindow) {
-    #[cfg(windows)]
-    {
-        let scale_factor = match _window.scale_factor() {
-            Ok(scale_factor) => scale_factor,
-            Err(e) => {
-                warn!("Failed to read window scale factor: {}", e);
-                return;
-            }
-        };
-
-        if let Err(e) = _window.with_webview(move |webview| unsafe {
-            use webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2Controller3;
-            use windows_core::Interface;
-
-            let controller = webview.controller();
-
-            if let Err(e) = controller.SetZoomFactor(1.0) {
-                warn!("Failed to lock WebView zoom factor: {}", e);
-            }
-
-            let Ok(controller3) = controller.cast::() else {
-                warn!("Failed to access WebView2 controller scale APIs");
-                return;
-            };
-
-            if let Err(e) = controller3.SetShouldDetectMonitorScaleChanges(false) {
-                warn!("Failed to disable WebView scale detection: {}", e);
-            }
-
-            if let Err(e) = controller3.SetRasterizationScale(scale_factor) {
-                warn!("Failed to lock WebView rasterization scale: {}", e);
-            }
-        }) {
-            warn!("Failed to access platform WebView: {}", e);
-        }
-    }
-}
-
-/// `lock_window_text_scale` disables WebView2's own monitor-scale detection
-/// (so the Windows text-size setting can't zoom the UI), which also stops it
-/// following per-monitor DPI. The new scale factor must be forwarded here on
-/// every `ScaleFactorChanged`, or a window dragged to a monitor with
-/// different scaling keeps rasterizing and laying out at the old DPI.
-pub fn update_window_rasterization_scale(_window: &WebviewWindow, _scale_factor: f64) {
-    #[cfg(windows)]
-    {
-        if let Err(e) = _window.with_webview(move |webview| unsafe {
-            use webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2Controller3;
-            use windows_core::Interface;
-
-            let controller = webview.controller();
-
-            let Ok(controller3) = controller.cast::() else {
-                warn!("Failed to access WebView2 controller scale APIs");
-                return;
-            };
-
-            if let Err(e) = controller3.SetRasterizationScale(_scale_factor) {
-                warn!("Failed to update WebView rasterization scale: {}", e);
-            }
-        }) {
-            warn!("Failed to access platform WebView: {}", e);
-        }
-    }
-}
-
-#[cfg(target_os = "macos")]
-fn add_traffic_lights(window: &WebviewWindow, controls_inset: Option>) {
-    use crate::platform::delegates;
-
-    let target_window = window.clone();
-    window
-        .run_on_main_thread(move || {
-            delegates::setup(
-                target_window.as_ref().window(),
-                controls_inset.unwrap_or(DEFAULT_TRAFFIC_LIGHTS_INSET),
-            );
-
-            let c_win = target_window.clone();
-            target_window.on_window_event(move |event| match event {
-                tauri::WindowEvent::ThemeChanged(..) | tauri::WindowEvent::Focused(..) => {
-                    position_traffic_lights_impl(&c_win.as_ref().window(), controls_inset);
-                }
-                _ => {}
-            });
-        })
-        .ok();
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(window))]
-pub fn set_theme(window: tauri::Window, theme: AppTheme) {
-    let _ = window.set_theme(match theme {
-        AppTheme::System => None,
-        AppTheme::Light => Some(tauri::Theme::Light),
-        AppTheme::Dark => Some(tauri::Theme::Dark),
-    });
-
-    #[cfg(target_os = "macos")]
-    match CapWindowId::from_str(window.label()) {
-        Ok(win) if win.traffic_lights_position().is_some() => position_traffic_lights(window, None),
-        Ok(_) | Err(_) => {}
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(_window))]
-pub fn position_traffic_lights(_window: tauri::Window, _controls_inset: Option<(f64, f64)>) {
-    #[cfg(target_os = "macos")]
-    position_traffic_lights_impl(
-        &_window,
-        _controls_inset.map(LogicalPosition::from).or_else(|| {
-            // Attempt to get the default inset from the window's traffic lights position
-            CapWindowId::from_str(_window.label())
-                .ok()
-                .and_then(|id| id.traffic_lights_position().flatten())
-        }),
-    );
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(_window))]
-pub fn set_teleprompter_window_level(_window: tauri::Window, _always_on_top: bool) {
-    #[cfg(target_os = "macos")]
-    if _window.label() == CapWindowId::Teleprompter.to_string() {
-        let level = if _always_on_top {
-            TELEPROMPTER_PANEL_LEVEL
-        } else {
-            objc2_app_kit::NSNormalWindowLevel
-        };
-        crate::platform::set_window_level(_window, level);
-    }
-
-    #[cfg(not(target_os = "macos"))]
-    if _window.label() == CapWindowId::Teleprompter.to_string()
-        && let Err(error) = _window.set_always_on_top(_always_on_top)
-    {
-        warn!(?error, "Failed to update teleprompter window level");
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(_window))]
-pub fn set_teleprompter_window_opacity(_window: tauri::Window, _opacity: f64) {
-    #[cfg(target_os = "macos")]
-    if _window.label() == CapWindowId::Teleprompter.to_string() {
-        crate::platform::set_window_opacity(_window, _opacity);
-    }
-}
-
-#[cfg(target_os = "macos")]
-fn position_traffic_lights_impl(
-    window: &tauri::Window,
-    controls_inset: Option>,
-) {
-    use crate::platform::delegates::{UnsafeWindowHandle, position_window_controls};
-    let c_win = window.clone();
-    window
-        .run_on_main_thread(move || {
-            let ns_window = match c_win.ns_window() {
-                Ok(handle) => handle,
-                Err(_) => return,
-            };
-            position_window_controls(
-                UnsafeWindowHandle(ns_window),
-                &controls_inset.unwrap_or(DEFAULT_TRAFFIC_LIGHTS_INSET),
-            );
-        })
-        .ok();
-}
-
-// Capture exclusion (WDA_EXCLUDEFROMCAPTURE / NSWindowSharingType::None) also hides
-// the window from "capture-based" displays such as virtual/indirect/dummy-HDMI or
-// mirrored monitors, making it invisible and unreachable. We therefore only protect
-// Cap's own windows while a recording is actually active, which is the only time the
-// exclusion is meaningful.
-//
-// On known capture-based remote displays (Shadow and RDP), recording-gated exclusion hides the recording
-// controls from the user and trips DRM detectors (Shadow error S:102), so exclusion
-// is skipped entirely there — Cap's windows then appear in recordings, which is the
-// lesser evil. Overridable via the CAP_WINDOW_CAPTURE_EXCLUSION env var.
-#[cfg(target_os = "windows")]
-pub fn capture_exclusion_hides_ui() -> bool {
-    static LAST_LOGGED: std::sync::Mutex> = std::sync::Mutex::new(None);
-
-    let reason = crate::platform::win::capture_streamed_display_reason();
-
-    if let Ok(mut last) = LAST_LOGGED.lock()
-        && *last != reason
-    {
-        match &reason {
-            Some(reason) => warn!(
-                %reason,
-                "Skipping window capture exclusion: this desktop is viewed through a \
-                 capture-based stream, so excluded windows would be invisible to the user. \
-                 Cap's windows will appear in recordings."
-            ),
-            None => info!("Window capture exclusion re-enabled"),
-        }
-        *last = reason.clone();
-    }
-
-    reason.is_some()
-}
-
-#[cfg(not(target_os = "windows"))]
-pub fn capture_exclusion_hides_ui() -> bool {
-    false
-}
-
-fn content_protection_enabled(app: &AppHandle) -> bool {
-    app.try_state::>()
-        .and_then(|state| {
-            state
-                .try_read()
-                .ok()
-                .map(|app| app.is_recording_active_or_pending())
-        })
-        .unwrap_or(false)
-}
-
-fn window_capture_excluded(app: &AppHandle, window_title: &str) -> bool {
-    if window_title == CapWindowId::Teleprompter.title() {
-        return true;
-    }
-
-    let matches = |list: &[WindowExclusion]| {
-        list.iter()
-            .any(|entry| entry.matches(None, None, Some(window_title)))
-    };
-
-    GeneralSettingsStore::get(app)
-        .ok()
-        .flatten()
-        .map(|settings| matches(&settings.excluded_windows))
-        .unwrap_or_else(|| matches(&general_settings::default_excluded_windows()))
-}
-
-fn should_protect_window(app: &AppHandle, window_title: &str) -> bool {
-    content_protection_enabled(app)
-        && !capture_exclusion_hides_ui()
-        && native_content_protection_allowed(window_title)
-        && window_capture_excluded(app, window_title)
-}
-
-fn native_content_protection_allowed(window_title: &str) -> bool {
-    !cfg!(target_os = "macos") || window_title != CapWindowId::RecordingControls.title()
-}
-
-pub fn apply_content_protection(app: &AppHandle, enabled: bool) {
-    let enabled = enabled && !capture_exclusion_hides_ui();
-
-    for (label, window) in app.webview_windows() {
-        let Ok(id) = CapWindowId::from_str(&label) else {
-            continue;
-        };
-
-        // The camera window's protection depends on the recording mode (studio excludes
-        // the preview, instant keeps it) and is driven from `start_recording`. Only ever
-        // clear it here so it stays visible outside of recordings.
-        if matches!(id, CapWindowId::Camera) {
-            if !enabled {
-                let _ = window.set_content_protected(false);
-            }
-            continue;
-        }
-
-        let title = id.title();
-        let should_protect = enabled
-            && native_content_protection_allowed(&title)
-            && window_capture_excluded(app, &title);
-        let _ = window.set_content_protected(should_protect);
-
-        #[cfg(target_os = "windows")]
-        log_window_content_protection(&window, should_protect, &title);
-    }
-}
-
-#[cfg(target_os = "windows")]
-fn cached_windows_version() -> Option<&'static scap_direct3d::WindowsVersion> {
-    static VERSION: std::sync::OnceLock> =
-        std::sync::OnceLock::new();
-    VERSION
-        .get_or_init(scap_direct3d::WindowsVersion::detect)
-        .as_ref()
-}
-
-#[cfg(target_os = "windows")]
-fn display_affinity_name(value: u32) -> &'static str {
-    match value {
-        0 => "WDA_NONE",
-        1 => "WDA_MONITOR",
-        17 => "WDA_EXCLUDEFROMCAPTURE",
-        _ => "UNKNOWN",
-    }
-}
-
-#[cfg(target_os = "windows")]
-fn log_window_content_protection(window: &WebviewWindow, enabled: bool, window_title: &str) {
-    use windows::Win32::UI::WindowsAndMessaging::{
-        GetWindowDisplayAffinity, WDA_EXCLUDEFROMCAPTURE, WDA_NONE,
-    };
-
-    let expected = if enabled {
-        WDA_EXCLUDEFROMCAPTURE
-    } else {
-        WDA_NONE
-    };
-
-    if let Some(version) = cached_windows_version()
-        && enabled
-        && version.build < 19041
-    {
-        warn!(
-            window = window.label(),
-            title = window_title,
-            version = %version.display_name(),
-            expected = display_affinity_name(expected.0),
-            "Window capture exclusion is not fully supported on this Windows build"
-        );
-    }
-
-    let hwnd = match window.hwnd() {
-        Ok(hwnd) => windows::Win32::Foundation::HWND(hwnd.0),
-        Err(error) => {
-            warn!(
-                window = window.label(),
-                title = window_title,
-                error = %error,
-                "Failed to get HWND for content protection diagnostics"
-            );
-            return;
-        }
-    };
-
-    let mut applied = 0u32;
-    match unsafe { GetWindowDisplayAffinity(hwnd, &mut applied) } {
-        Ok(()) => {
-            if applied == expected.0 {
-                debug!(
-                    window = window.label(),
-                    title = window_title,
-                    expected = display_affinity_name(expected.0),
-                    applied = display_affinity_name(applied),
-                    "Window content protection verified"
-                );
-            } else {
-                warn!(
-                    window = window.label(),
-                    title = window_title,
-                    expected = display_affinity_name(expected.0),
-                    expected_raw = expected.0,
-                    applied = display_affinity_name(applied),
-                    applied_raw = applied,
-                    "Window content protection mismatch"
-                );
-            }
-        }
-        Err(error) => {
-            warn!(
-                window = window.label(),
-                title = window_title,
-                expected = display_affinity_name(expected.0),
-                error = %error,
-                "Failed to query window display affinity"
-            );
-        }
-    }
-}
-
-#[tauri::command]
-#[specta::specta]
-#[instrument(skip(app))]
-pub fn refresh_window_content_protection(app: AppHandle) -> Result<(), String> {
-    let enabled = content_protection_enabled(&app);
-    apply_content_protection(&app, enabled);
-    Ok(())
-}
-
-// Credits: tauri-plugin-window-state
-trait MonitorExt {
-    fn intersects(
-        &self,
-        position: PhysicalPosition,
-        size: PhysicalSize,
-        scale: f64,
-    ) -> bool;
-}
-
-impl MonitorExt for Display {
-    fn intersects(
-        &self,
-        position: PhysicalPosition,
-        size: PhysicalSize,
-        _scale: f64,
-    ) -> bool {
-        #[cfg(target_os = "macos")]
-        {
-            let Some(bounds) = self.raw_handle().logical_bounds() else {
-                return false;
-            };
-
-            let left = (bounds.position().x() * _scale) as i32;
-            let right = left + (bounds.size().width() * _scale) as i32;
-            let top = (bounds.position().y() * _scale) as i32;
-            let bottom = top + (bounds.size().height() * _scale) as i32;
-
-            [
-                (position.x, position.y),
-                (position.x + size.width as i32, position.y),
-                (position.x, position.y + size.height as i32),
-                (
-                    position.x + size.width as i32,
-                    position.y + size.height as i32,
-                ),
-            ]
-            .into_iter()
-            .any(|(x, y)| x >= left && x < right && y >= top && y < bottom)
-        }
-
-        #[cfg(windows)]
-        {
-            let Some(bounds) = self.raw_handle().physical_bounds() else {
-                return false;
-            };
-
-            let left = bounds.position().x() as i32;
-            let right = left + bounds.size().width() as i32;
-            let top = bounds.position().y() as i32;
-            let bottom = top + bounds.size().height() as i32;
-
-            [
-                (position.x, position.y),
-                (position.x + size.width as i32, position.y),
-                (position.x, position.y + size.height as i32),
-                (
-                    position.x + size.width as i32,
-                    position.y + size.height as i32,
-                ),
-            ]
-            .into_iter()
-            .any(|(x, y)| x >= left && x < right && y >= top && y < bottom)
-        }
-
-        #[cfg(target_os = "linux")]
-        {
-            let Some(bounds) = self.raw_handle().physical_bounds() else {
-                return false;
-            };
-
-            let left = bounds.position().x() as i32;
-            let right = left + bounds.size().width() as i32;
-            let top = bounds.position().y() as i32;
-            let bottom = top + bounds.size().height() as i32;
-
-            [
-                (position.x, position.y),
-                (position.x + size.width as i32, position.y),
-                (position.x, position.y + size.height as i32),
-                (
-                    position.x + size.width as i32,
-                    position.y + size.height as i32,
-                ),
-            ]
-            .into_iter()
-            .any(|(x, y)| x >= left && x < right && y >= top && y < bottom)
-        }
-    }
-}
-
-#[specta::specta]
-#[tauri::command(async)]
-#[instrument(skip(_window))]
-pub async fn apply_macos_liquid_glass_background(
-    _window: tauri::Window,
-    _enabled: bool,
-    _radius: f64,
-) -> Result {
-    #[cfg(target_os = "macos")]
-    {
-        let window = _window.clone();
-        let (tx, rx) = tokio::sync::oneshot::channel();
-
-        _window
-            .run_on_main_thread(move || {
-                let result = if window.label() == CapWindowId::Main.label() {
-                    crate::platform::apply_main_window_liquid_glass_background(
-                        &window, _enabled, _radius,
-                    )
-                } else {
-                    crate::platform::apply_liquid_glass_background(&window, _enabled, _radius)
-                };
-                let _ = tx.send(result);
-            })
-            .map_err(|error| error.to_string())?;
-
-        return rx
-            .await
-            .map_err(|_| "macOS Liquid Glass task was cancelled".to_string())?;
-    }
-
-    #[cfg(not(target_os = "macos"))]
-    {
-        Ok(false)
-    }
-}
-
-#[specta::specta]
-#[tauri::command(async)]
-#[instrument(skip(_window))]
-pub fn set_window_transparent(_window: tauri::Window, _value: bool) {
-    #[cfg(target_os = "macos")]
-    {
-        let ns_win = _window
-            .ns_window()
-            .expect("Failed to get native window handle")
-            as *const objc2_app_kit::NSWindow;
-
-        unsafe {
-            (*ns_win).setOpaque(!_value);
-        }
-    }
-}
-
-fn project_window_key(path: &Path) -> PathBuf {
-    std::fs::canonicalize(path)
-        .or_else(|_| std::path::absolute(path))
-        .unwrap_or_else(|_| path.to_path_buf())
-}
-
-fn project_window_id_for_key(ids: &Mutex>, key: &Path) -> Option {
-    let entries = ids.lock().unwrap().clone();
-    entries
-        .into_iter()
-        .find_map(|(path, id)| (project_window_key(&path) == key).then_some(id))
-}
-
-fn next_project_window_id(counter: &AtomicU32) -> tauri::Result {
-    counter
-        .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |value| {
-            value.checked_add(1)
-        })
-        .map_err(|_| tauri::Error::Io(std::io::Error::other("project window IDs exhausted")))
-}
-
-#[derive(Default, Clone)]
-struct ProjectWindowOpenGates {
-    paths: Arc>,
-}
-
-type ProjectWindowGateMap = HashMap>>;
-
-impl ProjectWindowOpenGates {
-    fn for_path(&self, key: PathBuf) -> Arc> {
-        let mut paths = self.paths.lock().unwrap();
-        paths.retain(|_, gate| gate.strong_count() > 0);
-        if let Some(gate) = paths.get(&key).and_then(Weak::upgrade) {
-            return gate;
-        }
-        let gate = Arc::new(tokio::sync::Mutex::new(()));
-        paths.insert(key, Arc::downgrade(&gate));
-        gate
-    }
-}
-
-struct ProjectWindowOpening {
-    app: AppHandle,
-    ids: Arc>>,
-    id: CapWindowId,
-    existing_window: Option,
-    owned_window: Option,
-    committed: bool,
-    _gate: tokio::sync::OwnedMutexGuard<()>,
-}
-
-impl ProjectWindowOpening {
-    async fn acquire(
-        app: &AppHandle,
-        path: &Path,
-        ids: Arc>>,
-        counter: &AtomicU32,
-        gates: &ProjectWindowOpenGates,
-        make_id: fn(u32) -> CapWindowId,
-    ) -> tauri::Result {
-        let key = project_window_key(path);
-        let gate = gates.for_path(key.clone()).lock_owned().await;
-        let previous_id = project_window_id_for_key(&ids, &key);
-        if let Some(previous_id) = previous_id {
-            let id = make_id(previous_id);
-            if let Some(window) = id.get(app) {
-                return Ok(Self {
-                    app: app.clone(),
-                    ids,
-                    id,
-                    existing_window: Some(window),
-                    owned_window: None,
-                    committed: true,
-                    _gate: gate,
-                });
-            }
-        }
-
-        let numeric_id = next_project_window_id(counter)?;
-        let id = make_id(numeric_id);
-        {
-            let mut entries = ids.lock().unwrap();
-            entries.retain(|(_, id)| Some(*id) != previous_id);
-            entries.push((path.to_path_buf(), numeric_id));
-        }
-        Ok(Self {
-            app: app.clone(),
-            ids,
-            id,
-            existing_window: None,
-            owned_window: None,
-            committed: false,
-            _gate: gate,
-        })
-    }
-
-    fn own_window(&mut self, window: &WebviewWindow) {
-        self.owned_window = Some(window.clone());
-    }
-
-    fn commit(&mut self) {
-        self.committed = true;
-    }
-}
-
-impl Drop for ProjectWindowOpening {
-    fn drop(&mut self) {
-        if self.committed {
-            return;
-        }
-        let numeric_id = match self.id {
-            CapWindowId::Editor { id } | CapWindowId::ScreenshotEditor { id } => id,
-            _ => return,
-        };
-        self.ids
-            .lock()
-            .unwrap_or_else(std::sync::PoisonError::into_inner)
-            .retain(|(_, id)| *id != numeric_id);
-        if let Some(window) = self.owned_window.take() {
-            if let Err(error) = window.destroy() {
-                warn!(label = %self.id.label(), %error, "Failed to destroy unfinished project window");
-            }
-            let native_window = window.as_ref().window().clone();
-            match self.id {
-                CapWindowId::Editor { .. } => {
-                    tauri::async_runtime::spawn(EditorInstances::remove(native_window));
-                }
-                CapWindowId::ScreenshotEditor { .. } => {
-                    tauri::async_runtime::spawn(ScreenshotEditorInstances::remove(native_window));
-                }
-                _ => {}
-            }
-        }
-        let app = self.app.clone();
-        let id = self.id.clone();
-        tauri::async_runtime::spawn(async move {
-            let label = id.label();
-            match id {
-                CapWindowId::Editor { .. } => {
-                    PendingEditorInstances::get(&app)
-                        .cancel_prewarm(&label)
-                        .await;
-                }
-                CapWindowId::ScreenshotEditor { .. } => {
-                    PendingScreenshotEditorInstances::get(&app)
-                        .cancel_prewarm(&label)
-                        .await;
-                }
-                _ => {}
-            }
-        });
-    }
-}
-
-#[derive(Default, Clone)]
-pub struct EditorWindowIds {
-    pub ids: Arc>>,
-    pub counter: Arc,
-    open_gates: ProjectWindowOpenGates,
-}
-
-impl EditorWindowIds {
-    pub fn get(app: &AppHandle) -> Self {
-        app.state::().deref().clone()
-    }
-}
-
-#[derive(Default, Clone)]
-pub struct ScreenshotEditorWindowIds {
-    pub ids: Arc>>,
-    pub counter: Arc,
-    open_gates: ProjectWindowOpenGates,
-}
-
-impl ScreenshotEditorWindowIds {
-    pub fn get(app: &AppHandle) -> Self {
-        app.state::().deref().clone()
-    }
-}
-
-#[derive(Default, Clone)]
-pub struct EditorRecordingTarget(pub Arc>>);
-
-impl EditorRecordingTarget {
-    pub fn get(app: &AppHandle) -> Self {
-        app.state::().deref().clone()
-    }
-
-    pub fn set(app: &AppHandle, path: Option) {
-        *Self::get(app).0.lock().unwrap() = path;
-    }
-
-    pub fn current(app: &AppHandle) -> Option {
-        Self::get(app).0.lock().unwrap().clone()
-    }
-
-    pub fn take(app: &AppHandle) -> Option {
-        Self::get(app).0.lock().unwrap().take()
-    }
-}
-
-pub fn editor_window_for_path(app: &AppHandle, path: &std::path::Path) -> Option {
-    let ids = EditorWindowIds::get(app);
-    let id = project_window_id_for_key(&ids.ids, &project_window_key(path))?;
-    CapWindowId::Editor { id }.get(app)
-}
-
-#[cfg(test)]
-mod content_window_tests {
-    use super::*;
-
-    fn rect(x: f64, y: f64, width: f64, height: f64) -> ContentWindowRect {
-        ContentWindowRect {
-            x,
-            y,
-            width,
-            height,
-        }
-    }
-
-    fn assert_inside(frame: ContentWindowRect, area: ContentWindowRect) {
-        assert!(frame.x >= area.x + 16.0);
-        assert!(frame.y >= area.y + 16.0);
-        assert!(frame.x + frame.width <= area.x + area.width - 16.0);
-        assert!(frame.y + frame.height <= area.y + area.height - 16.0);
-    }
-
-    #[test]
-    fn small_display_fits_all_content_windows_and_lowers_oversized_minimums() {
-        let area = rect(0.0, 25.0, 1024.0, 703.0);
-        for id in [
-            CapWindowId::Settings,
-            CapWindowId::Editor { id: 0 },
-            CapWindowId::ScreenshotEditor { id: 0 },
-        ] {
-            let preferred = id.preferred_content_size().unwrap();
-            let fit = fit_content_window(
-                area,
-                rect(0.0, 0.0, preferred.0, preferred.1),
-                preferred,
-                id.min_size().unwrap(),
-                Some(preferred),
-            )
-            .unwrap();
-            assert_inside(fit.frame, area);
-            assert!(fit.minimum.0 <= fit.inner.0);
-            assert!(fit.minimum.1 <= fit.inner.1);
-        }
-    }
-
-    #[test]
-    fn roomy_display_keeps_preferred_size_and_minimum() {
-        let area = rect(0.0, 24.0, 2560.0, 1376.0);
-        let preferred = (1275.0, 800.0);
-        let fit = fit_content_window(
-            area,
-            rect(0.0, 0.0, 1275.0, 800.0),
-            preferred,
-            preferred,
-            Some(preferred),
-        )
-        .unwrap();
-        assert_eq!(fit.inner, preferred);
-        assert_eq!(fit.minimum, preferred);
-        assert_inside(fit.frame, area);
-    }
-
-    #[test]
-    fn decorated_window_fits_outer_frame_on_negative_origin_display() {
-        let area = rect(-1536.0, 24.0, 1536.0, 800.0);
-        let fit = fit_content_window(
-            area,
-            rect(0.0, 0.0, 1291.0, 839.0),
-            (1275.0, 800.0),
-            (1275.0, 800.0),
-            Some((1275.0, 800.0)),
-        )
-        .unwrap();
-        assert_eq!(fit.inner, (1275.0, 729.0));
-        assert_eq!(fit.minimum, (1275.0, 729.0));
-        assert_inside(fit.frame, area);
-    }
-
-    #[test]
-    fn work_area_uses_the_target_monitors_scale() {
-        for scale in [1.0, 1.25, 2.0] {
-            let position = PhysicalPosition::new(-1920, 30);
-            let size = PhysicalSize::new(1920, 1000);
-            let area = logical_work_area(position, size, scale).unwrap();
-            let fit = fit_content_window(
-                area,
-                rect(area.x, area.y, 1275.0, 800.0),
-                (1275.0, 800.0),
-                (1275.0, 800.0),
-                Some((1275.0, 800.0)),
-            )
-            .unwrap();
-            assert_inside(fit.frame, area);
-            assert!(fit.frame.x * scale >= position.x as f64);
-            assert!(
-                (fit.frame.x + fit.frame.width) * scale <= (position.x + size.width as i32) as f64
-            );
-        }
-        assert!(
-            logical_work_area(
-                PhysicalPosition::new(0, 0),
-                PhysicalSize::new(1024, 768),
-                0.0
-            )
-            .is_none()
-        );
-    }
-
-    #[test]
-    fn reopening_shrinks_and_recovers_an_oversized_offscreen_window() {
-        let area = rect(1920.0, 0.0, 1024.0, 728.0);
-        let fit = fit_content_window(
-            area,
-            rect(-2000.0, 3000.0, 1800.0, 1200.0),
-            (1800.0, 1200.0),
-            (1275.0, 800.0),
-            None,
-        )
-        .unwrap();
-        assert_eq!(fit.inner, (992.0, 696.0));
-        assert_inside(fit.frame, area);
-    }
-
-    #[test]
-    fn reopening_preserves_a_valid_user_size_and_position() {
-        let area = rect(0.0, 24.0, 1920.0, 1016.0);
-        let frame = rect(43.0, 71.0, 900.0, 650.0);
-        let fit = fit_content_window(area, frame, (900.0, 650.0), (780.0, 560.0), None).unwrap();
-        assert_eq!(fit.frame, frame);
-    }
-
-    #[test]
-    fn invalid_or_unusable_geometry_is_ignored() {
-        for area in [
-            rect(0.0, 0.0, 0.0, 768.0),
-            rect(0.0, 0.0, 20.0, 20.0),
-            rect(f64::NAN, 0.0, 1024.0, 768.0),
-        ] {
-            assert!(
-                fit_content_window(
-                    area,
-                    rect(0.0, 0.0, 1275.0, 800.0),
-                    (1275.0, 800.0),
-                    (1275.0, 800.0),
-                    None
-                )
-                .is_none()
-            );
-        }
-    }
-
-    #[test]
-    fn only_macos_controls_bypass_native_content_protection() {
-        assert_eq!(
-            native_content_protection_allowed(&CapWindowId::RecordingControls.title()),
-            !cfg!(target_os = "macos")
-        );
-        assert!(native_content_protection_allowed(
-            &CapWindowId::Camera.title()
-        ));
-        assert!(native_content_protection_allowed(
-            &CapWindowId::Settings.title()
-        ));
-        assert!(native_content_protection_allowed(
-            &CapWindowId::Teleprompter.title()
-        ));
-    }
-
-    #[tokio::test]
-    async fn panel_show_waits_for_acknowledgment_and_propagates_failure() {
-        let (tx, rx) = tokio::sync::oneshot::channel();
-        let wait = await_window_operation(rx, "Test panel", Duration::from_secs(1));
-        tokio::pin!(wait);
-        assert!(futures::poll!(&mut wait).is_pending());
-        tx.send(Err("Native panel conversion failed".to_string()))
-            .unwrap();
-        assert_eq!(
-            wait.await,
-            Err("Native panel conversion failed".to_string())
-        );
-    }
-
-    #[tokio::test]
-    async fn timed_out_panel_show_cancels_queued_native_work() {
-        let (tx, rx) = tokio::sync::oneshot::channel();
-        let result = await_window_operation(rx, "Test panel", Duration::ZERO).await;
-        assert_eq!(result, Err("Test panel timed out".to_string()));
-        assert!(tx.is_closed());
-    }
-
-    #[tokio::test]
-    async fn panel_show_success_and_cancel_are_distinct() {
-        let (tx, rx) = tokio::sync::oneshot::channel();
-        tx.send(Ok(())).unwrap();
-        assert!(
-            await_window_operation(rx, "Test panel", Duration::from_secs(1))
-                .await
-                .is_ok()
-        );
-        let (tx, rx) = tokio::sync::oneshot::channel();
-        drop(tx);
-        assert_eq!(
-            await_window_operation(rx, "Test panel", Duration::from_secs(1)).await,
-            Err("Test panel was cancelled".to_string())
-        );
-    }
-}
diff --git a/apps/desktop/src-tauri/tauri.conf.json b/apps/desktop/src-tauri/tauri.conf.json
deleted file mode 100644
index f7dcad0c39a..00000000000
--- a/apps/desktop/src-tauri/tauri.conf.json
+++ /dev/null
@@ -1,129 +0,0 @@
-{
-	"$schema": "https://schema.tauri.app/config/2",
-	"productName": "Cap - Development",
-	"identifier": "so.cap.desktop.dev",
-	"mainBinaryName": "Cap - Development",
-	"build": {
-		"beforeDevCommand": "bun run localdev",
-		"devUrl": "http://localhost:3002",
-		"beforeBuildCommand": "bun run turbo build --filter @cap/desktop",
-		"frontendDist": "../.output/public"
-	},
-	"app": {
-		"macOSPrivateApi": true,
-		"security": {
-			"csp": "default-src 'self' ws: ipc: http://ipc.localhost; connect-src 'self' ws: wss: ipc: http://ipc.localhost https://t.cap.so; img-src 'self' asset: http://asset.localhost blob: data:; media-src 'self' asset: http://asset.localhost; script-src 'self' 'unsafe-eval' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'",
-			"assetProtocol": {
-				"enable": true,
-				"scope": [
-					"$APPDATA/**",
-					"**/*.jpg",
-					"**/*.webp",
-					"**/*.mp3",
-					"**/*.wav",
-					"**/*.m4a",
-					"**/*.ogg",
-					"**/*.flac",
-					"**/*.aac",
-					"$RESOURCE/**",
-					"**/*.riv",
-					"$HOME/**"
-				]
-			}
-		}
-	},
-	"plugins": {
-		"updater": { "active": false, "pubkey": "" },
-		"deep-link": {
-			"desktop": {
-				"schemes": ["cap-desktop"]
-			}
-		}
-	},
-	"bundle": {
-		"active": true,
-		"createUpdaterArtifacts": true,
-		"targets": "all",
-		"externalBin": [
-			"binaries/cap-muxer",
-			"binaries/cap-exporter",
-			"binaries/cap-cli"
-		],
-		"icon": [
-			"icons/32x32.png",
-			"icons/128x128.png",
-			"icons/128x128@2x.png",
-			"icons/macos/icon.icns",
-			"icons/icon.ico"
-		],
-		"resources": {
-			"assets/backgrounds/macOS/*": "assets/backgrounds/macOS/",
-			"assets/backgrounds/blue/*": "assets/backgrounds/blue/",
-			"assets/backgrounds/cities/*": "assets/backgrounds/cities/",
-			"assets/backgrounds/dark/*": "assets/backgrounds/dark/",
-			"assets/backgrounds/orange/*": "assets/backgrounds/orange/",
-			"assets/backgrounds/purple/*": "assets/backgrounds/purple/",
-			"../src/assets/rive/*.riv": "assets/rive/",
-			"../src/assets/music/*.mp3": "assets/music/"
-		},
-		"macOS": {
-			"minimumSystemVersion": "12.3",
-			"dmg": {
-				"background": "assets/dmg-background.png",
-				"appPosition": {
-					"x": 180,
-					"y": 140
-				},
-				"applicationFolderPosition": {
-					"x": 480,
-					"y": 140
-				}
-			},
-			"frameworks": ["../../../target/native-deps/Spacedrive.framework"]
-		},
-		"windows": {
-			"nsis": {
-				"headerImage": "assets/nsis-header.bmp",
-				"sidebarImage": "assets/nsis-sidebar.bmp",
-				"installerIcon": "icons/icon.ico"
-			},
-			"wix": {
-				"upgradeCode": "79f4309d-ca23-54df-b6f9-826a1d783676",
-				"bannerPath": "assets/wix-banner.bmp",
-				"dialogImagePath": "assets/wix-dialog.bmp"
-			}
-		},
-		"linux": {
-			"deb": {
-				"depends": [
-					"libwebkit2gtk-4.1-0",
-					"libgtk-3-0",
-					"libayatana-appindicator3-1",
-					"libva2",
-					"libva-drm2",
-					"pulseaudio-utils",
-					"libpipewire-0.3-0",
-					"libasound2t64 | libasound2",
-					"libxkbcommon0",
-					"libxkbcommon-x11-0",
-					"libssl3t64 | libssl3"
-				],
-				"files": {
-					"/usr/share/icons/hicolor/scalable/status/so.cap.desktop-tray-default-symbolic.svg": "icons/linux/so.cap.desktop-tray-default-symbolic.svg",
-					"/usr/share/icons/hicolor/scalable/status/so.cap.desktop-tray-instant-symbolic.svg": "icons/linux/so.cap.desktop-tray-instant-symbolic.svg",
-					"/usr/share/icons/hicolor/scalable/status/so.cap.desktop-tray-screenshot-symbolic.svg": "icons/linux/so.cap.desktop-tray-screenshot-symbolic.svg",
-					"/usr/share/icons/hicolor/scalable/status/so.cap.desktop-tray-studio-symbolic.svg": "icons/linux/so.cap.desktop-tray-studio-symbolic.svg",
-					"/usr/share/icons/hicolor/scalable/status/so.cap.desktop-tray-stop-symbolic.svg": "icons/linux/so.cap.desktop-tray-stop-symbolic.svg"
-				}
-			}
-		},
-		"fileAssociations": [
-			{
-				"ext": ["cap"],
-				"name": "Cap Project",
-				"mimeType": "application/x-cap-project",
-				"role": "Editor"
-			}
-		]
-	}
-}
diff --git a/apps/desktop/src-tauri/tauri.prod.conf.json b/apps/desktop/src-tauri/tauri.prod.conf.json
deleted file mode 100644
index 3297c552ab5..00000000000
--- a/apps/desktop/src-tauri/tauri.prod.conf.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
-	"$schema": "https://schema.tauri.app/config/2",
-	"productName": "Cap",
-	"mainBinaryName": "Cap",
-	"identifier": "so.cap.desktop",
-	"build": {
-		"beforeBundleCommand": "node scripts/prodBeforeBundle.js"
-	},
-	"plugins": {
-		"updater": {
-			"active": true,
-			"endpoints": [
-				"https://cdn.crabnebula.app/update/cap/cap/{{target}}/{{current_version}}"
-			],
-			"dialog": true,
-			"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEUyOTAzOTdFNzJFQkRFOTMKUldTVDN1dHlmam1RNHFXb1VYTXlrQk1iMFFkcjN0YitqZlA5WnZNY0ZtQ1dvM1dxK211M3VIYUQK"
-		}
-	},
-	"bundle": {
-		"macOS": {
-			"entitlements": "Entitlements.plist"
-		},
-		"windows": {
-			"wix": {
-				"upgradeCode": "a765d9de-0ecc-55d0-b8a0-61e9d3276664"
-			}
-		}
-	}
-}
diff --git a/apps/desktop/src-tauri/tests/crash_sentinel.rs b/apps/desktop/src-tauri/tests/crash_sentinel.rs
deleted file mode 100644
index 2db8770e5bb..00000000000
--- a/apps/desktop/src-tauri/tests/crash_sentinel.rs
+++ /dev/null
@@ -1,2 +0,0 @@
-#[path = "../src/crash_sentinel.rs"]
-pub mod crash_sentinel;
diff --git a/apps/desktop/src-tauri/tests/exit_shutdown.rs b/apps/desktop/src-tauri/tests/exit_shutdown.rs
deleted file mode 100644
index 6561e8442cb..00000000000
--- a/apps/desktop/src-tauri/tests/exit_shutdown.rs
+++ /dev/null
@@ -1,527 +0,0 @@
-#[path = "../src/exit_shutdown.rs"]
-mod exit_shutdown;
-
-use exit_shutdown::{
-    AppExitAction, ExitBlocked, ExitRequestDecision, UpdateInstallState, abort_join_handles,
-    app_exit_action, collect_device_inventory, handle_exit_requested, prepare_then_begin_exit,
-    read_target_under_cursor, recording_start_allowed, run_while_active, with_idle_recording_state,
-};
-use std::sync::{
-    Arc,
-    atomic::{AtomicBool, Ordering},
-};
-
-struct DropFlag(Arc);
-
-impl Drop for DropFlag {
-    fn drop(&mut self) {
-        self.0.store(true, Ordering::Release);
-    }
-}
-
-#[test]
-fn exit_refusals_do_not_start_shutdown_or_disable_active_watchers() {
-    for reason in [
-        ExitBlocked::StateUnavailable,
-        ExitBlocked::RecordingActive,
-        ExitBlocked::FinalizationActive,
-        ExitBlocked::ExportActive,
-        ExitBlocked::UploadActive,
-        ExitBlocked::UpdateInstalling,
-    ] {
-        let state = tokio::sync::RwLock::new(());
-        let exiting = AtomicBool::new(false);
-        let result = with_idle_recording_state(
-            &state,
-            |_| Err(reason),
-            || {
-                exiting.store(true, Ordering::Release);
-                true
-            },
-        );
-        assert_eq!(result, Err(reason));
-        assert!(!exiting.load(Ordering::Acquire));
-        assert_eq!(
-            run_while_active(|| exiting.load(Ordering::Acquire), || 1),
-            Some(1)
-        );
-        assert!(!reason.message().is_empty());
-    }
-    assert!(recording_start_allowed(true, false).is_err());
-    assert!(!ExitBlocked::AlreadyExiting.message().is_empty());
-}
-
-#[test]
-fn failed_handoff_preparation_leaves_recording_available_and_success_commits_before_unlock() {
-    for succeeds in [false, true] {
-        let state = tokio::sync::RwLock::new(());
-        let exiting = AtomicBool::new(false);
-        let prepared = AtomicBool::new(false);
-        let result = with_idle_recording_state(
-            &state,
-            |_| Ok(()),
-            || {
-                prepare_then_begin_exit(
-                    || {
-                        assert!(state.try_write().is_err());
-                        assert!(!exiting.load(Ordering::Acquire));
-                        prepared.store(true, Ordering::Release);
-                        if succeeds {
-                            Ok(())
-                        } else {
-                            Err("Child launch failed".into())
-                        }
-                    },
-                    || {
-                        assert!(state.try_write().is_err());
-                        assert!(prepared.load(Ordering::Acquire));
-                        !exiting.swap(true, Ordering::AcqRel)
-                    },
-                )
-            },
-        )
-        .unwrap();
-        assert_eq!(result.is_ok(), succeeds);
-        assert_eq!(exiting.load(Ordering::Acquire), succeeds);
-        assert!(state.try_write().is_ok());
-        assert_eq!(
-            recording_start_allowed(exiting.load(Ordering::Acquire), false).is_ok(),
-            !succeeds
-        );
-    }
-}
-
-#[test]
-fn recording_and_finalization_refusals_never_dispatch_an_installer() {
-    for reason in [
-        ExitBlocked::RecordingActive,
-        ExitBlocked::FinalizationActive,
-    ] {
-        let state = tokio::sync::RwLock::new(());
-        let install = UpdateInstallState::default();
-        let dispatched = AtomicBool::new(false);
-        let result = with_idle_recording_state(
-            &state,
-            |_| Err(reason),
-            || {
-                let _admission = install.begin().unwrap();
-                dispatched.store(true, Ordering::Release);
-            },
-        );
-        assert_eq!(result, Err(reason));
-        assert!(!dispatched.load(Ordering::Acquire));
-        assert!(!install.blocks_recording());
-    }
-}
-
-#[test]
-fn installer_failure_releases_only_its_start_block_without_beginning_shutdown() {
-    let state = tokio::sync::RwLock::new(false);
-    let install = UpdateInstallState::default();
-    let exiting = AtomicBool::new(false);
-    let run_install = || -> Result<(), &'static str> {
-        let _admission = with_idle_recording_state(
-            &state,
-            |_| Ok(()),
-            || {
-                assert!(state.try_write().is_err());
-                install.begin().unwrap()
-            },
-        )
-        .unwrap();
-        assert!(install.is_installing());
-        assert!(install.begin().is_none());
-        let mut recording = state.try_write().unwrap();
-        let admitted =
-            recording_start_allowed(exiting.load(Ordering::Acquire), install.blocks_recording());
-        if admitted.is_ok() {
-            *recording = true;
-        }
-        assert!(admitted.is_err());
-        assert!(!*recording);
-        Err("Installer failed before dispatch")
-    };
-    assert!(run_install().is_err());
-    assert!(!install.blocks_recording());
-    assert!(!exiting.load(Ordering::Acquire));
-    assert!(recording_start_allowed(false, install.blocks_recording()).is_ok());
-    assert!(run_install().is_err());
-    assert!(!install.blocks_recording());
-}
-
-#[test]
-fn successful_installer_keeps_start_block_only_when_it_may_exit_later() {
-    for can_exit_later in [false, true] {
-        let install = UpdateInstallState::default();
-        let admission = install.begin().unwrap();
-        assert!(install.is_installing());
-        admission.complete(can_exit_later);
-        assert!(!install.is_installing());
-        assert_eq!(install.blocks_recording(), can_exit_later);
-        assert_eq!(
-            recording_start_allowed(false, install.blocks_recording()).is_err(),
-            can_exit_later
-        );
-        assert_eq!(install.begin().is_none(), can_exit_later);
-    }
-}
-
-#[test]
-fn quit_during_stop_does_not_wait_for_or_interrupt_the_recording_writer() {
-    let state = tokio::sync::RwLock::new(true);
-    let mut stopping = state.try_write().unwrap();
-    let result = with_idle_recording_state(
-        &state,
-        |_| panic!("Busy recording state must not be inspected"),
-        || -> bool { panic!("Shutdown must not begin while Stop holds the state") },
-    );
-    assert_eq!(result, Err(ExitBlocked::StateUnavailable));
-    *stopping = false;
-    drop(stopping);
-    let exiting = AtomicBool::new(false);
-    assert_eq!(
-        with_idle_recording_state(
-            &state,
-            |recording| {
-                if *recording {
-                    Err(ExitBlocked::RecordingActive)
-                } else {
-                    Ok(())
-                }
-            },
-            || !exiting.swap(true, Ordering::AcqRel),
-        ),
-        Ok(true)
-    );
-}
-
-#[test]
-fn recording_start_and_exit_admission_cannot_both_succeed() {
-    let state = Arc::new(tokio::sync::RwLock::new(false));
-    let exiting = Arc::new(AtomicBool::new(false));
-    let (entered_tx, entered_rx) = std::sync::mpsc::sync_channel(1);
-    let (release_tx, release_rx) = std::sync::mpsc::sync_channel(1);
-    let exit = {
-        let state = state.clone();
-        let exiting = exiting.clone();
-        std::thread::spawn(move || {
-            with_idle_recording_state(
-                &state,
-                |recording| {
-                    if *recording {
-                        Err(ExitBlocked::RecordingActive)
-                    } else {
-                        Ok(())
-                    }
-                },
-                || {
-                    entered_tx.send(()).unwrap();
-                    release_rx
-                        .recv_timeout(std::time::Duration::from_secs(2))
-                        .unwrap();
-                    !exiting.swap(true, Ordering::AcqRel)
-                },
-            )
-        })
-    };
-    entered_rx
-        .recv_timeout(std::time::Duration::from_secs(2))
-        .unwrap();
-    let start_was_locked = state.try_write().is_err();
-    release_tx.send(()).unwrap();
-    assert_eq!(exit.join().unwrap(), Ok(true));
-    assert!(start_was_locked);
-    let mut starting = state.try_write().unwrap();
-    let start = recording_start_allowed(exiting.load(Ordering::Acquire), false);
-    if start.is_ok() {
-        *starting = true;
-    }
-    assert!(start.is_err());
-    assert!(!*starting);
-    drop(starting);
-
-    let started_first = tokio::sync::RwLock::new(false);
-    let mut starting = started_first.try_write().unwrap();
-    recording_start_allowed(false, false).unwrap();
-    *starting = true;
-    drop(starting);
-    assert_eq!(
-        with_idle_recording_state(
-            &started_first,
-            |recording| {
-                if *recording {
-                    Err(ExitBlocked::RecordingActive)
-                } else {
-                    Ok(())
-                }
-            },
-            || -> bool { panic!("An admitted recording must prevent shutdown") },
-        ),
-        Err(ExitBlocked::RecordingActive)
-    );
-}
-
-#[test]
-fn run_while_active_skips_operation_once_exit_begins() {
-    let called = Arc::new(AtomicBool::new(false));
-    let flag = called.clone();
-
-    let result = run_while_active(
-        || true,
-        move || {
-            flag.store(true, Ordering::Release);
-            1usize
-        },
-    );
-
-    assert_eq!(result, None);
-    assert!(!called.load(Ordering::Acquire));
-}
-
-#[test]
-fn collect_device_inventory_skips_hardware_queries_once_exit_begins() {
-    let cameras_called = Arc::new(AtomicBool::new(false));
-    let microphones_called = Arc::new(AtomicBool::new(false));
-    let camera_flag = cameras_called.clone();
-    let microphone_flag = microphones_called.clone();
-
-    let result = collect_device_inventory(
-        || true,
-        true,
-        true,
-        move || {
-            camera_flag.store(true, Ordering::Release);
-            vec![1usize]
-        },
-        move || {
-            microphone_flag.store(true, Ordering::Release);
-            vec![2usize]
-        },
-    );
-
-    assert_eq!(result, None);
-    assert!(!cameras_called.load(Ordering::Acquire));
-    assert!(!microphones_called.load(Ordering::Acquire));
-}
-
-#[test]
-fn collect_device_inventory_respects_permissions_before_probings() {
-    let cameras_called = Arc::new(AtomicBool::new(false));
-    let microphones_called = Arc::new(AtomicBool::new(false));
-    let camera_flag = cameras_called.clone();
-    let microphone_flag = microphones_called.clone();
-
-    let result = collect_device_inventory(
-        || false,
-        false,
-        true,
-        move || {
-            camera_flag.store(true, Ordering::Release);
-            vec![1usize]
-        },
-        move || {
-            microphone_flag.store(true, Ordering::Release);
-            vec![2usize]
-        },
-    );
-
-    assert_eq!(result, Some((Vec::::new(), vec![2usize])));
-    assert!(!cameras_called.load(Ordering::Acquire));
-    assert!(microphones_called.load(Ordering::Acquire));
-}
-
-#[test]
-fn collect_device_inventory_stops_before_second_probe_when_exit_begins_midway() {
-    let exiting = Arc::new(AtomicBool::new(false));
-    let cameras_called = Arc::new(AtomicBool::new(false));
-    let microphones_called = Arc::new(AtomicBool::new(false));
-    let exit_flag = exiting.clone();
-    let camera_flag = cameras_called.clone();
-    let microphone_flag = microphones_called.clone();
-
-    let result = collect_device_inventory(
-        move || exit_flag.load(Ordering::Acquire),
-        true,
-        true,
-        move || {
-            camera_flag.store(true, Ordering::Release);
-            exiting.store(true, Ordering::Release);
-            vec![1usize]
-        },
-        move || {
-            microphone_flag.store(true, Ordering::Release);
-            vec![2usize]
-        },
-    );
-
-    assert_eq!(result, None);
-    assert!(cameras_called.load(Ordering::Acquire));
-    assert!(!microphones_called.load(Ordering::Acquire));
-}
-
-#[test]
-fn read_target_under_cursor_skips_queries_once_exit_begins() {
-    let display_called = Arc::new(AtomicBool::new(false));
-    let window_called = Arc::new(AtomicBool::new(false));
-    let display_flag = display_called.clone();
-    let window_flag = window_called.clone();
-
-    let result = read_target_under_cursor(
-        || true,
-        move || {
-            display_flag.store(true, Ordering::Release);
-            Some(1usize)
-        },
-        move || {
-            window_flag.store(true, Ordering::Release);
-            Some(2usize)
-        },
-    );
-
-    assert_eq!(result, None);
-    assert!(!display_called.load(Ordering::Acquire));
-    assert!(!window_called.load(Ordering::Acquire));
-}
-
-#[test]
-fn read_target_under_cursor_stops_before_window_query_when_exit_begins_midway() {
-    let exiting = Arc::new(AtomicBool::new(false));
-    let display_called = Arc::new(AtomicBool::new(false));
-    let window_called = Arc::new(AtomicBool::new(false));
-    let exit_flag = exiting.clone();
-    let display_flag = display_called.clone();
-    let window_flag = window_called.clone();
-
-    let result = read_target_under_cursor(
-        move || exit_flag.load(Ordering::Acquire),
-        move || {
-            display_flag.store(true, Ordering::Release);
-            exiting.store(true, Ordering::Release);
-            Some(1usize)
-        },
-        move || {
-            window_flag.store(true, Ordering::Release);
-            Some(2usize)
-        },
-    );
-
-    assert_eq!(result, None);
-    assert!(display_called.load(Ordering::Acquire));
-    assert!(!window_called.load(Ordering::Acquire));
-}
-
-#[tokio::test]
-async fn abort_all_tasks_cancels_background_tracking() {
-    let task_flag = Arc::new(AtomicBool::new(false));
-    let tasks_flag = Arc::new(AtomicBool::new(false));
-
-    let task = {
-        let task_flag = task_flag.clone();
-        tokio::spawn(async move {
-            let _flag = DropFlag(task_flag);
-            std::future::pending::<()>().await;
-        })
-    };
-
-    let tasks = vec![{
-        let tasks_flag = tasks_flag.clone();
-        tokio::spawn(async move {
-            let _flag = DropFlag(tasks_flag);
-            std::future::pending::<()>().await;
-        })
-    }];
-
-    tokio::task::yield_now().await;
-    abort_join_handles(tasks, Some(task));
-    tokio::task::yield_now().await;
-
-    assert!(task_flag.load(Ordering::Acquire));
-    assert!(tasks_flag.load(Ordering::Acquire));
-}
-
-#[test]
-fn app_exit_action_matches_current_platform() {
-    #[cfg(target_os = "macos")]
-    assert_eq!(app_exit_action(7), AppExitAction::Process(7));
-
-    #[cfg(not(target_os = "macos"))]
-    assert_eq!(app_exit_action(7), AppExitAction::Runtime(7));
-}
-
-#[test]
-fn exit_requested_prevents_user_exit_when_already_exiting() {
-    let prevented = Arc::new(AtomicBool::new(false));
-    let prevented_flag = prevented.clone();
-
-    let decision = handle_exit_requested(true, false, false, false, move || {
-        prevented_flag.store(true, Ordering::Release);
-    });
-
-    assert_eq!(decision, ExitRequestDecision::AlreadyExiting);
-    assert!(prevented.load(Ordering::Acquire));
-}
-
-#[test]
-fn exit_requested_allows_runtime_exit_when_already_exiting() {
-    let prevented = Arc::new(AtomicBool::new(false));
-    let prevented_flag = prevented.clone();
-
-    let decision = handle_exit_requested(true, false, true, false, move || {
-        prevented_flag.store(true, Ordering::Release);
-    });
-
-    assert_eq!(decision, ExitRequestDecision::AllowRuntimeExit);
-    assert!(!prevented.load(Ordering::Acquire));
-}
-
-#[test]
-fn exit_requested_allows_runtime_exit_when_export_cancel_is_draining() {
-    let prevented = Arc::new(AtomicBool::new(false));
-    let prevented_flag = prevented.clone();
-
-    let decision = handle_exit_requested(true, true, true, false, move || {
-        prevented_flag.store(true, Ordering::Release);
-    });
-
-    assert_eq!(decision, ExitRequestDecision::AllowRuntimeExit);
-    assert!(!prevented.load(Ordering::Acquire));
-}
-
-#[test]
-fn exit_requested_prevents_runtime_exit_during_export() {
-    let prevented = Arc::new(AtomicBool::new(false));
-    let prevented_flag = prevented.clone();
-
-    let decision = handle_exit_requested(false, true, true, false, move || {
-        prevented_flag.store(true, Ordering::Release);
-    });
-
-    assert_eq!(decision, ExitRequestDecision::ExportActive);
-    assert!(prevented.load(Ordering::Acquire));
-}
-
-#[test]
-fn exit_requested_allows_runtime_restart_without_starting_cleanup() {
-    let prevented = Arc::new(AtomicBool::new(false));
-    let prevented_flag = prevented.clone();
-
-    let decision = handle_exit_requested(false, false, true, true, move || {
-        prevented_flag.store(true, Ordering::Release);
-    });
-
-    assert_eq!(decision, ExitRequestDecision::AllowRuntimeRestart);
-    assert!(!prevented.load(Ordering::Acquire));
-}
-
-#[test]
-fn exit_requested_allows_unpreventable_runtime_restart_during_export() {
-    let prevented = Arc::new(AtomicBool::new(false));
-    let prevented_flag = prevented.clone();
-
-    let decision = handle_exit_requested(false, true, true, true, move || {
-        prevented_flag.store(true, Ordering::Release);
-    });
-
-    assert_eq!(decision, ExitRequestDecision::AllowRuntimeRestart);
-    assert!(!prevented.load(Ordering::Acquire));
-}
diff --git a/apps/desktop/src-tauri/tests/export_estimate_request.rs b/apps/desktop/src-tauri/tests/export_estimate_request.rs
deleted file mode 100644
index 9516cd6bd1b..00000000000
--- a/apps/desktop/src-tauri/tests/export_estimate_request.rs
+++ /dev/null
@@ -1,2 +0,0 @@
-#[path = "../src/export/estimate_request.rs"]
-mod estimate_request;
diff --git a/apps/desktop/src-tauri/tests/web_api_startup.rs b/apps/desktop/src-tauri/tests/web_api_startup.rs
deleted file mode 100644
index c9cf9f24809..00000000000
--- a/apps/desktop/src-tauri/tests/web_api_startup.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-use std::panic::{AssertUnwindSafe, catch_unwind};
-use std::sync::Arc;
-
-use cap_desktop_lib::{App, web_api::ManagerExt};
-use tauri::{Manager, test::mock_app};
-use tokio::sync::RwLock;
-
-#[test]
-fn make_app_url_before_manage_does_not_panic_and_uses_default_server_url() {
-    let app = mock_app();
-    let handle = app.handle().clone();
-
-    let raw_state_access = catch_unwind(AssertUnwindSafe(|| {
-        let _ = handle.state::>>();
-    }));
-
-    assert!(raw_state_access.is_err());
-
-    let url = futures::executor::block_on(handle.make_app_url("/api/upload/multipart/initiate"));
-
-    assert_eq!(
-        url,
-        format!(
-            "{}{}",
-            option_env!("VITE_SERVER_URL").unwrap_or("https://cap.so"),
-            "/api/upload/multipart/initiate"
-        )
-    );
-
-    std::mem::forget(app);
-}
-
-#[test]
-fn is_server_url_custom_before_manage_is_safe_and_false() {
-    let app = mock_app();
-    let handle = app.handle().clone();
-
-    let is_custom = futures::executor::block_on(handle.is_server_url_custom());
-
-    assert!(!is_custom);
-
-    std::mem::forget(app);
-}
diff --git a/apps/desktop/src/app.tsx b/apps/desktop/src/app.tsx
deleted file mode 100644
index 64f8ed73a7f..00000000000
--- a/apps/desktop/src/app.tsx
+++ /dev/null
@@ -1,408 +0,0 @@
-import { Route, Router, useCurrentMatches } from "@solidjs/router";
-import {
-	focusManager,
-	QueryClient,
-	QueryClientProvider,
-} from "@tanstack/solid-query";
-import {
-	getCurrentWebviewWindow,
-	type WebviewWindow,
-} from "@tauri-apps/api/webviewWindow";
-import { message } from "@tauri-apps/plugin-dialog";
-import {
-	createEffect,
-	createSignal,
-	lazy,
-	onCleanup,
-	onMount,
-	Suspense,
-} from "solid-js";
-import { Toaster } from "solid-toast";
-
-import "@cap/ui-solid/main.css";
-import "unfonts.css";
-import "./styles/theme.css";
-
-import { CapErrorBoundary } from "./components/CapErrorBoundary";
-import WindowChromeLayout from "./routes/(window-chrome)";
-import SettingsLayout from "./routes/(window-chrome)/settings";
-import { authStore, generalSettingsStore } from "./store";
-import { identifyUser, initAnonymousUser } from "./utils/analytics";
-import { type AppTheme, commands } from "./utils/tauri";
-import titlebar from "./utils/titlebar-state";
-
-const NewMainPage = lazy(() => import("./routes/(window-chrome)/new-main"));
-const SettingsGeneralPage = lazy(
-	() => import("./routes/(window-chrome)/settings/general"),
-);
-const SettingsQualityPage = lazy(
-	() => import("./routes/(window-chrome)/settings/quality"),
-);
-const SettingsRecordingsPage = lazy(
-	() => import("./routes/(window-chrome)/settings/recordings"),
-);
-const SettingsTranscriptionPage = lazy(
-	() => import("./routes/(window-chrome)/settings/transcription"),
-);
-const SettingsScreenshotsPage = lazy(
-	() => import("./routes/(window-chrome)/settings/screenshots"),
-);
-const SettingsAutomationsPage = lazy(
-	() => import("./routes/(window-chrome)/settings/automations"),
-);
-const SettingsHotkeysPage = lazy(
-	() => import("./routes/(window-chrome)/settings/hotkeys"),
-);
-const SettingsCliPage = lazy(
-	() => import("./routes/(window-chrome)/settings/cli"),
-);
-const SettingsChangelogPage = lazy(
-	() => import("./routes/(window-chrome)/settings/changelog"),
-);
-const SettingsFeedbackPage = lazy(
-	() => import("./routes/(window-chrome)/settings/feedback"),
-);
-const SettingsExperimentalPage = lazy(
-	() => import("./routes/(window-chrome)/settings/experimental"),
-);
-const SettingsLicensePage = lazy(
-	() => import("./routes/(window-chrome)/settings/license"),
-);
-const SettingsIntegrationsPage = lazy(
-	() => import("./routes/(window-chrome)/settings/integrations"),
-);
-const SettingsS3ConfigPage = lazy(
-	() => import("./routes/(window-chrome)/settings/integrations/s3-config"),
-);
-const SettingsGoogleDriveConfigPage = lazy(
-	() =>
-		import(
-			"./routes/(window-chrome)/settings/integrations/google-drive-config"
-		),
-);
-const OnboardingPage = lazy(
-	() => import("./routes/(window-chrome)/onboarding"),
-);
-const UpgradePage = lazy(() => import("./routes/(window-chrome)/upgrade"));
-const UpdatePage = lazy(() => import("./routes/(window-chrome)/update"));
-const CameraPage = lazy(() => import("./routes/camera"));
-const CaptureAreaPage = lazy(() => import("./routes/capture-area"));
-const DebugPage = lazy(() => import("./routes/debug"));
-const EditorPage = lazy(() => import("./routes/editor"));
-const InProgressRecordingPage = lazy(
-	() => import("./routes/in-progress-recording"),
-);
-const ModeSelectPage = lazy(() => import("./routes/mode-select"));
-const NotificationsPage = lazy(() => import("./routes/notifications"));
-const RecordingsOverlayPage = lazy(() => import("./routes/recordings-overlay"));
-const ScreenshotEditorPage = lazy(() => import("./routes/screenshot-editor"));
-const TargetSelectOverlayPage = lazy(
-	() => import("./routes/target-select-overlay"),
-);
-const WindowCaptureOccluderPage = lazy(
-	() => import("./routes/window-capture-occluder"),
-);
-const TeleprompterPage = lazy(() => import("./routes/teleprompter"));
-
-const queryClient = new QueryClient({
-	defaultOptions: {
-		queries: {
-			refetchOnWindowFocus: false,
-			refetchOnReconnect: false,
-		},
-		mutations: {
-			onError: (e) => {
-				message(`Error\n${e}`);
-			},
-		},
-	},
-});
-
-export default function App() {
-	return (
-		
-			
-				
-			
-		
-	);
-}
-
-function Inner() {
-	const currentWindow = getCurrentWebviewWindow();
-	createThemeListener(currentWindow);
-	createHiddenWindowQueryPause(currentWindow);
-
-	onMount(() => {
-		initAnonymousUser();
-		// OpenPanel keeps profileId in memory only (PostHog persisted it), so
-		// sign-in-time identify alone loses attribution after an app restart.
-		void authStore.get().then((auth) => {
-			if (auth?.user_id) identifyUser(auth.user_id);
-		});
-		prewarmFontCaches();
-	});
-
-	return (
-		<>
-			
-			
-				 {
-						const matches = useCurrentMatches();
-
-						onMount(() => {
-							let autoShow = true;
-							for (const match of matches()) {
-								if (match.route.info?.AUTO_SHOW_WINDOW === false)
-									autoShow = false;
-							}
-
-							if (
-								location.pathname === "/" ||
-								location.pathname === "/camera" ||
-								location.pathname === "/target-select-overlay" ||
-								location.pathname === "/window-capture-occluder"
-							) {
-								return;
-							}
-
-							if (autoShow) {
-								void currentWindow.show();
-								void currentWindow.setFocus();
-							} else {
-								// The route reveals itself after its first themed paint to
-								// avoid a load flash. Safety net so the window is never left
-								// hidden if that self-reveal never runs (e.g. chunk load error).
-								setTimeout(() => void currentWindow.show(), 2000);
-							}
-						});
-
-						return {props.children};
-					}}
-				>
-					
-						
-						
-							
-							
-							
-							
-							
-							
-							
-							
-							
-							
-							
-							
-							
-							
-							
-							
-						
-						
-						
-						
-					
-					
-					
-					
-					
-					
-					
-					
-					
-					
-					
-					
-					
-				
-			
-		
-	);
-}
-
-// WebKit resolves the emoji fallback chain lazily on first glyph paint, which
-// can jank the first list/text render containing emoji (e.g. recording
-// titles). Drawing once to an offscreen canvas at idle warms the per-process
-// font caches instead.
-function prewarmFontCaches() {
-	const warm = () => {
-		try {
-			const canvas = document.createElement("canvas");
-			canvas.width = 32;
-			canvas.height = 32;
-			const ctx = canvas.getContext("2d");
-			if (!ctx) return;
-			ctx.font = "16px 'Geist Sans'";
-			ctx.fillText("Ag", 0, 24);
-			ctx.font = "16px system-ui";
-			ctx.fillText("😀", 0, 24);
-		} catch {}
-	};
-
-	if ("requestIdleCallback" in window) requestIdleCallback(warm);
-	else setTimeout(warm, 250);
-}
-
-function createHiddenWindowQueryPause(currentWindow: WebviewWindow) {
-	if (currentWindow.label !== "main") return;
-
-	let focusGeneration = 0;
-
-	const unlisteners = [
-		currentWindow.listen("main-window-hidden", () => {
-			focusManager.setFocused(false);
-		}),
-		currentWindow.onFocusChanged((event) => {
-			focusGeneration += 1;
-			if (event.payload) {
-				focusManager.setFocused(undefined);
-				return;
-			}
-
-			const generation = focusGeneration;
-			void currentWindow.isVisible().then((visible) => {
-				if (visible || generation !== focusGeneration) return;
-				focusManager.setFocused(false);
-			});
-		}),
-	];
-
-	onCleanup(() => {
-		for (const unlisten of unlisteners) void unlisten.then((fn) => fn());
-	});
-}
-
-function createThemeListener(currentWindow: WebviewWindow) {
-	const [appTheme, setAppTheme] = createSignal();
-	let disposed = false;
-	let stopSettingsListening: (() => void) | undefined;
-	let stopThemeListening: (() => void) | undefined;
-
-	createEffect(() => {
-		update(appTheme());
-	});
-
-	onMount(() => {
-		void generalSettingsStore
-			.get()
-			.then((settings) => {
-				if (!disposed) setAppTheme(settings?.theme ?? null);
-			})
-			.catch((error) =>
-				console.error("Failed to load general settings:", error),
-			);
-
-		void generalSettingsStore
-			.listen((settings) => {
-				setAppTheme(settings?.theme ?? null);
-			})
-			.then((unlisten) => {
-				if (disposed) {
-					unlisten();
-					return;
-				}
-				stopSettingsListening = unlisten;
-			})
-			.catch((error) =>
-				console.error("Failed to listen to general settings:", error),
-			);
-
-		void currentWindow
-			.onThemeChanged(() => update(appTheme()))
-			.then((unlisten) => {
-				if (disposed) {
-					unlisten();
-					return;
-				}
-				stopThemeListening = unlisten;
-			})
-			.catch((error) =>
-				console.error("Failed to listen to window theme changes:", error),
-			);
-	});
-
-	onCleanup(() => {
-		disposed = true;
-		stopSettingsListening?.();
-		stopThemeListening?.();
-	});
-
-	function update(appTheme: AppTheme | null | undefined) {
-		if (location.pathname === "/camera") return;
-
-		if (appTheme === undefined || appTheme === null) return;
-
-		const isDark =
-			appTheme === "dark" ||
-			(appTheme === "system" &&
-				window.matchMedia("(prefers-color-scheme: dark)").matches);
-
-		try {
-			if (appTheme === "system") {
-				localStorage.removeItem("cap-theme");
-			} else {
-				localStorage.setItem("cap-theme", appTheme);
-			}
-		} catch {}
-
-		commands.setTheme(appTheme).then(() => {
-			document.documentElement.classList.toggle("dark", isDark);
-		});
-	}
-}
diff --git a/apps/desktop/src/assets/illustrations/cloud-1.png b/apps/desktop/src/assets/illustrations/cloud-1.png
deleted file mode 100644
index 6a8b14ff6b2..00000000000
Binary files a/apps/desktop/src/assets/illustrations/cloud-1.png and /dev/null differ
diff --git a/apps/desktop/src/assets/illustrations/cloud-2.png b/apps/desktop/src/assets/illustrations/cloud-2.png
deleted file mode 100644
index 962d1695391..00000000000
Binary files a/apps/desktop/src/assets/illustrations/cloud-2.png and /dev/null differ
diff --git a/apps/desktop/src/assets/illustrations/cloud-3.png b/apps/desktop/src/assets/illustrations/cloud-3.png
deleted file mode 100644
index d4b14e4b50f..00000000000
Binary files a/apps/desktop/src/assets/illustrations/cloud-3.png and /dev/null differ
diff --git a/apps/desktop/src/assets/illustrations/color.webp b/apps/desktop/src/assets/illustrations/color.webp
deleted file mode 100644
index ebce22e50d6..00000000000
Binary files a/apps/desktop/src/assets/illustrations/color.webp and /dev/null differ
diff --git a/apps/desktop/src/assets/illustrations/display.png b/apps/desktop/src/assets/illustrations/display.png
deleted file mode 100644
index 1bab32779f2..00000000000
Binary files a/apps/desktop/src/assets/illustrations/display.png and /dev/null differ
diff --git a/apps/desktop/src/assets/illustrations/gradient.webp b/apps/desktop/src/assets/illustrations/gradient.webp
deleted file mode 100644
index f580401bc9a..00000000000
Binary files a/apps/desktop/src/assets/illustrations/gradient.webp and /dev/null differ
diff --git a/apps/desktop/src/assets/illustrations/image.webp b/apps/desktop/src/assets/illustrations/image.webp
deleted file mode 100644
index 3174f401fef..00000000000
Binary files a/apps/desktop/src/assets/illustrations/image.webp and /dev/null differ
diff --git a/apps/desktop/src/assets/illustrations/instant-mode-dark.png b/apps/desktop/src/assets/illustrations/instant-mode-dark.png
deleted file mode 100644
index 08975be3ae9..00000000000
Binary files a/apps/desktop/src/assets/illustrations/instant-mode-dark.png and /dev/null differ
diff --git a/apps/desktop/src/assets/illustrations/instant-mode-light.png b/apps/desktop/src/assets/illustrations/instant-mode-light.png
deleted file mode 100644
index b2a4fac2414..00000000000
Binary files a/apps/desktop/src/assets/illustrations/instant-mode-light.png and /dev/null differ
diff --git a/apps/desktop/src/assets/illustrations/studio-mode-dark.png b/apps/desktop/src/assets/illustrations/studio-mode-dark.png
deleted file mode 100644
index 71de0305f80..00000000000
Binary files a/apps/desktop/src/assets/illustrations/studio-mode-dark.png and /dev/null differ
diff --git a/apps/desktop/src/assets/illustrations/studio-mode-light.png b/apps/desktop/src/assets/illustrations/studio-mode-light.png
deleted file mode 100644
index 8a973cdffb4..00000000000
Binary files a/apps/desktop/src/assets/illustrations/studio-mode-light.png and /dev/null differ
diff --git a/apps/desktop/src/assets/illustrations/transparent.webp b/apps/desktop/src/assets/illustrations/transparent.webp
deleted file mode 100644
index 9bddeba4d1b..00000000000
Binary files a/apps/desktop/src/assets/illustrations/transparent.webp and /dev/null differ
diff --git a/apps/desktop/src/assets/instant-toggle.jpg b/apps/desktop/src/assets/instant-toggle.jpg
deleted file mode 100644
index 0878c0c50d0..00000000000
Binary files a/apps/desktop/src/assets/instant-toggle.jpg and /dev/null differ
diff --git a/apps/desktop/src/assets/rive/pricing.riv b/apps/desktop/src/assets/rive/pricing.riv
deleted file mode 100644
index 78c4c6f4617..00000000000
Binary files a/apps/desktop/src/assets/rive/pricing.riv and /dev/null differ
diff --git a/apps/desktop/src/assets/theme-previews/auto.jpg b/apps/desktop/src/assets/theme-previews/auto.jpg
deleted file mode 100644
index 2a9304cb455..00000000000
Binary files a/apps/desktop/src/assets/theme-previews/auto.jpg and /dev/null differ
diff --git a/apps/desktop/src/assets/theme-previews/dark.jpg b/apps/desktop/src/assets/theme-previews/dark.jpg
deleted file mode 100644
index 9820c9f57ab..00000000000
Binary files a/apps/desktop/src/assets/theme-previews/dark.jpg and /dev/null differ
diff --git a/apps/desktop/src/assets/theme-previews/legacy-auto.jpg b/apps/desktop/src/assets/theme-previews/legacy-auto.jpg
deleted file mode 100644
index 54ee8d06091..00000000000
Binary files a/apps/desktop/src/assets/theme-previews/legacy-auto.jpg and /dev/null differ
diff --git a/apps/desktop/src/assets/theme-previews/legacy-dark.jpg b/apps/desktop/src/assets/theme-previews/legacy-dark.jpg
deleted file mode 100644
index 2fb280563c1..00000000000
Binary files a/apps/desktop/src/assets/theme-previews/legacy-dark.jpg and /dev/null differ
diff --git a/apps/desktop/src/assets/theme-previews/legacy-light.jpg b/apps/desktop/src/assets/theme-previews/legacy-light.jpg
deleted file mode 100644
index 46fc04cf433..00000000000
Binary files a/apps/desktop/src/assets/theme-previews/legacy-light.jpg and /dev/null differ
diff --git a/apps/desktop/src/assets/theme-previews/light.jpg b/apps/desktop/src/assets/theme-previews/light.jpg
deleted file mode 100644
index 64e83080e86..00000000000
Binary files a/apps/desktop/src/assets/theme-previews/light.jpg and /dev/null differ
diff --git a/apps/desktop/src/components/CameraPreviewChrome.tsx b/apps/desktop/src/components/CameraPreviewChrome.tsx
deleted file mode 100644
index e9e1f50f3aa..00000000000
--- a/apps/desktop/src/components/CameraPreviewChrome.tsx
+++ /dev/null
@@ -1,398 +0,0 @@
-import { ToggleButton as KToggleButton } from "@kobalte/core/toggle-button";
-import { type as ostype } from "@tauri-apps/plugin-os";
-import { cx } from "cva";
-import {
-	type ComponentProps,
-	createEffect,
-	createSignal,
-	onCleanup,
-	Show,
-} from "solid-js";
-import type { SetStoreFunction } from "solid-js/store";
-import type { BackgroundBlurMode, CameraPreviewShape } from "~/utils/tauri";
-
-export type CameraWindowState = {
-	size: number;
-	shape: CameraPreviewShape;
-	mirrored: boolean;
-	backgroundBlur: BackgroundBlurMode | boolean;
-};
-
-export const CAMERA_MIN_SIZE = 150;
-export const CAMERA_MAX_SIZE = 600;
-export const CAMERA_DEFAULT_SIZE = 230;
-export const CAMERA_PRESET_SMALL = 230;
-export const CAMERA_PRESET_LARGE = 400;
-export const CAMERA_TOOLBAR_HEIGHT = 56;
-export const CAMERA_WINDOW_STATE_STORAGE_KEY = "cameraWindowState";
-export const CAMERA_WIDE_ASPECT_RATIO = 16 / 9;
-
-export const cameraBackgroundOptions = (
-	macOS: boolean,
-): { name: string; value: BackgroundBlurMode }[] => [
-	{ name: "Off", value: "off" },
-	{ name: "Light Blur", value: "light" },
-	{ name: "Heavy Blur", value: "heavy" },
-	...(macOS ? [{ name: "Remove Background", value: "remove" as const }] : []),
-];
-const RESIZE_CORNERS = ["nw", "ne", "sw", "se"] as const;
-
-type ResizeCorner = (typeof RESIZE_CORNERS)[number];
-
-export const getDefaultCameraWindowState = (): CameraWindowState => ({
-	size: CAMERA_DEFAULT_SIZE,
-	shape: "round",
-	mirrored: false,
-	backgroundBlur: "off",
-});
-
-export const clampCameraSize = (size: number) =>
-	Math.max(CAMERA_MIN_SIZE, Math.min(CAMERA_MAX_SIZE, size));
-
-export const cameraPreviewAspectRatio = (
-	shape: CameraPreviewShape,
-	frameAspectRatio?: number | null,
-) => {
-	if (shape !== "full") return 1;
-	if (
-		typeof frameAspectRatio === "number" &&
-		Number.isFinite(frameAspectRatio) &&
-		frameAspectRatio > 0
-	) {
-		return Math.max(frameAspectRatio, CAMERA_WIDE_ASPECT_RATIO);
-	}
-	return CAMERA_WIDE_ASPECT_RATIO;
-};
-
-export const cameraPreviewDimensions = (
-	size: number,
-	shape: CameraPreviewShape,
-	frameAspectRatio?: number | null,
-) => {
-	const base = clampCameraSize(size);
-	const aspectRatio = cameraPreviewAspectRatio(shape, frameAspectRatio);
-	return {
-		height: base,
-		width: base * aspectRatio,
-	};
-};
-
-export const normalizeBackgroundBlurMode = (
-	mode: BackgroundBlurMode | boolean | undefined,
-): BackgroundBlurMode => {
-	if (typeof mode === "boolean") return mode ? "heavy" : "off";
-	return mode ?? "off";
-};
-
-export const cycleBlurMode = (
-	current: BackgroundBlurMode | boolean,
-	macOS = false,
-): BackgroundBlurMode => {
-	if (typeof current === "boolean") {
-		return current ? "heavy" : "light";
-	}
-	const modes = cameraBackgroundOptions(macOS).map((option) => option.value);
-	const idx = modes.indexOf(current);
-	return modes[(idx + 1) % modes.length];
-};
-
-export const blurModeLabel = (mode: BackgroundBlurMode | boolean): string => {
-	if (typeof mode === "boolean") return mode ? "Blur" : "";
-	switch (mode) {
-		case "light":
-			return "Light";
-		case "heavy":
-			return "Heavy";
-		case "remove":
-			return "Cutout";
-		default:
-			return "";
-	}
-};
-
-export const cameraToolbarScale = (size: number) => {
-	const normalized =
-		(clampCameraSize(size) - CAMERA_MIN_SIZE) /
-		(CAMERA_MAX_SIZE - CAMERA_MIN_SIZE);
-	return 0.7 + normalized * 0.3;
-};
-
-export function cameraBorderRadius(state: CameraWindowState) {
-	if (state.backgroundBlur === "remove") return "0px";
-	if (state.shape === "round") return "9999px";
-	const normalized =
-		(clampCameraSize(state.size) - CAMERA_MIN_SIZE) /
-		(CAMERA_MAX_SIZE - CAMERA_MIN_SIZE);
-	const radius = 3 + normalized * 1.5;
-	return `${radius}rem`;
-}
-
-export function CameraPreviewToolbar(props: {
-	state: CameraWindowState;
-	setState: SetStoreFunction;
-	visible: boolean;
-	scale?: number;
-	onClose?: () => void;
-}) {
-	const toolbarClass = () =>
-		cx(
-			"flex flex-row gap-1 p-1 rounded-xl transition-[opacity,transform] bg-gray-1 border border-white-transparent-20 text-gray-10",
-			props.visible ? "opacity-100 translate-y-0" : "opacity-0 translate-y-2",
-		);
-
-	return (
-		
- - {(onClose) => ( - - - - )} - - = CAMERA_PRESET_LARGE} - onClick={() => { - props.setState( - "size", - props.state.size < CAMERA_PRESET_LARGE - ? CAMERA_PRESET_LARGE - : CAMERA_PRESET_SMALL, - ); - }} - > - - - - props.setState("shape", (shape) => - shape === "round" - ? "square" - : shape === "square" - ? "full" - : "round", - ) - } - > - {props.state.shape === "round" && } - {props.state.shape === "square" && } - {props.state.shape === "full" && ( - - )} - - props.setState("mirrored", (mirrored) => !mirrored)} - > - - - - props.setState("backgroundBlur", (mode) => - cycleBlurMode(mode, ostype() === "macos"), - ) - } - > -
- - - - {blurModeLabel(props.state.backgroundBlur)} - - -
-
-
- ); -} - -function ControlButton( - props: Omit, "type" | "class">, -) { - return ( - - ); -} - -export function CameraResizeHandles(props: { - state: CameraWindowState; - setState: SetStoreFunction; - toolbarHeight: number; - visible: boolean; -}) { - const [isResizing, setIsResizing] = createSignal(false); - const [activeCorner, setActiveCorner] = createSignal( - null, - ); - const [resizeStart, setResizeStart] = createSignal({ - size: 0, - x: 0, - y: 0, - corner: "nw" as ResizeCorner, - }); - - const handleResizeStart = (corner: ResizeCorner) => (e: MouseEvent) => { - if (e.button !== 0) return; - e.preventDefault(); - e.stopPropagation(); - setIsResizing(true); - setActiveCorner(corner); - setResizeStart({ - size: props.state.size, - x: e.clientX, - y: e.clientY, - corner, - }); - }; - - const handleResizeMove = (e: MouseEvent) => { - if (!isResizing()) return; - const start = resizeStart(); - const deltaX = e.clientX - start.x; - const deltaY = e.clientY - start.y; - - const hasE = start.corner.includes("e"); - const hasW = start.corner.includes("w"); - const hasS = start.corner.includes("s"); - const hasN = start.corner.includes("n"); - - const dx = hasE ? deltaX : hasW ? -deltaX : 0; - const dy = hasS ? deltaY : hasN ? -deltaY : 0; - - const delta = (hasE || hasW) && (hasN || hasS) ? Math.max(dx, dy) : dx + dy; - - props.setState("size", clampCameraSize(start.size + delta)); - }; - - const handleResizeEnd = () => { - setIsResizing(false); - setActiveCorner(null); - }; - - createEffect(() => { - if (!isResizing()) return; - window.addEventListener("mousemove", handleResizeMove); - window.addEventListener("mouseup", handleResizeEnd); - onCleanup(() => { - window.removeEventListener("mousemove", handleResizeMove); - window.removeEventListener("mouseup", handleResizeEnd); - }); - }); - - return ( -
- {RESIZE_CORNERS.map((corner) => ( - - ))} -
- ); -} - -function ResizeCornerHandle(props: { - corner: ResizeCorner; - onMouseDown: (e: MouseEvent) => void; - active: boolean; - visible: boolean; -}) { - const hitAreaClass = () => { - switch (props.corner) { - case "nw": - return "top-0 left-0 cursor-nw-resize"; - case "ne": - return "top-0 right-0 cursor-ne-resize"; - case "sw": - return "bottom-0 left-0 cursor-sw-resize"; - case "se": - return "bottom-0 right-0 cursor-se-resize"; - } - }; - - const bracketPositionClass = () => { - switch (props.corner) { - case "nw": - return "top-1.5 left-1.5 border-t-2 border-l-2 rounded-tl-[6px]"; - case "ne": - return "top-1.5 right-1.5 border-t-2 border-r-2 rounded-tr-[6px]"; - case "sw": - return "bottom-1.5 left-1.5 border-b-2 border-l-2 rounded-bl-[6px]"; - case "se": - return "bottom-1.5 right-1.5 border-b-2 border-r-2 rounded-br-[6px]"; - } - }; - - // A thicker dark bracket sits 1px outside the white one on every edge so - // the L reads as a contour on light desktops too (cutout mode has no - // backdrop behind it). Same construction as the GPUI window. - const outlinePositionClass = () => { - switch (props.corner) { - case "nw": - return "top-[5px] left-[5px] border-t-4 border-l-4 rounded-tl-[7px]"; - case "ne": - return "top-[5px] right-[5px] border-t-4 border-r-4 rounded-tr-[7px]"; - case "sw": - return "bottom-[5px] left-[5px] border-b-4 border-l-4 rounded-bl-[7px]"; - case "se": - return "bottom-[5px] right-[5px] border-b-4 border-r-4 rounded-br-[7px]"; - } - }; - - return ( -
-
-
-
-
-
- ); -} diff --git a/apps/desktop/src/components/CapErrorBoundary.tsx b/apps/desktop/src/components/CapErrorBoundary.tsx deleted file mode 100644 index b7f3801a90f..00000000000 --- a/apps/desktop/src/components/CapErrorBoundary.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { Button } from "@cap/ui-solid"; -import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow"; -import { writeText } from "@tauri-apps/plugin-clipboard-manager"; -import { type as ostype } from "@tauri-apps/plugin-os"; -import { ErrorBoundary, type ParentProps } from "solid-js"; -import Titlebar from "./titlebar/Titlebar"; - -export function CapErrorBoundary(props: ParentProps) { - return ( - { - console.error(e); - const windowLabel = getCurrentWebviewWindow().label; - const showTitlebar = - ostype() === "windows" && - ([ - "main", - "settings", - "upgrade", - "mode-select", - "onboarding", - "teleprompter", - ].includes(windowLabel) || - /^(editor|screenshot-editor)-\d+$/.test(windowLabel)); - return ( -
- {showTitlebar && } -
- -

- An Error Occured -

-

- We're very sorry, but something has gone wrong. -

-
- - - -
- - {import.meta.env.DEV && ( - - )} -
-
- ); - }} - > - {props.children} -
- ); -} diff --git a/apps/desktop/src/components/Cropper.tsx b/apps/desktop/src/components/Cropper.tsx deleted file mode 100644 index 5ae71bbb4fa..00000000000 --- a/apps/desktop/src/components/Cropper.tsx +++ /dev/null @@ -1,1671 +0,0 @@ -import { createEventListenerMap } from "@solid-primitives/event-listener"; -import { createResizeObserver } from "@solid-primitives/resize-observer"; -import type { - CheckMenuItemOptions, - PredefinedMenuItemOptions, -} from "@tauri-apps/api/menu"; -import { type as ostype } from "@tauri-apps/plugin-os"; -import { - type Accessor, - children, - createEffect, - createMemo, - createRoot, - createSignal, - For, - on, - onCleanup, - onMount, - type ParentProps, - Show, -} from "solid-js"; -import { createStore } from "solid-js/store"; -import { Transition } from "solid-transition-group"; -import { createKeyDownSignal } from "~/utils/events"; - -import { commands } from "~/utils/tauri"; -import { alignCrop, type CropGuides } from "./crop-alignment"; -import "./cropper.css"; -export interface CropBounds { - x: number; - y: number; - width: number; - height: number; -} -export const CROP_ZERO: CropBounds = { x: 0, y: 0, width: 0, height: 0 }; - -type Direction = "n" | "e" | "s" | "w" | "nw" | "ne" | "se" | "sw"; -type BoundsConstraints = { - top: boolean; - right: boolean; - bottom: boolean; - left: boolean; -}; -type Vec2 = { x: number; y: number }; - -type HandleSide = { - x: "l" | "r" | "c"; - y: "t" | "b" | "c"; - direction: Direction; - cursor: string; - movable: BoundsConstraints; - origin: Vec2; - isCorner: boolean; -}; - -const HANDLES: readonly HandleSide[] = [ - { x: "l", y: "t", direction: "nw", cursor: "nwse-resize" }, - { x: "r", y: "t", direction: "ne", cursor: "nesw-resize" }, - { x: "l", y: "b", direction: "sw", cursor: "nesw-resize" }, - { x: "r", y: "b", direction: "se", cursor: "nwse-resize" }, - { x: "c", y: "t", direction: "n", cursor: "ns-resize" }, - { x: "c", y: "b", direction: "s", cursor: "ns-resize" }, - { x: "l", y: "c", direction: "w", cursor: "ew-resize" }, - { x: "r", y: "c", direction: "e", cursor: "ew-resize" }, -].map( - (handle) => - ({ - ...handle, - movable: { - top: handle.y === "t", - bottom: handle.y === "b", - left: handle.x === "l", - right: handle.x === "r", - }, - origin: { - x: handle.x === "l" ? 1 : handle.x === "r" ? 0 : 0.5, - y: handle.y === "t" ? 1 : handle.y === "b" ? 0 : 0.5, - }, - isCorner: handle.x !== "c" && handle.y !== "c", - }) as HandleSide, -); -export type Ratio = [number, number]; -export const COMMON_RATIOS: readonly Ratio[] = [ - [1, 1], - [2, 1], - [3, 2], - [4, 3], - [9, 16], - [16, 9], - [16, 10], - [21, 9], -]; -const ORIGIN_CENTER: Vec2 = { x: 0.5, y: 0.5 }; - -const ratioToValue = (r: Ratio) => r[0] / r[1]; -const clamp = (n: number, min = 0, max = 1) => Math.max(min, Math.min(max, n)); -const easeInOutCubic = (t: number) => - t < 0.5 ? 4 * t * t * t : 1 - (-2 * t + 2) ** 3 / 2; - -const shouldTriggerHaptic = ostype() === "macos"; -function triggerHaptic() { - if (shouldTriggerHaptic) commands.performHapticFeedback("alignment", null); -} - -function findClosestRatio( - width: number, - height: number, - threshold = 0.01, -): Ratio | null { - const currentRatio = width / height; - for (const ratio of COMMON_RATIOS) { - if (Math.abs(currentRatio - ratio[0] / ratio[1]) < threshold) - return [ratio[0], ratio[1]]; - if (Math.abs(currentRatio - ratio[1] / ratio[0]) < threshold) - return [ratio[1], ratio[0]]; - } - return null; -} - -// ----------------------------- -// Bounds helpers -// ----------------------------- -function moveBounds( - bounds: CropBounds, - x: number | null, - y: number | null, -): CropBounds { - return { - ...bounds, - x: x !== null ? Math.round(x) : bounds.x, - y: y !== null ? Math.round(y) : bounds.y, - }; -} - -function resizeBounds( - bounds: CropBounds, - newWidth: number, - newHeight: number, - origin: Vec2, -): CropBounds { - const fromX = bounds.x + bounds.width * origin.x; - const fromY = bounds.y + bounds.height * origin.y; - return { - x: Math.round(fromX - newWidth * origin.x), - y: Math.round(fromY - newHeight * origin.y), - width: Math.round(newWidth), - height: Math.round(newHeight), - }; -} - -function scaleBounds(bounds: CropBounds, factor: number, origin: Vec2) { - return resizeBounds( - bounds, - bounds.width * factor, - bounds.height * factor, - origin, - ); -} - -function constrainBoundsToRatio( - bounds: CropBounds, - ratio: number, - origin: Vec2, -) { - const currentRatio = bounds.width / bounds.height; - if (Math.abs(currentRatio - ratio) < 0.001) return bounds; - return resizeBounds(bounds, bounds.width, bounds.width / ratio, origin); -} - -function constrainBoundsToSize( - bounds: CropBounds, - max: Vec2 | null, - min: Vec2 | null, - origin: Vec2, - ratio: number | null = null, -) { - let next = { ...bounds }; - let maxW = max?.x ?? null; - let maxH = max?.y ?? null; - let minW = min?.x ?? null; - let minH = min?.y ?? null; - - if (ratio) { - // Correctly calculate effective min/max sizes when a ratio is present - if (minW && minH) { - const effectiveMinW = Math.max(minW, minH * ratio); - minW = effectiveMinW; - minH = effectiveMinW / ratio; - } - if (maxW && maxH) { - const effectiveMaxW = Math.min(maxW, maxH * ratio); - maxW = effectiveMaxW; - maxH = effectiveMaxW / ratio; - } - } - - if (maxW && next.width > maxW) - next = resizeBounds(next, maxW, ratio ? maxW / ratio : next.height, origin); - if (maxH && next.height > maxH) - next = resizeBounds(next, ratio ? maxH * ratio : next.width, maxH, origin); - if (minW && next.width < minW) - next = resizeBounds(next, minW, ratio ? minW / ratio : next.height, origin); - if (minH && next.height < minH) - next = resizeBounds(next, ratio ? minH * ratio : next.width, minH, origin); - - return next; -} - -function slideBoundsIntoContainer( - bounds: CropBounds, - containerWidth: number, - containerHeight: number, -): CropBounds { - let { x, y, width, height } = bounds; - - if (x < 0) x = 0; - if (y < 0) y = 0; - if (x + width > containerWidth) x = containerWidth - width; - if (y + height > containerHeight) y = containerHeight - height; - - return { ...bounds, x, y }; -} - -export type CropperRef = { - fill: () => void; - reset: (options?: { animate?: boolean }) => void; - setCropProperty: (field: keyof CropBounds, value: number) => void; - setCrop: ( - value: CropBounds | ((b: CropBounds) => CropBounds), - origin?: Vec2, - ) => void; - bounds: Accessor; - animateTo: (real: CropBounds, durationMs?: number) => void; -}; - -export function Cropper( - props: ParentProps<{ - onCropChange?: (bounds: CropBounds) => void; - onInteraction?: (interacting: boolean) => void; - onContextMenu?: (event: PointerEvent) => void; - ref?: CropperRef | ((ref: CropperRef) => void); - class?: string; - minSize?: Vec2; - maxSize?: Vec2; - targetSize?: Vec2; - initialCrop?: CropBounds | (() => CropBounds | undefined); - aspectRatio?: Ratio; - showBounds?: boolean; - snapToRatioEnabled?: boolean; - useBackdropFilter?: boolean; - allowLightMode?: boolean; - appearance?: "editor"; - snapToAlignmentEnabled?: boolean; - }>, -) { - let containerRef: HTMLDivElement | undefined; - let regionRef: HTMLDivElement | undefined; - let occTopRef: HTMLDivElement | undefined; - let occBottomRef: HTMLDivElement | undefined; - let occLeftRef: HTMLDivElement | undefined; - let occRightRef: HTMLDivElement | undefined; - - const resolvedChildren = children(() => props.children); - - // raw bounds are in "logical" coordinates (not scaled to targetSize) - const [rawBounds, setRawBounds] = createSignal(CROP_ZERO); - const [displayRawBounds, setDisplayRawBounds] = - createSignal(CROP_ZERO); - - const [isAnimating, setIsAnimating] = createSignal(false); - let animationFrameId: number | null = null; - const [isReady, setIsReady] = createSignal(false); - - function stopAnimation() { - if (animationFrameId !== null) cancelAnimationFrame(animationFrameId); - animationFrameId = null; - setIsAnimating(false); - setDisplayRawBounds(rawBounds()); - } - - const boundsTooSmall = createMemo( - () => displayRawBounds().width <= 30 || displayRawBounds().height <= 30, - ); - - const [mouseState, setMouseState] = createStore< - ( - | { drag: null | "region" | "overlay" } - | { drag: "handle"; cursor: string } - ) & { hoveringHandle: HandleSide | null } - >({ drag: null, hoveringHandle: null }); - - const [alignmentGuides, setAlignmentGuides] = createSignal({ - x: null, - y: null, - }); - - const resizing = () => - mouseState.drag === "handle" || mouseState.drag === "overlay"; - const cursorStyle = () => { - if (mouseState.drag === "region" || mouseState.drag === "overlay") - return "grabbing"; - if (mouseState.drag === "handle") return mouseState.cursor; - }; - - createEffect(() => props.onInteraction?.(mouseState.drag !== null)); - - const [aspectState, setAspectState] = createStore({ - snapped: null as Ratio | null, - value: null as number | null, - }); - - createEffect(() => { - const min = props.minSize; - const max = props.maxSize; - - if (min && max) { - if (min.x > max.x) - throw new Error( - `Cropper constraint error: minSize.x (${min.x}px) exceeds maxSize.x (${max.x}px). Please adjust the size constraints.`, - ); - if (min.y > max.y) - throw new Error( - `Cropper constraint error: minSize.y (${min.y}px) exceeds maxSize.y (${max.y}px). Please adjust the size constraints.`, - ); - } - }); - - createEffect( - on( - () => props.aspectRatio, - (v) => { - const nextRatio = v ? ratioToValue(v) : null; - setAspectState("value", nextRatio); - - if (!isReady() || !nextRatio) return; - let targetBounds = rawBounds(); - - targetBounds = constrainBoundsToRatio( - targetBounds, - nextRatio, - ORIGIN_CENTER, - ); - setRawBoundsAndAnimate(targetBounds); - }, - ), - ); - - const [containerSize, setContainerSize] = createSignal({ x: 1, y: 1 }); - const targetSize = createMemo(() => props.targetSize || containerSize()); - - const logicalScale = createMemo(() => { - if (props.targetSize) { - const target = props.targetSize; - const container = containerSize(); - return { x: target.x / container.x, y: target.y / container.y }; - } - return { x: 1, y: 1 }; - }); - - const realBounds = createMemo(() => { - const { x, y, width, height } = rawBounds(); - const scale = logicalScale(); - const target = targetSize(); - const bounds = { - x: Math.round(x * scale.x), - y: Math.round(y * scale.y), - width: Math.round(width * scale.x), - height: Math.round(height * scale.y), - }; - - if (bounds.width > target.x) bounds.width = target.x; - if (bounds.height > target.y) bounds.height = target.y; - if (bounds.x < 0) bounds.x = 0; - if (bounds.y < 0) bounds.y = 0; - if (bounds.x + bounds.width > target.x) bounds.x = target.x - bounds.width; - if (bounds.y + bounds.height > target.y) - bounds.y = target.y - bounds.height; - - props.onCropChange?.(bounds); - return bounds; - }); - - function calculateLabelTransform(handle: HandleSide) { - const bounds = rawBounds(); - if (!containerRef) return { x: 0, y: 0 }; - const containerRect = containerRef.getBoundingClientRect(); - const labelWidth = 80; - const labelHeight = 25; - const margin = 25; - - const handleScreenX = - containerRect.left + - bounds.x + - bounds.width * (handle.x === "l" ? 0 : handle.x === "r" ? 1 : 0.5); - const handleScreenY = - containerRect.top + - bounds.y + - bounds.height * (handle.y === "t" ? 0 : handle.y === "b" ? 1 : 0.5); - - let idealX = handleScreenX; - let idealY = handleScreenY; - - if (handle.x === "l") idealX -= labelWidth + margin; - else if (handle.x === "r") idealX += margin; - else idealX -= labelWidth / 2; - - if (handle.y === "t") idealY -= labelHeight + margin; - else if (handle.y === "b") idealY += margin; - else idealY -= labelHeight / 2; - - const finalX = clamp( - idealX, - margin, - window.innerWidth - labelWidth - margin, - ); - const finalY = clamp( - idealY, - margin, - window.innerHeight - labelHeight - margin, - ); - - return { x: finalX, y: finalY }; - } - - const labelTransform = createMemo(() => - resizing() && mouseState.hoveringHandle - ? calculateLabelTransform(mouseState.hoveringHandle) - : null, - ); - - function boundsToRaw(real: CropBounds) { - const scale = logicalScale(); - return { - x: Math.max(0, real.x / scale.x), - y: Math.max(0, real.y / scale.y), - width: Math.max(0, real.width / scale.x), - height: Math.max(0, real.height / scale.y), - }; - } - - function animateToRawBounds(target: CropBounds, durationMs = 240) { - const start = displayRawBounds(); - if ( - target.x === start.x && - target.y === start.y && - target.width === start.width && - target.height === start.height - ) { - animationFrameId = null; - setIsAnimating(false); - setDisplayRawBounds(target); - return; - } - - setIsAnimating(true); - if (animationFrameId !== null) cancelAnimationFrame(animationFrameId); - const startTime = performance.now(); - - const step = () => { - const now = performance.now(); - const t = Math.min(1, (now - startTime) / durationMs); - const e = easeInOutCubic(t); - setDisplayRawBounds({ - x: start.x + (target.x - start.x) * e, - y: start.y + (target.y - start.y) * e, - width: start.width + (target.width - start.width) * e, - height: start.height + (target.height - start.height) * e, - }); - if (t < 1) animationFrameId = requestAnimationFrame(step); - else { - animationFrameId = null; - setIsAnimating(false); - triggerHaptic(); - } - }; - - animationFrameId = requestAnimationFrame(step); - } - - function setRawBoundsAndAnimate( - bounds: CropBounds, - origin?: Vec2, - durationMs = 240, - ) { - if (animationFrameId !== null) cancelAnimationFrame(animationFrameId); - animationFrameId = null; - setIsAnimating(true); - setRawBoundsConstraining(bounds, origin); - animateToRawBounds(rawBounds(), durationMs); - } - - function computeInitialBounds(): CropBounds { - const target = targetSize(); - const initialCrop = - typeof props.initialCrop === "function" - ? props.initialCrop() - : props.initialCrop; - - const startBoundsReal = initialCrop ?? { - x: 0, - y: 0, - width: Math.round(target.x / 2), - height: Math.round(target.y / 2), - }; - - let bounds = boundsToRaw(startBoundsReal); - const ratioValue = aspectState.value; - if (ratioValue) - bounds = constrainBoundsToRatio(bounds, ratioValue, ORIGIN_CENTER); - const container = containerSize(); - - if (bounds.width > container.x) - bounds = scaleBounds(bounds, container.x / bounds.width, ORIGIN_CENTER); - if (bounds.height > container.y) - bounds = scaleBounds(bounds, container.y / bounds.height, ORIGIN_CENTER); - - bounds = slideBoundsIntoContainer(bounds, container.x, container.y); - - if (!initialCrop) - bounds = moveBounds( - bounds, - container.x / 2 - bounds.width / 2, - container.y / 2 - bounds.height / 2, - ); - return bounds; - } - - function rawSizeConstraint() { - const scale = logicalScale(); - return { - min: props.minSize - ? { x: props.minSize.x / scale.x, y: props.minSize.y / scale.y } - : null, - max: props.maxSize - ? { x: props.maxSize.x / scale.x, y: props.maxSize.y / scale.y } - : null, - }; - } - - function setRawBoundsConstraining( - bounds: CropBounds, - origin = ORIGIN_CENTER, - ) { - const ratioValue = aspectState.value; - const container = containerSize(); - const { min, max } = rawSizeConstraint(); - let newBounds = { ...bounds }; - - newBounds = constrainBoundsToSize(newBounds, max, min, origin, ratioValue); - - if (ratioValue) - newBounds = constrainBoundsToRatio(newBounds, ratioValue, origin); - - if (newBounds.width > container.x) - newBounds = scaleBounds(newBounds, container.x / newBounds.width, origin); - if (newBounds.height > container.y) - newBounds = scaleBounds( - newBounds, - container.y / newBounds.height, - origin, - ); - - newBounds = slideBoundsIntoContainer(newBounds, container.x, container.y); - setRawBounds(newBounds); - if (!isAnimating()) setDisplayRawBounds(newBounds); - } - - function fill() { - const container = containerSize(); - const targetRaw = { - x: 0, - y: 0, - width: container.x, - height: container.y, - }; - setRawBoundsAndAnimate(targetRaw); - setAspectState("snapped", null); - } - - onMount(() => { - if (!containerRef) return; - let initialized = false; - - const updateContainerSize = (width: number, height: number) => { - const prevScale = logicalScale(); - const currentRaw = rawBounds(); - const preservedReal = { - x: Math.round(currentRaw.x * prevScale.x), - y: Math.round(currentRaw.y * prevScale.y), - width: Math.round(currentRaw.width * prevScale.x), - height: Math.round(currentRaw.height * prevScale.y), - }; - - setContainerSize({ x: width, y: height }); - - setRawBoundsConstraining(boundsToRaw(preservedReal)); - - if (!initialized && width > 1 && height > 1) { - initialized = true; - init(); - } - }; - - createResizeObserver(containerRef, (e) => - updateContainerSize(e.width, e.height), - ); - updateContainerSize(containerRef.clientWidth, containerRef.clientHeight); - - setDisplayRawBounds(rawBounds()); - - function init() { - const bounds = computeInitialBounds(); - setRawBoundsConstraining(bounds); - setDisplayRawBounds(bounds); - setIsReady(true); - } - - if (props.ref) { - const cropperRef: CropperRef = { - reset: (options) => { - const bounds = computeInitialBounds(); - if (options?.animate === false) { - stopAnimation(); - setRawBoundsConstraining(bounds); - } else { - setRawBoundsAndAnimate(bounds); - } - setAspectState("snapped", null); - }, - fill, - setCropProperty: (field, value) => { - setAspectState("snapped", null); - setRawBoundsConstraining( - boundsToRaw({ ...realBounds(), [field]: value }), - { x: 0, y: 0 }, - ); - }, - setCrop: (value, origin) => - setRawBoundsConstraining( - boundsToRaw( - typeof value === "function" ? value(rawBounds()) : value, - ), - origin, - ), - get bounds() { - return realBounds; - }, - animateTo: (real, durationMs) => - setRawBoundsAndAnimate(boundsToRaw(real), undefined, durationMs), - }; - - if (typeof props.ref === "function") props.ref(cropperRef); - else props.ref = cropperRef; - } - }); - - function onRegionPointerDown(e: PointerEvent) { - if (!containerRef || e.button !== 0) return; - - const target = e.currentTarget as HTMLElement; - disposeActivePointerSession(); - stopAnimation(); - e.stopPropagation(); - setMouseState({ drag: "region" }); - let currentBounds = rawBounds(); - const containerRect = containerRef.getBoundingClientRect(); - const startOffset = { - x: e.clientX - containerRect.left - currentBounds.x, - y: e.clientY - containerRect.top - currentBounds.y, - }; - - trackPointerSession( - target, - e.pointerId, - (e) => { - let newX = e.clientX - containerRect.left - startOffset.x; - let newY = e.clientY - containerRect.top - startOffset.y; - - newX = clamp(newX, 0, containerRect.width - currentBounds.width); - newY = clamp(newY, 0, containerRect.height - currentBounds.height); - - currentBounds = moveBounds(currentBounds, newX, newY); - const aligned = - props.snapToAlignmentEnabled && !e.shiftKey - ? alignCrop(currentBounds, containerSize()) - : { bounds: currentBounds, guides: { x: null, y: null } }; - currentBounds = aligned.bounds; - setAlignmentGuides(aligned.guides); - setRawBounds(currentBounds); - - if (!isAnimating()) setDisplayRawBounds(currentBounds); - }, - () => { - setMouseState({ drag: null }); - }, - ); - } - - let activePointerSessionDispose: (() => void) | undefined; - - function disposeActivePointerSession() { - activePointerSessionDispose?.(); - activePointerSessionDispose = undefined; - } - - function trackPointerSession( - target: HTMLElement, - pointerId: number, - onMove: (event: PointerEvent) => void, - onEnd: () => void, - ) { - target.setPointerCapture?.(pointerId); - - createRoot((dispose) => { - let ended = false; - const finish = () => { - if (ended) return; - ended = true; - if (target.hasPointerCapture?.(pointerId)) { - target.releasePointerCapture(pointerId); - } - setAlignmentGuides({ x: null, y: null }); - onEnd(); - activePointerSessionDispose = undefined; - dispose(); - }; - const finishForPointer = (event: PointerEvent) => { - if (event.pointerId === pointerId) finish(); - }; - - createEventListenerMap(window, { - pointermove: (event) => { - if (event.pointerId === pointerId) onMove(event); - }, - pointerup: finishForPointer, - pointercancel: finishForPointer, - // While pointer capture is held the drag is still ours even if the window - // loses focus (e.g. another overlay or the camera window grabs it on - // Windows). Real pointer loss arrives via pointercancel/lostpointercapture. - // Defer the capture check by one microtask so setPointerCapture has time - // to finalize before we decide the session is orphaned. - blur: () => { - queueMicrotask(() => { - if (!target.hasPointerCapture?.(pointerId)) finish(); - }); - }, - }); - createEventListenerMap(target, { - lostpointercapture: finishForPointer, - }); - - activePointerSessionDispose = finish; - }); - } - - onCleanup(() => { - disposeActivePointerSession(); - if (animationFrameId !== null) cancelAnimationFrame(animationFrameId); - }); - - function onHandlePointerDown(handle: HandleSide, e: PointerEvent) { - if (!containerRef || e.button !== 0) return; - const target = e.currentTarget as HTMLElement; - disposeActivePointerSession(); - e.stopPropagation(); - - stopAnimation(); - setMouseState({ drag: "handle", cursor: handle.cursor }); - - const context: ResizeSessionState = { - containerRect: containerRef.getBoundingClientRect(), - startBounds: rawBounds(), - isAltMode: e.altKey, - activeHandle: { ...handle }, - originalHandle: handle, - }; - - trackPointerSession( - target, - e.pointerId, - (e) => handleResizePointerMove(e, context), - () => { - setMouseState({ drag: null }); - }, - ); - } - - // Helper: update handle movable sides when switching between anchor <-> center-origin mode - function updateHandleForModeSwitch( - handle: HandleSide, - currentBounds: CropBounds, - pointX: number, - pointY: number, - ) { - const center = { - x: currentBounds.x + currentBounds.width / 2, - y: currentBounds.y + currentBounds.height / 2, - }; - const newMovable = { ...handle.movable }; - if (handle.movable.left || handle.movable.right) { - newMovable.left = pointX < center.x; - newMovable.right = pointX >= center.x; - } - if (handle.movable.top || handle.movable.bottom) { - newMovable.top = pointY < center.y; - newMovable.bottom = pointY >= center.y; - } - return { ...handle, movable: newMovable }; - } - - type ResizeSessionState = { - startBounds: CropBounds; - isAltMode: boolean; - activeHandle: HandleSide; - originalHandle: HandleSide; - containerRect: DOMRect; - }; - - function handleResizePointerMove( - e: PointerEvent, - context: ResizeSessionState, - ) { - const previousSnappedRatio = aspectState.snapped; - const pointX = e.clientX - context.containerRect.left; - const pointY = e.clientY - context.containerRect.top; - - if (e.altKey !== context.isAltMode) { - context.isAltMode = e.altKey; - context.startBounds = rawBounds(); - if (context.isAltMode) { - context.activeHandle = context.originalHandle; - } else { - context.activeHandle = updateHandleForModeSwitch( - context.originalHandle, - context.startBounds, - pointX, - pointY, - ); - } - } - - const { min, max } = rawSizeConstraint(); - const shiftKey = e.shiftKey; - const ratioValue = aspectState.value; - - const options: ResizeOptions = { - container: containerSize(), - min, - max, - isAltMode: context.isAltMode, - shiftKey, - ratioValue, - snapToRatioEnabled: !!props.snapToRatioEnabled && !boundsTooSmall(), - }; - - let nextBounds: CropBounds; - - if (ratioValue !== null) { - nextBounds = - computeAspectRatioResize( - pointX, - pointY, - context.startBounds, - context.activeHandle, - options, - ) ?? rawBounds(); - } else { - const { bounds, snappedRatio } = computeFreeResize( - pointX, - pointY, - context.startBounds, - context.activeHandle, - options, - ); - nextBounds = bounds; - setAspectState("snapped", snappedRatio); - } - - const finalBounds = slideBoundsIntoContainer( - nextBounds, - containerSize().x, - containerSize().y, - ); - - let alignedBounds = finalBounds; - setAlignmentGuides({ x: null, y: null }); - if (props.snapToAlignmentEnabled && !e.shiftKey) { - const { movable } = context.activeHandle; - const start = context.startBounds; - const centered = context.isAltMode && ratioValue === null; - const aligned = alignCrop(finalBounds, containerSize(), { - origin: { - x: centered - ? 0.5 - : pointX < start.x + (movable.left ? start.width : 0) - ? 1 - : 0, - y: centered - ? 0.5 - : pointY < start.y + (movable.top ? start.height : 0) - ? 1 - : 0, - }, - axes: { - x: movable.left || movable.right, - y: movable.top || movable.bottom, - }, - ratio: ratioValue, - }); - alignedBounds = aligned.bounds; - setAlignmentGuides(aligned.guides); - if (aligned.guides.x !== null || aligned.guides.y !== null) - setAspectState("snapped", null); - } - if (aspectState.snapped && !previousSnappedRatio) triggerHaptic(); - setRawBounds(alignedBounds); - if (!isAnimating()) setDisplayRawBounds(alignedBounds); - } - - function onHandleDoubleClick(handle: HandleSide, e: MouseEvent) { - e.stopPropagation(); - const currentBounds = rawBounds(); - const container = containerSize(); - - const newBounds = { ...currentBounds }; - - if (handle.movable.top) { - newBounds.height = currentBounds.y + currentBounds.height; - newBounds.y = 0; - } - if (handle.movable.bottom) { - newBounds.height = container.y - currentBounds.y; - } - if (handle.movable.left) { - newBounds.width = currentBounds.x + currentBounds.width; - newBounds.x = 0; - } - if (handle.movable.right) { - newBounds.width = container.x - currentBounds.x; - } - - setRawBoundsAndAnimate(newBounds, handle.origin); - } - - function onOverlayPointerDown(e: PointerEvent) { - if (!containerRef || e.button !== 0) return; - const target = e.currentTarget as HTMLElement; - disposeActivePointerSession(); - e.preventDefault(); - e.stopPropagation(); - stopAnimation(); - - const initialBounds = { ...rawBounds() }; - const SE_HANDLE_INDEX = 3; // use bottom-right as the temporary handle - const handle = HANDLES[SE_HANDLE_INDEX]; - - setMouseState({ drag: "overlay" }); - - const containerRect = containerRef.getBoundingClientRect(); - const startPoint = { - x: e.clientX - containerRect.left, - y: e.clientY - containerRect.top, - }; - - const startBounds: CropBounds = { - x: startPoint.x, - y: startPoint.y, - width: 1, - height: 1, - }; - - const context: ResizeSessionState = { - containerRect, - startBounds, - isAltMode: e.altKey, - activeHandle: { ...handle }, - originalHandle: handle, - }; - - trackPointerSession( - target, - e.pointerId, - (e) => handleResizePointerMove(e, context), - () => { - setMouseState({ drag: null }); - const bounds = rawBounds(); - if (bounds.width < 5 || bounds.height < 5) { - setRawBounds(initialBounds); - if (!isAnimating()) setDisplayRawBounds(initialBounds); - } - }, - ); - } - - const KEY_MAPPINGS = new Map([ - ["ArrowRight", "e"], - ["ArrowDown", "s"], - ["ArrowLeft", "w"], - ["ArrowUp", "n"], - ]); - - const [keyboardState, setKeyboardState] = createStore({ - pressedKeys: new Set(), - shift: false, - alt: false, - meta: false, // Cmd or Ctrl - }); - - let keyboardFrameId: number | null = null; - - function keyboardActionLoop() { - const currentBounds = rawBounds(); - const { pressedKeys, shift, alt, meta } = keyboardState; - - const delta = shift ? 10 : 2; - - if (meta) { - // Resize - const origin = alt ? ORIGIN_CENTER : { x: 0, y: 0 }; - let newWidth = currentBounds.width; - let newHeight = currentBounds.height; - - if (pressedKeys.has("ArrowLeft")) newWidth -= delta; - if (pressedKeys.has("ArrowRight")) newWidth += delta; - if (pressedKeys.has("ArrowUp")) newHeight -= delta; - if (pressedKeys.has("ArrowDown")) newHeight += delta; - - newWidth = Math.max(1, newWidth); - newHeight = Math.max(1, newHeight); - - const resized = resizeBounds(currentBounds, newWidth, newHeight, origin); - - setRawBoundsConstraining(resized, origin); - } else { - // Move - let dx = 0; - let dy = 0; - - if (pressedKeys.has("ArrowLeft")) dx -= delta; - if (pressedKeys.has("ArrowRight")) dx += delta; - if (pressedKeys.has("ArrowUp")) dy -= delta; - if (pressedKeys.has("ArrowDown")) dy += delta; - - const moved = moveBounds( - currentBounds, - currentBounds.x + dx, - currentBounds.y + dy, - ); - - setRawBoundsConstraining(moved); - } - - keyboardFrameId = requestAnimationFrame(keyboardActionLoop); - } - - function handleKeyDown(e: KeyboardEvent) { - if (!KEY_MAPPINGS.has(e.key) || mouseState.drag !== null) return; - - e.preventDefault(); - e.stopPropagation(); - - setKeyboardState("pressedKeys", (p) => p.add(e.key)); - setKeyboardState({ - shift: e.shiftKey, - alt: e.altKey, - meta: e.metaKey || e.ctrlKey, - }); - - if (!keyboardFrameId) { - stopAnimation(); - keyboardActionLoop(); - } - } - - function handleKeyUp(e: KeyboardEvent) { - if ( - !KEY_MAPPINGS.has(e.key) && - !["Shift", "Alt", "Meta", "Control"].includes(e.key) - ) - return; - - e.preventDefault(); - - setKeyboardState("pressedKeys", (p) => { - p.delete(e.key); - return p; - }); - - setKeyboardState({ - shift: e.shiftKey, - alt: e.altKey, - meta: e.metaKey || e.ctrlKey, - }); - - if (keyboardState.pressedKeys.size === 0) { - if (keyboardFrameId) { - cancelAnimationFrame(keyboardFrameId); - keyboardFrameId = null; - } - } - } - - // Only update during a frame animation. - // Note: Doing this any other way can very likely cause a huge memory usage or even leak until the resizing stops. - createEffect( - on(displayRawBounds, (b, _prevIn, prevFrameId) => { - if (prevFrameId) cancelAnimationFrame(prevFrameId); - return requestAnimationFrame(() => { - if (regionRef) { - regionRef.style.width = `${Math.round(b.width)}px`; - regionRef.style.height = `${Math.round(b.height)}px`; - regionRef.style.transform = `translate(${Math.round(b.x)}px,${Math.round(b.y)}px)`; - } - if (occLeftRef) { - occLeftRef.style.width = `${Math.max(0, Math.round(b.x))}px`; - } - if (occRightRef) { - occRightRef.style.left = `${Math.round(b.x + b.width)}px`; - } - if (occTopRef) { - occTopRef.style.left = `${Math.round(b.x)}px`; - occTopRef.style.width = `${Math.round(b.width)}px`; - occTopRef.style.height = `${Math.max(0, Math.round(b.y))}px`; - } - if (occBottomRef) { - occBottomRef.style.top = `${Math.round(b.y + b.height)}px`; - occBottomRef.style.left = `${Math.round(b.x)}px`; - occBottomRef.style.width = `${Math.round(b.width)}px`; - } - }); - }), - ); - - const altDown = createKeyDownSignal(window, "Alt"); - - return ( -
fill()} - > - - - {(transform) => ( -
- {realBounds().width} x {realBounds().height} -
- )} -
-
- - {resolvedChildren()} - - {/* Occluder */} -