diff --git a/.cargo/config.toml b/.cargo/config.toml
deleted file mode 100644
index 304e9ab..0000000
--- a/.cargo/config.toml
+++ /dev/null
@@ -1,13 +0,0 @@
-include = [{ path = "local.toml", optional = true }]
-
-# Cargo configuration with lint policy
-# Clippy lint levels enforce code quality while remaining pragmatic
-
-[build]
-# Use all available CPU cores for faster builds
-jobs = -1
-
-[alias]
-# Convenient cross-platform lint commands
-lint = "clippy --all-targets --all-features -- -D warnings"
-fmt-check = "fmt -- --check"
diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
index e875e74..17913cb 100644
--- a/.github/copilot-instructions.md
+++ b/.github/copilot-instructions.md
@@ -1,802 +1,337 @@
-# SproutGit — Copilot Instructions
+# SproutGit Copilot Instructions
-## Repository
+> These instructions apply to every AI-assisted change in this repository.
-- **Owner / GitHub org**: [InterestingSoftware](https://github.com/InterestingSoftware)
-- **Repo URL**: https://github.com/InterestingSoftware/SproutGit.git
+**GitHub:** https://github.com/InterestingSoftware/SproutGit
+**Owner / org:** InterestingSoftware
+**Repo:** SproutGit
+**Clone URL:** https://github.com/InterestingSoftware/SproutGit.git
-## What is SproutGit?
+## Project overview
-Open-source, cross-platform Git desktop app with a **worktree-first** workflow. The MVP lets users clone/init repos, manage Git worktrees in a prescribed directory layout, view a commit graph, and create branches paired with worktrees.
+SproutGit is an Electron-based, cross-platform Git desktop app with a **worktree-first** workflow.
-## Tech Stack
+**Monorepo:** pnpm v11 workspaces + Turborepo v2
+**Dev command:** `pnpm dev`
+**Test command:** `pnpm test` (unit) / `pnpm test:e2e` (Playwright E2E)
+**Typecheck:** `pnpm typecheck`
+**Lint:** `pnpm lint`
-| Layer | Technology | Notes |
-| ------------------ | ---------------------------------------------------------- | ------------------------------------------------------------ |
-| Desktop shell | **Tauri v2** | Rust backend, webview frontend |
-| Frontend framework | **SvelteKit + Svelte 5** | SSR disabled (`ssr = false`), `adapter-static` for SPA |
-| Language | **TypeScript** (frontend), **Rust** (backend) | |
-| Styling | **Tailwind CSS v4** | via `@tailwindcss/vite` plugin |
-| State (frontend) | Svelte 5 runes | `$state`, `$derived`, `$derived.by`, `$props`, `$effect` |
-| State (persistent) | **SQLite** via `rusqlite` (bundled) + `rusqlite_migration` | workspace `state.db` + app-global `config.db` |
-| Package manager | **pnpm** | Tauri hooks use `pnpm run dev` / `pnpm run build` |
-| Git integration | CLI-based | Rust backend shells out to `git` via `std::process::Command` |
+---
-## Project Structure
+## Stack & versions
-This structure is a high-level orientation map. For file-level accuracy, verify against the current workspace tree before making assumptions.
+| Technology | Version |
+|---|---|
+| Electron | 42 |
+| electron-vite | 5 |
+| electron-builder | 26 |
+| React | 19 |
+| TanStack Router | 1 |
+| Zustand | 5 |
+| Tailwind CSS | 4 (`@tailwindcss/vite`) |
+| TypeScript | 5 |
+| Drizzle ORM | latest |
+| simple-git | latest |
+| node-pty | latest |
+| Playwright | latest |
-```
-sproutgit/
-├── src/ # SvelteKit frontend
-│ ├── app.css # Global design tokens (--sg-* CSS vars), animations, light/dark theme
-│ ├── lib/
-│ │ ├── sproutgit.ts # Typed API layer wrapping Tauri invoke() calls
-│ │ ├── toast.svelte.ts # Toast notification state (Svelte 5 rune module, no stores)
-│ │ └── components/
-│ │ ├── CommitGraph.svelte # SVG commit graph with lane algorithm, search, context menu, worktree markers
-│ │ ├── Autocomplete.svelte # Filterable dropdown with keyboard nav, aria attributes
-│ │ ├── ContextMenu.svelte # Right-click context menu, auto-positions within viewport
-│ │ ├── Spinner.svelte # Animated loading spinner (sm/md/lg)
-│ │ └── ToastContainer.svelte # Fixed-position toast renderer (auto-dismiss, slide animations)
-│ └── routes/
-│ ├── +layout.svelte # Minimal: imports app.css, renders
-│ ├── +layout.ts # export const ssr = false
-│ ├── +page.svelte # Screen 1: Project picker (clone, open, recent projects)
-│ ├── settings/
-│ │ └── +page.svelte # Settings screen
-│ └── workspace/
-│ └── +page.svelte # Screen 2: Workspace (worktree mgmt + commit graph)
-├── src-tauri/
-│ ├── src/
-│ │ ├── lib.rs # Tauri entry: registers all commands
-│ │ ├── db.rs # Database connections + migration runner
-│ │ ├── workspace.rs # Workspace create/inspect/import commands
-│ │ ├── hooks.rs # Hook definitions, dependencies, run history
-│ │ ├── git/ # Git operations, helpers, diff, staging
-│ │ └── ... # config, editor, github, terminal, watcher
-│ ├── migrations/
-│ │ ├── workspace/ # Migrations for per-workspace state.db
-│ │ │ └── 001_initial_schema.sql
-│ │ └── config/ # Migrations for app-global config.db
-│ │ └── 001_initial_schema.sql
-│ ├── tauri.conf.json # App config: window 1200x800, min 900x600, resizable
-│ ├── Cargo.toml # Rust deps: tauri, rusqlite, rusqlite_migration, sea-orm, …
-│ └── capabilities/default.json # Permissions: core, opener, dialog
-├── docs/
-│ ├── index.md # Documentation index; read first to discover relevant docs for a task
-│ ├── requirements.md # Full MVP requirements with P0/P1 features
-│ └── design-review-and-screen-plan.md # Screen architecture (8 screens planned)
-└── package.json # pnpm scripts: dev, build, check, tauri
-```
-
-## Documentation Index (Required)
-
-The `docs/` folder contains product, architecture, security, and workflow decisions that may be directly relevant to implementation work.
-
-Agent requirements:
-
-- At the start of each new task, read `docs/index.md` first to discover whether any repository docs are relevant.
-- If a linked doc is relevant to the task, read it before making design or implementation decisions.
-- When adding, renaming, removing, or substantially repurposing a document in `docs/`, update `docs/index.md` in the same change.
-- Treat `docs/index.md` as the maintained entry point for the repository documentation set.
-
-## Tauri Playwright Adapter (Required For E2E Changes)
-
-When working on `e2e/**`, adapter fixtures, or Playwright/Tauri bridge behavior, read `docs/tauri-playwright-adapter-cheatsheet.md` before editing.
-
-Key reminders:
-
-- `TauriPage` is Playwright-like but not identical to `Page`.
-- `TauriLocator.waitFor` expects a numeric timeout, not a Playwright options object.
-- Keep plugin socket/port values consistent across setup/launch and worker processes for each run.
-- In `tauri` mode, do not use `page.goto()` for app reset or startup navigation.
-- Prefer per-spec `beforeEach` reset hooks over global Playwright lifecycle hooks for stateful E2E flows.
-- For E2E isolation, reset both the test workspace directory and the isolated config DB, then return to the project picker with stable in-app navigation (`ensureHome()`-style helpers). Avoid making full webview reloads the default reset path for the suite.
-- Current default runtime is headless Playwright in `e2e/playwright.config.ts`; do not switch to headed by default.
-- During reset, clear cached workspace hints (`sg_workspace_hint`) **before** navigating home; the clear must happen before the home page mounts so `onMount` never auto-navigates back to the previous workspace. Do not perform a full `window.location.reload()` — UI-driven navigation already tears down and remounts all page components, and hard reloads cost 20–45 s on slow Windows CI runners.
-- In E2E `beforeEach` hooks, the required reset order is: `resetConfigDb()` → `reloadToHome()` → `resetTestDirs()`. Rationale: (1) `resetConfigDb()` first so the app never queries a deleted schema; the config DB lives in a separate run-scoped directory with no watcher or process holding it open. (2) `reloadToHome()` second so the workspace `onDestroy` fires `closeAllTerminals()` + `stopWatchingWorktrees()` before any filesystem cleanup — PTY children (PowerShell on Windows) hold CWD handles on worktree directories, and watchers hold directory handles. (3) `resetTestDirs()` last, after those handles are released.
-
-### E2E Selector Strategy (Required)
-
-- Prefer `getByTestId(...)` for all E2E element interactions and waits.
-- Use CSS selectors only when no stable test ID exists, and keep those selectors narrow and local.
-- If an interaction depends on visual state (hover-only controls, transient overlays), add or use a dedicated test ID before introducing brittle structural selectors.
-- **If a needed `data-testid` does not exist in the UI source, add it.** Never work around a missing test ID with fragile structural selectors — add the `data-testid` attribute to the component/template and use it in the test.
-
-## E2E Failure Triage Protocol (Required)
-
-When debugging a flaky or platform-specific E2E failure, follow this order exactly.
-
-1. Reproduce locally with the narrowest failing scope (single spec or test name).
-2. Classify the failure as one of: deterministic logic bug, timing/timeout issue, state reset leak, or platform-only behavior.
-3. Validate reset assumptions first (workspace cleanup, config DB reset, `sg_workspace_hint` clear, verified reload).
-4. If Windows-only, inspect path format and shell semantics before raising timeouts.
-5. Apply the smallest fix that addresses root cause; avoid masking deterministic failures with broad timeout increases.
-6. Re-run only the affected spec first, then re-run the required E2E gate.
-
-### Timeout Budget Policy (Required)
+---
-- Keep Playwright per-test timeout and helper timeouts aligned; do not change one without auditing the other.
-- For CI reliability updates, document why each timeout changed and which operation consumed the budget.
-- Increase timeouts only when evidence shows slow-environment variance; if failure is deterministic, fix behavior instead.
-- When a timeout is increased, include before/after values in the commit message or PR notes.
-
-## Workspace Layout (User Projects)
-
-SproutGit manages user repos in a prescribed directory layout:
+## Monorepo structure
```
-/
-├── root/ # Main bare-ish checkout (protected, don't work directly here)
-├── worktrees/ # Managed worktrees created by SproutGit
-│ ├── feature-foo/
-│ └── bugfix-bar/
-└── .sproutgit/ # SproutGit metadata
- └── state.db # SQLite: workspace state (meta, hooks, sessions)
+app/ ← Electron app (main + renderer + preload)
+packages/
+ git/ ← @sproutgit/git — simple-git wrapper; all Git operations
+ terminal/ ← @sproutgit/terminal — node-pty wrapper
+ database/ ← @sproutgit/database — Drizzle + node:sqlite
+ types/ ← @sproutgit/types — shared types + ALL IPC channel constants
+ ui/ ← @sproutgit/ui — shared React components
+ ts-config/ ← shared tsconfig
+ eslint-config/ ← shared ESLint config
+e2e/ ← Playwright end-to-end tests
+website/ ← Astro marketing site
+old/ ← Legacy Tauri/SvelteKit source (do NOT modify)
```
-## Rust Backend (`src-tauri/src/lib.rs`)
-
-`src-tauri/src/lib.rs` is the source of truth for registered Tauri commands via `tauri::generate_handler![]`.
-
-### Structs (all `#[serde(rename_all = "camelCase")]`)
-
-- `GitInfo` — installed, version
-- `WorktreeInfo` — path, head, branch, detached
-- `WorktreeListResult` — repo_path, worktrees
-- `WorkspaceInitResult` — workspace_path, root_path, worktrees_path, metadata_path, state_db_path, cloned
-- `WorkspaceStatus` — workspace_path, root_path, worktrees_path, metadata_path, state_db_path, is_sproutgit_project, root_exists, worktrees_exists, metadata_exists, state_db_exists
-- `RefInfo` — name, full_name, kind, target
-- `RefsResult` — repo_path, refs
-- `CommitEntry` — hash, short_hash, parents, author_name, author_date, subject, refs
-- `CommitGraphResult` — repo_path, commits
-- `CreateWorktreeResult` — worktree_path, branch, from_ref
-
-### Tauri Commands (Representative, Not Exhaustive)
-
-Representative command groups currently include:
-
-- Git operations and worktree lifecycle (`git_info`, `list_worktrees`, `create_managed_worktree`, `delete_managed_worktree`, `checkout_worktree`, `reset_worktree_branch`, `get_worktree_push_status`, `fetch_worktree`, `pull_worktree`, `push_worktree_branch`)
-- Diff and staging (`get_diff_files`, `get_diff_content`, `get_worktree_status`, `stage_files`, `unstage_files`, `create_commit`, `get_working_diff`)
-- Workspace and config (`create_sproutgit_workspace`, `import_git_repo_workspace`, `inspect_sproutgit_workspace`, recent workspaces, app settings)
-- Hooks (`list_workspace_hooks`, create/update/delete/toggle, `run_workspace_hook`)
-- Worktree metadata (`list_worktree_provenance`, `get_worktree_provenance`, nested repo sync rule CRUD)
-- Editor/Git tool integration (`open_in_editor`, editor detection, git config read/write)
-- Terminal and watcher (`spawn_terminal`, `terminal_input`, `start_watching_worktrees`)
-- Optional E2E-only helpers (`set_window_size` when `e2e-testing` feature is enabled)
+---
-When command surfaces change, update this section in the same change.
+## Main process (`app/src/main/`)
-### Helper Functions
+- **Entry point:** `app/src/main/index.ts`
+ - Registers all IPC handlers on app startup
+ - Creates `BrowserWindow` with `titleBarStyle: 'hiddenInset'` on macOS
+ - Sets `app.name = 'SproutGit'` before `whenReady()`
+ - Sets dock icon in dev mode via `app.dock?.setIcon()`
+ - Registers macOS application menu via `Menu.setApplicationMenu()` — **required for Cmd+C/V/Z/X to work in text inputs**
+ - Handles `open-file` event and sends `IPC.EVENT_OPEN_WORKSPACE` to renderer
-- `run_git(args)` — Execute `git` with args, capture stdout
-- `ensure_git_success(args)` — Run git, return error on non-zero exit
-- `normalize_existing_path` / `normalize_or_create_dir` — Path canonicalization
-- `initialize_workspace_db(path)` — Run workspace migrations, creating `state.db` if needed
-- `slugify_for_path(name)` — Branch name → filesystem-safe slug
-- `now_epoch_seconds()` — Current Unix timestamp
+- **IPC handlers:** `app/src/main/ipc/`
+ - `git.ts` — Git operations (delegates to `@sproutgit/git`)
+ - `workspace.ts` — workspace CRUD, recent workspaces, hooks, worktree metadata
+ - `workspace-init.ts` — import, init, inspect workspace (creates `.sproutgit/` layout)
+ - `terminal.ts` — PTY create/write/resize/kill (delegates to `@sproutgit/terminal`)
+ - `settings.ts` — user settings stored in config DB
+ - `system.ts` — OS utilities (dialog, open external, home dir)
+ - `github.ts` — GitHub OAuth + repo listing
+ - `hooks.ts` — workspace lifecycle hook execution
+ - `watcher.ts` — chokidar filesystem watcher → push events to renderer
+ - `update.ts` — electron-updater auto-update
-### Important Patterns
+---
-- Clone uses `--progress` flag with piped stderr, emitting `clone-progress` Tauri events via `tauri::Emitter` for real-time UI feedback
-- `create_sproutgit_workspace` takes `app_handle: tauri::AppHandle` for event emission
-- Commit graph uses `\x1e` (record separator) as field delimiter in git log format
-- All git operations use `git -C ` to target specific repos
+## IPC contract
-## Frontend API (`src/lib/sproutgit.ts`)
+**Rule: all IPC channel names live in `packages/types/src/ipc.ts`.**
-Typed wrappers around `invoke()` from `@tauri-apps/api/core`. Every Rust struct has a matching TypeScript type.
+- Export name pattern: `IPC.DOMAIN_ACTION` (e.g., `IPC.GIT_STAGE_FILES`)
+- String value pattern: `'domain:action'` (e.g., `'git:stageFiles'`)
+- Event channels are prefixed `EVENT_` and use the string prefix `'event:'`
-`src/lib/sproutgit.ts` is the source of truth for frontend-callable API wrappers.
+When adding a new IPC call:
+1. Add the constant to `packages/types/src/ipc.ts`
+2. Rebuild types: `pnpm --filter @sproutgit/types build`
+3. Add the handler in the appropriate `app/src/main/ipc/*.ts` file
+4. Expose it via `window.api` in `app/src/preload/index.ts` using `contextBridge.exposeInMainWorld`
+5. Consume via `window.api.myNewCall()` in the renderer — never use `ipcRenderer` directly in the renderer
-Representative export groups include:
+---
-- `getGitInfo()`, `createWorkspace()`, `inspectWorkspace()`
-- Workspace import and recents/settings
-- Worktree lifecycle (`createManagedWorktree`, delete, checkout, reset, push status, fetch, pull, push/publish)
-- Diff and staging helpers
-- Hook CRUD + progress listeners (`onHookProgress`)
-- Worktree provenance + nested repo sync rule helpers
-- File watcher helpers
-- Terminal lifecycle helpers
-- GitHub auth/repo helpers
-- Event listeners (`onCloneProgress`, `onImportProgress`, `onWorktreeChanged`, terminal events)
+## Preload (`app/src/preload/index.ts`)
-## Theme System
+Exposes `window.api` (and types `Window.Api`) via `contextBridge`.
-CSS custom properties with auto dark mode:
+- Invoke calls: `ipcRenderer.invoke(IPC.CHANNEL, ...args)`
+- Event subscriptions return an unsubscribe function:
+ ```ts
+ onMyEvent: (cb: (data: MyData) => void) => {
+ const listener = (_e: Electron.IpcRendererEvent, data: MyData) => cb(data);
+ ipcRenderer.on(IPC.MY_EVENT, listener);
+ return () => ipcRenderer.removeListener(IPC.MY_EVENT, listener);
+ },
+ ```
-- Light mode: `:root { --sg-bg: #f5f5f5; --sg-primary: #1a8a5c; ... }`
-- Dark mode: `@media (prefers-color-scheme: dark) { :root { --sg-bg: #1e1e2e; --sg-primary: #74c7a4; ... } }`
-- All tokens prefixed `--sg-*`: bg, surface, surface-raised, border, border-subtle, text, text-dim, text-faint, primary, primary-hover, danger, warning, accent, input-bg, input-border, input-focus
+---
-Always use `var(--sg-*)` tokens in components. Never hardcode colors outside of `app.css`.
+## Renderer (`app/src/renderer/`)
-**Light and dark mode are both required.** Every component and UI surface must look correct in both. When designing or editing any UI:
+### Routing
-- Use only `var(--sg-*)` tokens — never hardcode hex colors in components.
-- Mentally verify the design in both light mode (`--sg-bg: #f5f5f5`, `--sg-text: #1e1e2e`) and dark mode (`--sg-bg: #1e1e2e`, `--sg-text: #cdd6f4`).
-- Components that use Canvas or WebGL rendering (e.g. xterm.js terminals) require explicit theme objects for both modes — detect `window.matchMedia('(prefers-color-scheme: dark)').matches` at init time and apply the correct theme.
-- For screenshot testing, `forceTheme()` in `e2e/helpers/screenshots.ts` handles CSS var injection and xterm canvas re-theming — keep it in sync with any new terminal-like components.
+- **TanStack Router v1** with `createHashHistory()`
+- Routes in `app/src/renderer/routes/`:
+ - `__root.tsx` — root layout (ToastContainer, `onOpenWorkspace` subscription)
+ - `index.tsx` — home/landing view (recent workspaces, clone, import)
+ - `workspace.tsx` — main workspace view (worktree sidebar + content area)
+ - `settings.tsx` — settings panel
+- Navigation: `useNavigate()` from TanStack Router, or `window.location.hash = '#/route?param=value'`
-## Commit Graph Component
+### State management
-`CommitGraph.svelte` implements a hand-rolled lane assignment algorithm:
+- **Zustand v5**; stores in `app/src/renderer/stores/`
+- `useWorkspaceStore` — active workspace path, gitRepoPath, worktrees, status
+- `useUpdateStore` — update availability state
-- **Algorithm**: Two-pass column allocation. First pass assigns lanes (first parent continues lane, others allocate new). Second pass resolves parent positions for line drawing.
-- **Rendering**: SVG for lane lines (straight + bezier curves) alongside a commit list with subject, ref badges, short hash, author, date.
-- **Search**: CMD/CTRL+F opens inline search bar. Matches by subject, short hash, or full hash. Enter/Shift+Enter navigates matches. Non-matching rows dim to 30% opacity.
-- **Context Menu**: Right-click on commits, branches, or tags shows copy actions (hash, message, branch, worktree path). Uses `ContextMenu.svelte`.
-- **Worktree Integration**: Accepts `worktrees` prop. Commits on worktree branches get a diamond node shape (vs circle), a "WT" badge, and a distinct accent-colored ref badge with ⌥ prefix. Worktree branches are highlighted in `--sg-accent` color.
-- **Constants**: ROW_H=28, COL_W=16, NODE_R=4, 10 cycling lane colors.
+### Styling
-## UI Components
+- **Tailwind CSS v4** — utility classes only (no config file, uses CSS variables)
+- CSS variables for brand/semantic colours defined in `app/src/renderer/tailwind.css`
+- Custom variable prefix: `--sg-*`
+- Use `cn()` (from `clsx`/`tailwind-merge`) for conditional class names
+- **Icons:** use `lucide-react` for all renderer/UI icons. Do not introduce new icon libraries, emoji glyphs, or ad-hoc inline icon text when a Lucide icon exists.
-### Toast System (`toast.svelte.ts` + `ToastContainer.svelte`)
+### Workspace layout components
-- **State module**: `toast.svelte.ts` exports `toast.info()`, `toast.success()`, `toast.error()`, `toast.warning()`. Uses `$state` (no Svelte stores). Auto-dismiss after 4s by default.
-- **Renderer**: `ToastContainer.svelte` mounted in `+layout.svelte`. Fixed top-right, slide-in/out animations, close button.
+Located in `app/src/renderer/workspace/`:
+- `WorktreeSidebar.tsx` — list of worktrees + compact icon toolbar
+- `dialogs/` — `NewWorktreeDialog`, `DeleteWorktreeDialog`, `HooksDialog`, etc.
-### Autocomplete (`Autocomplete.svelte`)
+---
-- Filterable dropdown with `items: {label, value, detail?}[]`. Supports keyboard nav (up/down/enter/escape), click outside to close.
-- Two-way binding via `bind:value`. `onselect` callback. ARIA combobox role.
-- Used for source branch selection in the workspace sidebar.
+## Database (`@sproutgit/database`)
-### Context Menu (`ContextMenu.svelte`)
+- **`node:sqlite`** (built into Electron ≥32) — no native binary dependencies
+- Drizzle ORM for schema and migrations
+- **Config DB:** `userData/config.db` — user settings, recent workspaces
+- **Workspace DB:** `/.sproutgit/state.db` — worktree metadata, hooks, per-workspace UI state, etc.
+- Schema in `packages/database/src/schema/`
+- Migrations in `packages/database/migrations/` (two folders: `config/` and `workspace/`)
+- **Always generate migrations with drizzle-kit — never write migration SQL by hand.**
+ - Config schema: `cd packages/database && pnpm drizzle-kit generate --config=drizzle.config.config.ts`
+ - Workspace schema: `cd packages/database && pnpm drizzle-kit generate --config=drizzle.workspace.config.ts`
-- `items: MenuItem[]` with `{label, action, icon?, danger?}` or `{separator: true}`.
-- Auto-adjusts position to stay within viewport bounds. Closes on click outside or Escape.
+---
-### Spinner (`Spinner.svelte`)
+## Git package (`@sproutgit/git`)
-- Sizes: `sm`, `md`, `lg`. Optional `label` text. Uses `--sg-primary` color.
+All git operations go through this package. Do not call `simple-git` directly from the main process — always import from `@sproutgit/git`.
-### Form Controls (`Checkbox.svelte` + `Select.svelte`)
+Key modules:
+- `client.ts` — simpleGit factory with defaults
+- `commits.ts` — log, graph data
+- `diff.ts` — diff, patch
+- `staging.ts` — stage, unstage, commit
+- `worktrees.ts` — list, add, remove worktrees
+- `branches.ts` — create, delete, rename branches
+- `remote.ts` — fetch, pull, push
-- Use shared form controls from `src/lib/components/` instead of ad-hoc checkbox/select markup in feature components.
-- `Checkbox.svelte` is the source of truth for custom checkbox visuals and spacing behavior. Keep checked/unchecked icon rendering layout-stable to avoid row height shifts.
-- `Select.svelte` is the source of truth for themed dropdowns. Prefer it over native `