localdeck 1.4.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/dashboard.md CHANGED
@@ -6,39 +6,59 @@ Open the dashboard with `localdeck open`. It runs on `http://localhost:7777` by
6
6
 
7
7
  ## Command palette
8
8
 
9
- Press **⌘K** on macOS or **Ctrl+K** on Windows/Linux, or click **Search commands** in the sidebar. Search by action, project, or service name; words can appear in any order, such as `logs web my-app`. Use **↑/↓** to select, **Enter** to run, and **Escape** to close. Closing returns focus to the previous control.
9
+ Press **⌘K** on macOS or **Ctrl+K** on Windows/Linux, or click **Search** in the sidebar. Search by action, project, or service name; words can appear in any order, such as `logs web my-app`. Use **↑/↓** to select, **Enter** to run, and **Escape** to close. Closing returns focus to the previous control.
10
10
 
11
- Commands open projects, Settings, running app URLs, logs, and requests, and start, stop, or restart individual services through the existing dashboard controls. Start is available for configured stopped services; restart is available for configured daemon-owned services. Controls are unavailable while disconnected or while that service is starting, stopping, or restarting. Failed actions stay visible in the palette. Project loading failures show a Retry control.
11
+ Commands open projects, project and global Settings, running app URLs, and each service's logs, requests or configuration page, and start, stop, or restart individual services. Start is available for configured stopped services; restart is available for configured daemon-owned services. Controls are unavailable while disconnected or while that service is starting, stopping, or restarting. Failed actions stay visible in the palette. Project loading failures show a Retry control.
12
12
 
13
- ## Pages and projects
13
+ ## Layout and navigation
14
14
 
15
- - **Projects** (`/projects`) lists projects remembered through the CLI. Selecting one opens `/projects/<id>`.
16
- - **All Services** (`/services`) lists configured and running services across projects, with search, Start/Stop, Share, View logs, and View requests controls.
17
- - **Settings** (`/settings`) contains Clean URLs and the log display limit.
18
- - **About** (`/about`) contains setup and command information.
19
- - **Changelog** (`/changelog`) lists release features and changes.
15
+ The sidebar holds **Search**, **Projects**, **All services**, and your projects with a status dot and running count. Its footer shows the daemon status; the ⚙ menu opens **Settings**, **About**, and **Changelog**. Collapse the sidebar to icons with the button beside the logo, or drag its edge (arrow keys and Home/End also work) to resize it. On phones it opens as an overlay and closes after you navigate.
20
16
 
21
- Routes support refresh, direct links, and browser Back/Forward. LocalDeck remembers registered project files; it does not scan your disk. Missing or invalid projects remain visible with recovery actions until fixed or forgotten.
17
+ Every view has its own address, so refresh, direct links, middle-click and browser Back/Forward all work. Back and Forward return to where you were on the page. Search boxes keep their text in the address (`?q=`).
22
18
 
23
- Project pages expose individual Start/Stop, View logs, View requests, and Share controls, plus Start all and Stop all. Start includes prerequisites and waits for readiness; Stop all reverses dependency order. Local and shared URLs appear below each service. Failed services keep their own errors so other services remain usable.
19
+ | Address | Page |
20
+ | --- | --- |
21
+ | `/projects` | Projects you've remembered through the CLI |
22
+ | `/projects/<id>` | A project's **Overview**; tabs for **Activity**, **Checks**, **Secrets** and **Settings** follow the same address |
23
+ | `/projects/<id>/services/<name>` | A service's page: **Logs**, **Requests** (`…/requests`) and **Config** (`…/config`) tabs |
24
+ | `/services` | All services across projects |
25
+ | `/settings`, `/about`, `/changelog` | App settings, setup and command reference, release notes |
24
26
 
25
- Dashboard-started services run in the background under the daemon. Terminal services stay attached to their original CLI session; stopping them is supported, but restart them from their terminal. Unexpected process exits trigger up to three automatic restarts, each after a three-second delay. Logs show the attempt number; after the third failed retry, start the service manually to try again. The retry budget lasts until the next manual start. Stop, Stop all, Ctrl-C, and daemon shutdown cancel pending retries. Shutting down the daemon stops its services and shares.
27
+ LocalDeck remembers registered project files; it does not scan your disk. Missing or invalid projects remain visible with Retry and Forget until fixed or forgotten.
28
+
29
+ ## Projects and services
30
+
31
+ The project header shows the project name and status, the **Environment** (Git worktree) and **Profiles** menus, the tabs, and **Start project** / **Start remaining**, **Stop project** and **Open app**. Start includes prerequisites and waits for readiness; Stop reverses dependency order.
32
+
33
+ Each service row shows its address, ports, share link and status, with Start, Stop (and Restart when its configuration changed) and an options menu: **View logs**, **View requests**, **Configure**, **Watch in panel**, **Copy address**, and **Share…** or **Stop sharing**. Select a service's name to open its page. Failed services keep their own errors so other services remain usable.
34
+
35
+ Dashboard-started services run in the background under the daemon. Terminal services stay attached to their original CLI session; stopping them is supported, but restart them from their terminal (the service page says so). Unexpected process exits trigger up to three automatic restarts, each after a three-second delay. Logs show the attempt number; after the third failed retry, start the service manually to try again. The retry budget lasts until the next manual start. Stop, Stop project, Ctrl-C, and daemon shutdown cancel pending retries. Shutting down the daemon stops its services and shares.
36
+
37
+ ## Feedback and confirmations
38
+
39
+ Saving shows a short confirmation in the bottom-right corner and closes whatever opened the form. Errors stay on screen until you dismiss them, and the field that caused one is marked. Actions that delete something ask first: forgetting a project, removing a secret, deleting a check, clearing logs or requests, and removing the Clean URLs forwarder. Press **Escape** to close the topmost menu, dialog or inspector.
40
+
41
+ ## Profiles
42
+
43
+ When `.localdeck` defines [profiles](configuration.md#profiles), a **Profiles** menu appears beside Environment at the top of the project page. Tick profiles to turn them on or off for this project on this computer; **Turn all off** clears them. Each entry shows its description and which services it changes. If two active profiles change the same setting, the menu says which one wins.
44
+
45
+ The active profiles appear next to the project status, and each service they change gets a small profile tag. Switching never starts, stops or restarts services. A running service whose settings changed shows **Restart to apply profile changes** with a Restart button. Terminal-owned services say to restart them in their terminal instead. The same notice appears after hand-editing a running service's command, directory, environment or secret names in `.localdeck`.
26
46
 
27
47
  ## Project settings
28
48
 
29
- Use **Settings** beside the project name to edit its nickname and service configuration. The nickname is saved to `.localdeck`; an unchanged nickname disables Save, and a blank nickname removes it.
49
+ Open the **Settings** tab (`/projects/<project-id>/settings`) for the project's nickname, service configuration, profiles, diagnostics and **Forget project** (under Danger zone). The nickname is saved to `.localdeck`; an unchanged nickname disables Save, and a blank nickname removes it.
30
50
 
31
51
  A nickname such as `platform` produces `http://platform.web.localhost:7777`. Without one, a unique service may use `http://web.localhost:7777`. Ambiguous short names are rejected rather than routed to the wrong project. Qualified aliases and stable numeric URLs remain available.
32
52
 
33
- Service configuration fills the available width. Edit stable and upstream ports, TCP or HTTP readiness, timing, and startup dependencies. Changes are validated and saved atomically, and apply to running services after restart. Commands, working directories, environment values, and command-based readiness remain file-edited.
53
+ Each service links to its **Config** tab, which shows **What it will run**: its command, working directory, environment variables and secret names with active profiles applied, and whether each came from the base service or a profile. Secret values are never shown. Edit stable and upstream ports, TCP or HTTP readiness, timing, and startup dependencies. Changes are validated and saved atomically, and apply to running services after restart. Commands, working directories, environment values, and command-based readiness remain file-edited. The **Profiles** section lists each profile, whether it is on, and what it changes; profiles are also edited in `.localdeck`.
34
54
 
35
- The Secrets button beside Settings on the project page opens a dedicated Secrets page at `/projects/<project-id>/secrets`. It lists declared names and whether each value is configured. Use Add secret, Replace, or Set value to open the editor popover; click outside or press Escape to dismiss it. Remove deletes a saved value. Password fields start empty; saved values are never shown again. Secrets are stored in plaintext on this computer, outside your project. They are not encrypted. Anyone with access to the file can read them. Changes apply when the service next starts. Secret values are per machine and must be configured separately on each machine.
55
+ The **Secrets** tab (`/projects/<project-id>/secrets`) lists declared names and whether each value is configured. **Add secret**, **Replace** and **Set value** open a dialog; saving closes it. **Remove** asks before deleting a saved value. Password fields start empty; saved values are never shown again. Secrets are stored in plaintext on this computer, outside your project. They are not encrypted. Anyone with access to the file can read them. Changes apply when the service next starts. Secret values are per machine and must be configured separately on each machine.
36
56
 
37
57
  ## Logs
38
58
 
39
- Choose **Logs** or **View logs** to open that service's tab in the bottom panel. Select additional sources from the Services menu; **All selected** combines their output chronologically. Filter retained output or follow new lines. Use the trash icon beside a service tab to clear that service’s logs. Clearing keeps the service running and new output continues to appear.
59
+ Each service page has **Logs** and **Requests** tabs for that service. To watch several services at once, open the panel at the bottom: select **Logs** or **Requests** in the bar at the bottom of the window, press **⌘J** (**Ctrl+J**), or choose **Watch in panel** from a service's menu. Pick sources from the **Services** menu; **All selected** combines their output chronologically. Filter retained output or follow new lines. Use the trash icon beside a source to clear its logs or requests after confirming. Clearing keeps the service running and new output continues to appear.
40
60
 
41
- Drag the panel's top edge to resize it, or focus the edge and use the arrow keys or Home/End. Its height is saved in the browser. The panel stays available when navigating between pages.
61
+ Drag the panel's top edge to resize it, or focus the edge and use the arrow keys or Home/End. Its height is saved in the browser. The panel stays open while you move between pages.
42
62
 
43
63
  **Settings → Logs** sets the display limit from 100 to 5,000 lines, default 1,000. Values above 5,000 are clamped. This controls the dashboard buffer and view; the daemon retains a bounded history of its own, so increasing the setting cannot recover discarded output.
44
64
 
@@ -46,17 +66,17 @@ Tunnel requests and sharing events have a **SHARE** label and distinct color. Re
46
66
 
47
67
  ## Public sharing
48
68
 
49
- Install [cloudflared](https://developers.cloudflare.com/tunnel/downloads/) separately. Start an HTTP service, choose **Share**, enter an optional password, and submit. Leaving the password blank generates one; reveal it with **Show** next to the link. To share without a password, tick **Public link** explicitly. Database services cannot be shared over HTTP.
69
+ Install [cloudflared](https://developers.cloudflare.com/tunnel/downloads/) separately. Start an HTTP service, choose **Share…** from its options menu, enter an optional password, and select **Create link**. Leaving the password blank generates one; reveal it with **Show** next to the link. To share without a password, tick **Public link** explicitly. Database services cannot be shared over HTTP.
50
70
 
51
- The menu closes on submission. The generated URL appears below the local URL with a spinner until verified. At one minute, a hint suggests opening it manually; a request reaching the public tunnel can confirm readiness even when the daemon's DNS probe fails. Startup has a two-minute limit. Failure closes the tunnel and shows an inline error with retry guidance.
71
+ The dialog closes on submission. The generated URL appears below the local URL with a spinner until verified. At one minute, a hint suggests opening it manually; a request reaching the public tunnel can confirm readiness even when the daemon's DNS probe fails. Startup has a two-minute limit. Failure closes the tunnel and shows an inline error with retry guidance.
52
72
 
53
- Pending state, the generated URL, and startup failures live in the daemon and survive dashboard refresh. They are not restored after daemon shutdown. Active protected links display a masked password with Show/Hide; the password is fetched on demand and is not included in service listings or events. The Share menu also provides Copy link and Stop sharing.
73
+ Pending state, the generated URL, and startup failures live in the daemon and survive dashboard refresh. They are not restored after daemon shutdown. Active protected links display a masked password with Show/Hide; the password is fetched on demand and is not included in service listings or events. Copy the link with the button beside it; **Stop sharing** is in the service's options menu.
54
74
 
55
75
  Quick Tunnel URLs are temporary and depend on Cloudflare DNS and connectivity. Stop sharing, service stop/restart, terminal disconnect, and daemon shutdown end the link. Named tunnels and custom public domains are not configured in v1.
56
76
 
57
77
  ## Clean URLs
58
78
 
59
- Enable **Clean URLs** in Settings or through the prompt above Local runtime. LocalDeck verifies its own response through port 80 before displaying links without `:7777`. Keep the dashboard itself on its original port.
79
+ Enable **Clean URLs** in Settings or through the notice at the bottom of the sidebar. LocalDeck verifies its own response through port 80 before displaying links without `:7777`. Keep the dashboard itself on its original port.
60
80
 
61
81
  On macOS, installation may request administrator approval for a localhost-only system forwarder. It runs Apple's `nc` as the normal user and survives reboot. The daemon and application processes remain unprivileged. Cancellation retains the normal URLs; retry from Settings when needed.
62
82
 
@@ -85,3 +105,23 @@ Traffic must pass through a LocalDeck service URL to be captured. Calls directly
85
105
  For an occupied startup port, service errors show recovery guidance with the raw output under Technical details. Vite guidance covers `strictPort` and reading `PORT`; LocalDeck does not change your application configuration or terminate unrelated listeners.
86
106
 
87
107
  Clean URLs and public links are distinct browser origins. Your API must allow the frontend origin you visit. Injected `LOCALDECK_URL` and service URL references use stable numeric localhost addresses for service-to-service communication. See [configuration](configuration.md).
108
+
109
+ ## Activity and Since my change
110
+
111
+ Open a project and select **Activity** to combine request records, logs, and service lifecycle transitions. The default **Incidents** view emphasizes failures and state changes; **All activity**, service filters, and search narrow the stream. Inspecting an event pauses live updates so the evidence stays in place. Event links can be copied and reopened; expired or cleared records are identified instead of silently replaced. Nearby events are temporal context, not proof that a request caused a log line.
112
+
113
+ Use **Mark baseline** before changing code. LocalDeck saves a summary of the preceding five minutes and compares it with later observations for the same services. Comparisons show sample counts, error rates, restarts, error signatures, and route latency. Windows may have different lengths. “Not observed again” does not mean verified fixed; sparse traffic and incomplete history are explicitly reported. The latest 50 baselines are retained across restarts. Logs and requests keep their existing bounded history, and the lifecycle journal retains the latest 2,000 transitions. Clearing logs or requests also removes those records from Activity.
114
+
115
+ ## Worktree environments
116
+
117
+ The project environment selector discovers existing Git worktrees from the selected repository, including matching nested project configurations. Choose **Register & switch** to add a sibling worktree, or **Switch** for one already registered. Discovery does not start services. Branch names, detached HEADs, directories, availability, and running counts identify the selected environment.
118
+
119
+ Each worktree retains its path-based project ID and independent automatic ports. Copied nicknames are qualified when needed to avoid routing to another environment. Conflicting explicitly pinned ports are reported; LocalDeck does not override them. Databases, Docker resources, and external services can still be shared through configuration. Secrets are not copied. This release discovers existing worktrees; it does not create or delete them.
120
+
121
+ ## Saved reproduction checks
122
+
123
+ In a request inspector, choose **Preview sanitized request**, review omitted values, then copy cURL or structured JSON. Exported headers are restricted to representation metadata, recognized credentials are removed, and unsupported/incomplete bodies are omitted. Review the preview before sharing it: application data may still be private.
124
+
125
+ Eligible GET/HEAD requests can be saved with a name and an explicitly chosen expected HTTP status. Open the project's **Checks** tab to run them. Saving never executes a request. Runs use the selected environment's current local service, omit credentials, do not follow redirects, and retain the existing five-second/64-KiB replay bounds. Secret-bearing paths and requests with bodies cannot be saved as executable checks. Even GET can have application side effects.
126
+
127
+ Check definitions survive expiration or clearing of the source request. The latest 200 checks and 20 results per check are retained. Results distinguish an expected status, a status mismatch, and transport failure; response bodies are not persisted in run history.
package/docs/mcp.md CHANGED
@@ -51,12 +51,24 @@ A protocol connection alone starts no apps. The first tool call starts the daemo
51
51
  | Tool | What it does |
52
52
  | --- | --- |
53
53
  | `list_projects` | List remembered projects, IDs and configuration availability. |
54
- | `list_services` | List registered and configured services, including ones that have never run. Optional `projectId` filter. |
55
- | `get_service` | Read a configured or registered service's state; ports, URLs and counters appear after its first start. |
54
+ | `list_services` | List registered and configured services, including ones that have never run. Optional `projectId` filter. Running services include the `profiles` they started with and `restartNeeded`. |
55
+ | `get_service` | Read a configured or registered service's state; ports, URLs and counters appear after its first start. `configuration` shows the resolved command and where each setting came from (base or a profile); environment and secret values are not returned. |
56
56
  | `get_logs` | Read recent logs, optionally filtered by `stream`: stdout, stderr or system. |
57
57
  | `get_requests` | Read HTTP request records, captured headers, and body previews when available, optionally filtered by exact `status`, `method`, or a `path` substring. |
58
58
  | `get_response` | Read a cached response body using the exact service key and request ID from `get_requests`; does not replay the request. |
59
- | `start_service` | Start a configured service and prerequisites in the background, using the daemon supervisor. |
59
+ | `get_timeline` | Read project activity with optional exact `services`, `filter` (`all` or `incidents`), `query`, `cursor`, and `limit` (maximum 200). Returns `items`, optional `nextCursor`, and `coverage`. |
60
+ | `mark_baseline` | Explicitly save a marker for `projectId`, optional exact `services` and `label`. Does not run requests. |
61
+ | `list_baselines` | Read saved markers for a project. |
62
+ | `compare_baseline` | Compare a project's `baselineId`: before/after evidence, `newlyObserved`, `notObservedAgain`, `insufficientEvidence`, and `coverage`. |
63
+ | `list_environments` | Discover a project's Git worktree environments without registering or starting them. With `--project`, returns only that project's environment. |
64
+ | `register_environment` | Explicitly register a discovered `environmentId`. Disabled with `--project`, because registration can add another project. |
65
+ | `export_request` | Export a redacted reproduction for an exact service key and request ID without executing it. |
66
+ | `save_check` | Save a recorded GET/HEAD using `projectId`, `serviceKey`, `requestId`, `name`, and `expectedStatus` (100–599), without running it. |
67
+ | `list_checks` | Read a project's saved checks and retained results. |
68
+ | `run_check` | Explicitly execute one saved `checkId` against its current local service. Even GET can have side effects. |
69
+ | `list_profiles` | Read a project's profiles, which services each changes, which are on, and any clashes. |
70
+ | `set_profiles` | Replace the list of profiles turned on for `projectId` on this computer. Never starts, stops or restarts services; running services report `restartNeeded` until restarted. |
71
+ | `start_service` | Start a configured service and prerequisites in the background, using the daemon supervisor. Uses the project's active profiles. |
60
72
  | `stop_service` | Stop a registered service and its share. Terminal services receive the existing stop request. |
61
73
  | `restart_service` | Restart a configured daemon-owned service. Active terminal services must be restarted in their original terminal. |
62
74
  | `replay_request` | Resend a recorded GET/HEAD, selected by `requestId`, to that service's current local upstream. |
@@ -64,7 +76,7 @@ A protocol connection alone starts no apps. The first tool call starts the daemo
64
76
  | `start_share` | Create a Cloudflare quick share, generating a password and returning it once. `public: true` explicitly removes password protection. Requires cloudflared. |
65
77
  | `stop_share` | Close the tunnel while keeping the local service running. |
66
78
 
67
- List tools accept `limit` (default 50, maximum 200). Logs and request filters search the last 200 retained records; they are not full-history queries. Responses contain structured data and a JSON text fallback, capped together at 64 KiB, with `truncated` when information is omitted. No infinite log-follow operation is exposed.
79
+ `list_projects`, `list_services`, `get_logs`, `get_requests`, and `get_timeline` accept `limit` (default 50, maximum 200). Logs and request filters search the last 200 retained records; they are not full-history queries. Responses contain structured data and a JSON text fallback, capped together at 64 KiB, with `truncated` when information is omitted. No infinite log-follow operation is exposed.
68
80
 
69
81
  ## Actions and data
70
82
 
@@ -129,7 +141,7 @@ Bodies live in the daemon's shared 64 MiB cache. They can be evicted or lost on
129
141
 
130
142
  1. If an action times out, do not repeat it immediately: it may already have completed.
131
143
  2. Call `get_service` or `get_share` to inspect the resulting state. Each tool call rediscovers the daemon connection.
132
- 3. Retry only after establishing that the requested change is still needed. Log and request reads are bounded snapshots; there is no live-follow tool or pagination cursor.
144
+ 3. Retry only after establishing that the requested change is still needed. Log and request reads are bounded snapshots; there is no live-follow tool. Timeline reads provide an opaque pagination cursor for retained activity.
133
145
 
134
146
  ### Share a service for review
135
147
 
@@ -138,3 +150,15 @@ Bodies live in the daemon's shared 64 MiB cache. They can be evicted or lost on
138
150
  3. When sharing is authorized, call `start_share`; password protection is the default. Use `public: true` only when unprotected public access is intended.
139
151
  4. Return the URL and the newly generated password from that result. `get_share` cannot recover the password later.
140
152
  5. Call `stop_share` when the share is no longer needed; the local service stays running.
153
+
154
+
155
+ ### Compare evidence around a fix
156
+
157
+ 1. Discover the project and exact service keys. Read `get_timeline` with `filter: "incidents"`; use `nextCursor` for another retained page and inspect `coverage`.
158
+ 2. Before changing code, explicitly call `mark_baseline` with the project, optional service keys, and a useful label.
159
+ 3. Make the change and generate representative traffic only when authorized. Marking or comparing a baseline never sends requests automatically.
160
+ 4. Call `compare_baseline` using the marker's ID. Report newly observed evidence and evidence not observed again separately. Missing retention or traffic can make a comparison inconclusive; absence of an incident does not prove a fix.
161
+ 5. Use `export_request` to inspect a redacted reproduction without executing it. Missing credentials and omitted bodies can limit reproducibility.
162
+ 6. For an authorized repeatable GET/HEAD check, call `save_check` with the expected status, then explicitly `run_check`. Saving and listing checks never runs them. Check execution retains the same local-destination and credential restrictions as replay.
163
+
164
+ Environment discovery is read-only. `register_environment` remembers an explicitly selected worktree and does not launch it. Project-restricted MCP servers reject registration; use an unrestricted server or register through the dashboard when that broader action is intended.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "localdeck",
3
- "version": "1.4.0",
3
+ "version": "1.6.1",
4
4
  "type": "module",
5
5
  "description": "Stable ports, shareable HTTPS links and request logs for your local dev servers",
6
6
  "bin": {
@@ -1 +0,0 @@
1
- :root{color-scheme:dark;--bg: #191b1d;--bg-2: #202325;--bg-3: #24282b;--border: #353a3d;--text: #ededed;--muted: #a0a6aa;--accent: #b6ef6b;--accent-hover: #c5f58a;--accent-ink: #1c2515;--selected: #293322;--input-border: #515b61;--radius: 6px;--orange: #b6ef6b;--ok: #b6ef6b;--warn: #d1b576;--err: #ed9e91;--share: #91c7c4;--chrome: #191b1d;--chrome-border: #353a3d;--chrome-text: #ededed;--chrome-muted: #a0a6aa;--mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;--sans: var(--mono);--text-small: .75rem;--text-body: .8125rem;--text-label: .875rem;--text-section: 1rem;--text-title: 2.25rem;--control-height: 2.25rem}*{box-sizing:border-box}html{font-size:100%}html,body{margin:0;min-width:320px;height:100%;background:var(--chrome);color:var(--text);font-family:var(--sans);line-height:1.5}body{font-size:var(--text-body)}#app{height:100%}a{color:var(--accent);text-decoration:none}a:hover{text-decoration:underline}button{display:inline-flex;align-items:center;justify-content:center;text-align:center;gap:6px;font:500 var(--text-body)/1.4 var(--sans);color:var(--text);background:transparent;border:1px solid var(--border);border-radius:var(--radius);padding:7px 12px;min-height:var(--control-height);cursor:pointer;white-space:nowrap}button:hover{background:var(--bg-2);border-color:var(--muted)}button.primary{background:var(--accent);border-color:var(--accent);color:var(--accent-ink)}button.primary:hover{background:var(--accent-hover);border-color:var(--accent-hover)}button.danger:hover{color:var(--err);border-color:var(--err)}button:disabled{opacity:.45;cursor:default}input,select,textarea{font:inherit;color:var(--text);background:transparent;border:1px solid var(--border);border-radius:var(--radius);padding:8px 10px}input:not([type=checkbox]):not([type=radio]),select{min-height:var(--control-height)}input,select,textarea{font-size:var(--text-body);border-color:var(--input-border)}input[type=checkbox]{accent-color:var(--accent)}button:focus-visible,a:focus-visible,summary:focus-visible{outline:2px solid var(--accent);outline-offset:3px}code,.mono{font-family:var(--mono);font-size:var(--text-small)}::-webkit-scrollbar{width:7px;height:7px}::-webkit-scrollbar-thumb{background:#8f8f8560}[hidden]{display:none!important}summary{cursor:pointer}pre{overflow:auto}@media(prefers-reduced-motion:reduce){*,*:before,*:after{scroll-behavior:auto!important;transition:none!important}}@media(pointer:coarse),(max-width:760px){:root{--control-height: 2.75rem}input:not([type=checkbox]):not([type=radio]),select,textarea{font-size:1rem}}label:has(input[type=checkbox]){min-height:var(--control-height)}input:focus-visible,select:focus-visible,textarea:focus-visible{outline:2px solid var(--accent);outline-offset:3px}::selection{background:var(--accent);color:var(--accent-ink)}input::placeholder,textarea::placeholder{color:#929a9f}button,a{-webkit-tap-highlight-color:transparent;transition:background .12s,border-color .12s,color .12s}button:active:not(:disabled){transform:translateY(1px)}h1{font-weight:400;letter-spacing:-.04em}@media(prefers-reduced-motion:reduce){button,a{transition:none}button:active:not(:disabled){transform:none}}:root{--page-padding-x: 40px;--page-padding-y: 48px}.page-shell{width:100%;min-width:0;padding:var(--page-padding-y) var(--page-padding-x)}.page-heading{display:flex;align-items:flex-start;justify-content:space-between;flex-wrap:wrap;gap:20px;margin:0 0 24px}.page-heading h1{margin:0;font:400 var(--text-title)/1.25 var(--sans);letter-spacing:-.04em;overflow-wrap:anywhere}.page-heading .page-subtitle{margin:8px 0 0;color:var(--muted);font:400 var(--text-small)/1.5 var(--sans)}@media(max-width:760px){:root{--page-padding-x: 16px;--page-padding-y: 24px;--text-title: 1.5rem}.page-heading{gap:12px}}dialog.svelte-vw7b2v{width:min(640px,calc(100vw - 32px));max-height:min(620px,80dvh);margin:12dvh auto auto;padding:0;border:1px solid var(--border);background:var(--bg);color:var(--text);box-shadow:0 24px 80px #0005;overflow:hidden;border-radius:8px}dialog[open].svelte-vw7b2v{display:flex;flex-direction:column}dialog.svelte-vw7b2v::backdrop{background:#1119}.search-row.svelte-vw7b2v{display:flex;align-items:center;gap:12px;padding:14px 18px;border-bottom:1px solid var(--border);flex-shrink:0}.search-row.svelte-vw7b2v svg{flex-shrink:0;color:var(--muted)}input.svelte-vw7b2v{flex:1;min-width:0;border:0;padding:8px 0}.close.svelte-vw7b2v{min-height:28px;padding:3px 6px;font:12px var(--mono);color:var(--muted)}.results.svelte-vw7b2v{overflow:auto;min-height:0;padding:6px}.results.svelte-vw7b2v button:where(.svelte-vw7b2v){width:100%;justify-content:space-between;gap:16px;border:0;padding:12px;text-align:left;white-space:normal}.results.svelte-vw7b2v button.chosen:where(.svelte-vw7b2v){background:var(--accent);color:var(--accent-ink)}.results.svelte-vw7b2v button.chosen:where(.svelte-vw7b2v) small:where(.svelte-vw7b2v){color:var(--accent-ink)}.search-row.svelte-vw7b2v:focus-within{border-bottom-color:var(--accent)}.search-row.svelte-vw7b2v input:where(.svelte-vw7b2v):focus-visible{outline:none}.results.svelte-vw7b2v button[aria-disabled=true]:where(.svelte-vw7b2v){color:var(--muted)}strong.svelte-vw7b2v,small.svelte-vw7b2v{display:block}strong.svelte-vw7b2v{font-weight:500}small.svelte-vw7b2v{font-size:var(--text-small);color:var(--muted);overflow-wrap:anywhere}footer.svelte-vw7b2v{display:flex;justify-content:space-between;gap:12px;padding:12px 18px;border-top:1px solid var(--border);font-size:var(--text-small);color:var(--muted);flex-shrink:0}.separator.svelte-vw7b2v{margin:0 6px}.empty.svelte-vw7b2v,.error.svelte-vw7b2v{padding:16px 18px;margin:0}.empty.svelte-vw7b2v{color:var(--muted)}.error.svelte-vw7b2v{color:var(--err)}.load-error.svelte-vw7b2v{display:flex;align-items:center;gap:12px;padding:12px 18px;color:var(--err);border-top:1px solid var(--border);font-size:var(--text-small)}@media(max-width:480px){dialog.svelte-vw7b2v{margin-top:6dvh;max-height:88dvh}.search-row.svelte-vw7b2v{gap:8px;padding:10px}footer.svelte-vw7b2v{flex-wrap:wrap}}section.svelte-1hauwfi{margin-top:32px}h3.svelte-1hauwfi{margin:0 0 12px;font:500 var(--text-section)/1.4 var(--sans)}p.svelte-1hauwfi,li.svelte-1hauwfi{line-height:1.7}p.svelte-1hauwfi{color:var(--muted)}ul.svelte-1hauwfi{padding-left:20px}code.svelte-1hauwfi{overflow-wrap:anywhere}.copy-command.svelte-1hauwfi{display:inline-flex;vertical-align:middle;padding:4px;margin-left:5px;min-height:28px;width:28px;border:0;border-radius:0;background:transparent;color:var(--muted)}.copy-command.svelte-1hauwfi:hover{background:transparent;color:var(--text)}.sr-only.svelte-1hauwfi{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}li.svelte-1hauwfi+li:where(.svelte-1hauwfi){margin-top:8px}h2.svelte-1vwaeio{font-size:var(--text-section);line-height:1.4;margin:0 0 12px;font-weight:600}p.svelte-1vwaeio{line-height:1.6;margin:0 0 16px;max-width:65ch}.about.svelte-1vwaeio>section:where(.svelte-1vwaeio){margin-top:40px;padding-top:28px;border-top:1px solid var(--border)}.steps.svelte-1vwaeio{padding-left:24px;margin:20px 0}.steps.svelte-1vwaeio li:where(.svelte-1vwaeio){padding-left:8px;margin-bottom:16px}.steps.svelte-1vwaeio span:where(.svelte-1vwaeio){display:block;margin-top:4px;color:var(--muted)}.note.svelte-1vwaeio{color:var(--muted);font-size:var(--text-small)}code.svelte-1vwaeio{overflow-wrap:anywhere}.command-groups.svelte-1vwaeio{margin:24px 0;border-top:1px solid var(--border)}details.svelte-1vwaeio{border-bottom:1px solid var(--border)}summary.svelte-1vwaeio{padding:16px 0;min-height:var(--control-height);font-weight:500}summary.svelte-1vwaeio span:where(.svelte-1vwaeio){color:var(--muted);font-size:var(--text-small);font-weight:400;margin-left:12px;white-space:nowrap}dl.svelte-1vwaeio{margin:0 0 16px}dl.svelte-1vwaeio>div:where(.svelte-1vwaeio){padding:16px 0}dl.svelte-1vwaeio>div:where(.svelte-1vwaeio)+div:where(.svelte-1vwaeio){border-top:1px solid var(--border)}dt.svelte-1vwaeio{margin-bottom:8px}dd.svelte-1vwaeio{margin:0;color:var(--muted);line-height:1.6;max-width:65ch}@media(max-width:760px){summary.svelte-1vwaeio span:where(.svelte-1vwaeio){display:block;margin:4px 0 0 18px}}h3.svelte-1offp6a{margin-top:32px;font:500 var(--text-section)/1.4 var(--sans)}label.svelte-1offp6a{display:block;margin-bottom:8px}.controls.svelte-1offp6a{display:flex;align-items:center;gap:8px}input.svelte-1offp6a{width:160px}input.svelte-1offp6a:focus-visible{outline:none;border-color:var(--text)}p.svelte-1offp6a{color:var(--muted);line-height:1.6}.current.svelte-1offp6a{font-size:var(--text-small)}article.svelte-1tl5wtp{padding:28px 0;border-bottom:1px solid var(--border)}h2.svelte-1tl5wtp{margin:0 0 16px;font:500 var(--text-section)/1.4 var(--sans)}h2.svelte-1tl5wtp span:where(.svelte-1tl5wtp){color:var(--muted);margin-left:12px;font-size:var(--text-label)}h3.svelte-1tl5wtp{font-size:var(--text-label);font-weight:500;margin:0 0 10px}.release-section.svelte-1tl5wtp{max-width:100ch;margin-top:28px}li.svelte-1tl5wtp+li:where(.svelte-1tl5wtp){margin-top:8px}ul.svelte-1tl5wtp{margin:0;padding-left:20px;line-height:1.8}.secrets.svelte-sh54s5{margin-top:28px}h2.svelte-sh54s5{font-size:18px;margin:0;font-weight:500}.section-heading.svelte-sh54s5{display:flex;align-items:center;justify-content:space-between;gap:16px}.count.svelte-sh54s5,.section-note.svelte-sh54s5{font-size:var(--text-small);color:var(--muted)}.section-note.svelte-sh54s5{margin:8px 0 22px;line-height:1.6}ul.svelte-sh54s5{padding:0;margin:0;list-style:none}.list-heading.svelte-sh54s5,li.svelte-sh54s5{display:grid;grid-template-columns:minmax(0,1fr) 130px minmax(124px,auto);gap:16px;align-items:center}.list-heading.svelte-sh54s5{padding:0 0 10px;border-bottom:1px solid var(--border);color:var(--muted);font-size:var(--text-small)}li.svelte-sh54s5{min-height:66px;padding:12px 0;border-bottom:1px solid var(--border)}code.svelte-sh54s5{overflow-wrap:anywhere;font-size:var(--text-small)}.secret-status.svelte-sh54s5{display:flex;gap:7px;align-items:center;font-size:var(--text-small);color:var(--muted)}.secret-status.svelte-sh54s5 i:where(.svelte-sh54s5){width:6px;height:6px;flex-shrink:0;background:currentColor}.secret-status.configured.svelte-sh54s5{color:var(--ok)}.actions.svelte-sh54s5{display:flex;justify-content:flex-end;gap:14px}.text-action.svelte-sh54s5{padding:4px 0;min-height:32px;border:0;background:transparent;font-size:var(--text-small);text-decoration:underline;text-underline-offset:4px}.text-action.svelte-sh54s5:hover{text-decoration-thickness:2px}.remove.svelte-sh54s5{color:var(--muted)}.count.svelte-sh54s5{display:block;margin-top:6px}.secret-editor.svelte-sh54s5{position:relative}summary.svelte-sh54s5{cursor:pointer;list-style:none;display:inline-flex;gap:7px;align-items:center;justify-content:center}summary.svelte-sh54s5::-webkit-details-marker{display:none}summary[aria-disabled=true].svelte-sh54s5{opacity:.5;cursor:default}.add-secret.svelte-sh54s5{padding:7px 12px;min-height:var(--control-height);border:1px solid var(--border);font-weight:500}.add-secret.svelte-sh54s5:hover{background:var(--bg-2)}.editor-popover.svelte-sh54s5{position:absolute;top:calc(100% + 8px);right:0;z-index:40;width:min(340px,calc(100vw - 110px));padding:20px;background:var(--bg);border:1px solid var(--border);border-radius:8px;box-shadow:0 8px 24px #0005;text-align:left}.editor-popover.svelte-sh54s5 h2:where(.svelte-sh54s5){margin-bottom:20px}.editor-popover.svelte-sh54s5 .section-note:where(.svelte-sh54s5){margin:14px 0}.editor-popover.svelte-sh54s5 .primary:where(.svelte-sh54s5){width:100%}.fields.svelte-sh54s5{display:grid;grid-template-columns:1fr;gap:16px}label.svelte-sh54s5{display:grid;gap:8px;font-size:var(--text-small);font-weight:500;min-width:0}input.svelte-sh54s5{width:100%;min-width:0;background:var(--bg)}.storage-note.svelte-sh54s5{margin-top:28px;padding-left:14px;border-left:2px solid var(--border);max-width:680px;font-size:var(--text-small);color:var(--muted)}.storage-note.svelte-sh54s5 strong:where(.svelte-sh54s5){font-weight:500;color:var(--text)}.storage-note.svelte-sh54s5 p:where(.svelte-sh54s5){margin:6px 0 0;line-height:1.6}.error.svelte-sh54s5{color:var(--err)}.saved.svelte-sh54s5{color:var(--ok)}.empty.svelte-sh54s5{padding:22px 0;border-block:1px solid var(--border);color:var(--muted)}@media(max-width:1000px){.list-heading.svelte-sh54s5{display:none}li.svelte-sh54s5{grid-template-columns:minmax(0,1fr) auto;gap:8px 16px}.secret-status.svelte-sh54s5{grid-column:1;grid-row:2}.actions.svelte-sh54s5{grid-column:2;grid-row:1 / 3}}@media(max-width:650px){.fields.svelte-sh54s5{grid-template-columns:1fr;gap:16px}form.svelte-sh54s5{padding:18px}}.share-line.svelte-iodvty{display:flex;align-items:center;flex-wrap:wrap;gap:8px 16px;min-width:0}.slow-hint.svelte-iodvty{flex-basis:100%;color:var(--muted);font-size:var(--text-small)}.slow-hint.svelte-iodvty a:where(.svelte-iodvty){text-decoration:underline}.password.svelte-iodvty{display:inline-flex;flex-wrap:wrap;align-items:center;gap:7px;color:var(--muted);font-size:var(--text-small);overflow-wrap:anywhere}.password.svelte-iodvty button:where(.svelte-iodvty){padding:0;min-height:0;border:0;background:transparent;text-decoration:underline;color:inherit}a.svelte-iodvty{width:fit-content;max-width:100%;overflow-wrap:anywhere;color:var(--share);font-size:var(--text-small)}.connecting.svelte-iodvty,.error.svelte-iodvty{display:flex;align-items:center;gap:7px;font-size:var(--text-small)}.connecting.svelte-iodvty{flex-wrap:wrap;color:var(--muted)}.error.svelte-iodvty{color:var(--err);align-items:flex-start;overflow-wrap:anywhere}.error.svelte-iodvty svg{flex-shrink:0;margin-top:3px}.spinner.svelte-iodvty{display:inline-flex;animation:svelte-iodvty-spin 1s linear infinite}@keyframes svelte-iodvty-spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.spinner.svelte-iodvty{animation:none}}.menu-item.svelte-1u7hpyn>summary:where(.svelte-1u7hpyn){justify-content:flex-start;gap:10px;border:0;font-weight:400;padding:10px 12px}.menu-item.svelte-1u7hpyn .share-popover:where(.svelte-1u7hpyn){position:static;width:100%;box-shadow:none;border:0;padding:12px}.share-control.svelte-1u7hpyn{position:relative}summary.svelte-1u7hpyn{display:flex;align-items:center;justify-content:center;gap:7px;padding:7px 12px;min-height:var(--control-height);border:1px solid var(--border);list-style:none;font-weight:500}summary.svelte-1u7hpyn::-webkit-details-marker{display:none}summary.svelte-1u7hpyn:hover{background:var(--bg-2);border-color:var(--muted)}.share-popover.svelte-1u7hpyn{position:absolute;right:0;top:calc(100% + 8px);z-index:30;width:min(340px,calc(100vw - 96px));padding:18px;border:1px solid var(--border);background:var(--bg);border-radius:8px;box-shadow:0 8px 24px #0005;text-align:left}.share-url.svelte-1u7hpyn{display:block;margin-top:12px;overflow-wrap:anywhere}p.svelte-1u7hpyn{font-size:var(--text-small);color:var(--muted);line-height:1.6;overflow-wrap:anywhere}label.svelte-1u7hpyn{display:grid;gap:6px;font-size:var(--text-small)}label.public.svelte-1u7hpyn{display:flex;align-items:center;gap:8px;margin-bottom:12px}label.public.svelte-1u7hpyn input:where(.svelte-1u7hpyn){width:auto}input.svelte-1u7hpyn{width:100%;min-width:0}.actions.svelte-1u7hpyn{display:flex;flex-wrap:wrap;gap:8px}.error.svelte-1u7hpyn{color:var(--err)}.service-options.svelte-m918bk{position:relative}summary.svelte-m918bk{display:flex;align-items:center;justify-content:center;gap:8px;padding:7px 12px;min-height:var(--control-height);border:1px solid var(--border);border-radius:var(--radius);list-style:none;font-weight:500;cursor:pointer}summary.svelte-m918bk::-webkit-details-marker{display:none}summary.svelte-m918bk:hover,.service-options[open].svelte-m918bk>summary:where(.svelte-m918bk){background:var(--bg-2);border-color:var(--muted)}.options-popover.svelte-m918bk{position:absolute;z-index:40;right:0;top:calc(100% + 6px);width:min(300px,calc(100vw - 100px));padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:8px;box-shadow:0 8px 24px #0005}.options-popover.svelte-m918bk>button:where(.svelte-m918bk){width:100%;border:0;background:transparent;display:flex;gap:10px;justify-content:flex-start;padding:10px 12px;text-align:left;font-weight:400}.options-popover.svelte-m918bk>button:where(.svelte-m918bk):hover{background:var(--bg-2)}.share-action.svelte-m918bk{border-top:1px solid var(--border);margin-top:4px;padding-top:4px}.service-error.svelte-13pnhk8{padding:12px 0;font-size:var(--text-small);overflow-wrap:anywhere}strong.svelte-13pnhk8,p.svelte-13pnhk8{color:var(--err)}p.svelte-13pnhk8{margin:0;white-space:pre-wrap}ul.svelte-13pnhk8{margin:8px 0 12px;padding-left:20px;color:var(--text);line-height:1.7}li.svelte-13pnhk8+li:where(.svelte-13pnhk8){margin-top:6px}summary.svelte-13pnhk8{width:fit-content;color:var(--muted)}pre.svelte-13pnhk8{margin:8px 0 0;white-space:pre-wrap;font:inherit;font-family:var(--mono);color:var(--muted)}.diagnostics.svelte-1xk5qw3{margin:16px 0;padding:12px;border:1px solid var(--border);border-radius:0}summary.svelte-1xk5qw3{cursor:pointer}p.svelte-1xk5qw3{color:var(--muted);font-size:var(--text-small)}textarea.svelte-1xk5qw3{display:block;width:100%;box-sizing:border-box;margin:8px 0;background:var(--bg-2);color:var(--text);border:1px solid var(--border);font:var(--text-small)/1.5 var(--mono)}form.svelte-1gn57ev{width:100%;min-width:0;padding:20px 0 8px}fieldset.svelte-1gn57ev{border:0;padding:0;margin:0;min-width:0}.fields.svelte-1gn57ev{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}label.svelte-1gn57ev{display:flex;flex-direction:column;gap:6px;font-size:var(--text-body);color:var(--text)}input.svelte-1gn57ev,select.svelte-1gn57ev{width:100%;min-width:0;background:var(--bg)}.dependencies.svelte-1gn57ev{margin:20px 0;font-size:var(--text-small)}.dependencies.svelte-1gn57ev>div:where(.svelte-1gn57ev){display:flex;flex-wrap:wrap;gap:16px;margin-top:8px}.dependencies.svelte-1gn57ev label:where(.svelte-1gn57ev){flex-direction:row;align-items:center}.dependencies.svelte-1gn57ev input:where(.svelte-1gn57ev){width:auto}p.svelte-1gn57ev{color:var(--muted);font-size:var(--text-small)}.error.svelte-1gn57ev{color:var(--err)}@media(max-width:600px){.fields.svelte-1gn57ev{grid-template-columns:1fr}}form.svelte-ruqv4s{margin:24px 0 40px;max-width:480px}label.svelte-ruqv4s{font-weight:600}p.svelte-ruqv4s{font-size:var(--text-small);color:var(--muted);line-height:1.6}.controls.svelte-ruqv4s{display:flex;gap:8px;margin-top:8px}input.svelte-ruqv4s{flex:1;width:180px;min-width:0}.error.svelte-ruqv4s{color:var(--err);margin-bottom:0}.notice.svelte-ruqv4s{color:var(--ok);margin-bottom:0}.hint.svelte-ruqv4s{font-size:var(--text-small)}.service-port.svelte-1poq4pf{display:flex;flex-wrap:wrap;gap:4px 16px;color:var(--muted);font-size:var(--text-small);line-height:1.5}strong.svelte-1poq4pf{color:var(--text);font-weight:500}.project-overview.svelte-l7un4l{min-height:100%;display:flex;flex-direction:column}.heading.svelte-l7un4l{min-width:0}h1.svelte-l7un4l,h2.svelte-l7un4l,p.svelte-l7un4l{margin-top:0}h2.svelte-l7un4l{margin-bottom:8px;font-size:var(--text-section)}.project-actions.svelte-l7un4l,.service-actions.svelte-l7un4l,.recovery-actions.svelte-l7un4l{display:flex;align-items:center;gap:8px}.summary-row.svelte-l7un4l{display:flex;flex-wrap:wrap;gap:14px;padding:4px 0;color:var(--muted);font-size:var(--text-small)}.summary-row.svelte-l7un4l strong:where(.svelte-l7un4l){color:var(--text);font-variant-numeric:tabular-nums}.bulk-summary.svelte-l7un4l{margin:0 0 10px;color:var(--muted)}.service-grid.svelte-l7un4l{display:grid;grid-template-columns:1fr;gap:0}.service-card.svelte-l7un4l{min-width:0;display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;column-gap:16px;padding:22px 0;border-bottom:1px solid var(--border)}.service-card.failed.svelte-l7un4l{border-color:#f87171a6}.service-main.svelte-l7un4l{display:grid;grid-template-columns:minmax(0,1fr);justify-content:stretch;width:100%;padding:0;border:0;background:transparent;text-align:left;white-space:normal}.service-main.svelte-l7un4l:hover{background:transparent}.service-heading.svelte-l7un4l{display:flex;align-items:center;gap:8px}.status-dot.svelte-l7un4l{width:7px;height:7px;border-radius:50%;background:var(--muted)}.status-dot.running.svelte-l7un4l{background:var(--ok)}.status-dot.waiting.svelte-l7un4l{background:var(--warn)}.status-text.svelte-l7un4l{margin-left:8px;color:var(--muted);font-size:var(--text-small);background:var(--bg-3);border-radius:var(--radius);padding:2px 7px}.ownership.svelte-l7un4l{margin:4px 0 8px 15px;color:var(--muted);font-size:var(--text-small)}.service-url.svelte-l7un4l{color:var(--accent);overflow:hidden;text-overflow:ellipsis}.command.svelte-l7un4l{margin-top:7px;color:var(--text);overflow:hidden;text-overflow:ellipsis}.dependency-summary.svelte-l7un4l{margin-top:7px;color:var(--accent);font-size:var(--text-small)}.dependency-summary.svelte-l7un4l span:where(.svelte-l7un4l){color:var(--muted)}.dependency-editor.svelte-l7un4l{margin-top:10px;padding-top:9px;border-top:1px solid var(--border)}.dependency-editor.svelte-l7un4l summary:where(.svelte-l7un4l){color:var(--muted);cursor:pointer;font-size:var(--text-small)}.dependency-editor.svelte-l7un4l form:where(.svelte-l7un4l){margin-top:9px}.dependency-editor.svelte-l7un4l fieldset:where(.svelte-l7un4l){display:flex;flex-wrap:wrap;gap:7px 12px;margin:0;padding:0;border:0}.dependency-editor.svelte-l7un4l legend:where(.svelte-l7un4l){width:100%;margin-bottom:6px;color:var(--muted);font-size:var(--text-small)}.dependency-editor.svelte-l7un4l label:where(.svelte-l7un4l){display:inline-flex;align-items:center;gap:5px;font-size:var(--text-small)}.dependency-actions.svelte-l7un4l{display:flex;gap:7px;margin-top:10px}.no-dependencies.svelte-l7un4l{color:var(--muted);font-size:var(--text-small)}.inline-error.svelte-l7un4l{margin:9px 0 0;color:var(--err);font-size:var(--text-small);overflow-wrap:anywhere}.unavailable.svelte-l7un4l{display:flex;justify-content:space-between;align-items:center;gap:20px;margin-top:16px;padding:16px;border:1px solid rgba(248,113,113,.55);border-radius:var(--radius);background:var(--bg-2)}.unavailable.svelte-l7un4l p:where(.svelte-l7un4l),.empty-services.svelte-l7un4l p:where(.svelte-l7un4l){margin-bottom:0;color:var(--muted)}.active-services.svelte-l7un4l{margin-top:18px}.active-services.svelte-l7un4l>h2:where(.svelte-l7un4l){margin-bottom:3px}.active-services.svelte-l7un4l>p:where(.svelte-l7un4l){margin-bottom:10px;color:var(--muted)}.empty-services.svelte-l7un4l{grid-column:1 / -1;padding:24px;border:1px dashed var(--border);border-radius:var(--radius);text-align:center}.launch-panel.svelte-l7un4l{padding:20px;background:var(--bg-2);border:1px solid var(--err);border-radius:var(--radius);margin-bottom:32px}.launch-panel.svelte-l7un4l h2:where(.svelte-l7un4l){font-size:var(--text-section);letter-spacing:-.025em;margin:7px 0}.launch-panel.svelte-l7un4l p:where(.svelte-l7un4l):last-child{color:var(--muted);margin-bottom:0;font-size:var(--text-small)}.open-app.svelte-l7un4l{display:inline-flex;align-items:center;gap:10px;padding:7px 12px;min-height:var(--control-height);font-family:var(--sans);line-height:1.4;border-radius:var(--radius);background:var(--accent);color:var(--accent-ink);font-weight:600;white-space:nowrap;font-size:var(--text-body)}.open-app.svelte-l7un4l:hover{background:var(--accent-hover);text-decoration:none}.list-heading.svelte-l7un4l{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:18px}.list-heading.svelte-l7un4l h2:where(.svelte-l7un4l){font-size:var(--text-section);margin:0;font-weight:600}.service-search.svelte-l7un4l span:where(.svelte-l7un4l){display:block;color:var(--muted);font-size:var(--text-small);margin-bottom:4px}.service-search.svelte-l7un4l input:where(.svelte-l7un4l){background:var(--bg-2);width:220px}.service-heading.svelte-l7un4l strong:where(.svelte-l7un4l){font-size:var(--text-body)}.service-settings.svelte-l7un4l{grid-column:1 / -1;margin-top:14px;border-top:1px solid var(--border);padding-top:9px;color:var(--muted);font-size:var(--text-small)}.service-settings[open].svelte-l7un4l{padding-bottom:12px}.service-open.svelte-l7un4l{font-weight:600;padding:8px;white-space:nowrap}.service-actions.svelte-l7un4l{flex-wrap:wrap;justify-content:flex-end}.copy.svelte-l7un4l{background:transparent}.service-links.svelte-l7un4l{display:grid;gap:5px;margin-top:8px;min-width:0}.service-links.svelte-l7un4l a:where(.svelte-l7un4l){width:fit-content;max-width:100%;overflow-wrap:anywhere;font-size:var(--text-small)}.inline-error.svelte-l7un4l{grid-column:1 / -1}.settings-panel.svelte-l7un4l{width:100%;min-width:0}.settings-note.svelte-l7un4l{color:var(--muted);font-size:var(--text-small)}.config-list.svelte-l7un4l{width:100%;min-width:0;margin:20px 0 32px;border-top:1px solid var(--border)}.config-list.svelte-l7un4l>details:where(.svelte-l7un4l){min-width:0;border-bottom:1px solid var(--border);padding:16px 0}.config-list.svelte-l7un4l summary:where(.svelte-l7un4l){min-height:var(--control-height);display:flex;gap:20px;align-items:center;list-style:none}.config-list.svelte-l7un4l summary:where(.svelte-l7un4l)::-webkit-details-marker{display:none}.config-list.svelte-l7un4l summary:where(.svelte-l7un4l) strong:where(.svelte-l7un4l){min-width:80px;font:500 var(--text-label)/1.4 var(--sans)}.config-list.svelte-l7un4l summary:where(.svelte-l7un4l) span:where(.svelte-l7un4l){color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--text-small)}.config-list.svelte-l7un4l summary:where(.svelte-l7un4l) .edit-label:where(.svelte-l7un4l){margin-left:auto;flex-shrink:0;color:var(--text)}.settings-tools.svelte-l7un4l{padding:12px 0;color:var(--muted)}.settings-panel.svelte-l7un4l h2:where(.svelte-l7un4l){margin-top:24px}.project-health.svelte-l7un4l{display:flex;align-items:center;gap:12px;color:var(--muted)}.project-health.svelte-l7un4l:has(.running:where(.svelte-l7un4l)){color:var(--ok)}.project-address.svelte-l7un4l{display:flex;align-items:center;gap:12px;min-width:0;color:var(--muted);padding:24px 0;border-bottom:1px solid var(--border);margin-bottom:28px}.project-address.svelte-l7un4l a:where(.svelte-l7un4l){color:var(--muted);overflow-wrap:anywhere;font-size:var(--text-body)}.project-address.svelte-l7un4l button:where(.svelte-l7un4l),.manage-button.svelte-l7un4l{display:inline-flex;align-items:center;border:0;background:transparent;color:var(--muted);padding:10px}.manage-button.svelte-l7un4l{border-radius:var(--radius);text-decoration:none;border:1px solid var(--border);min-height:var(--control-height);gap:8px;padding:7px 12px;justify-content:center}.overview-row.svelte-l7un4l{display:grid;grid-template-columns:36px minmax(90px,1fr) minmax(60px,.8fr) minmax(90px,1fr);gap:16px;align-items:center;width:100%;font-size:var(--text-body)}.overview-row.svelte-l7un4l strong:where(.svelte-l7un4l){font-size:var(--text-label);font-weight:500;overflow-wrap:anywhere}.service-icon.svelte-l7un4l{width:36px;height:36px;display:grid;place-items:center;border:1px solid var(--border);border-radius:var(--radius);background:var(--bg-2);color:var(--muted)}.technical-name.svelte-l7un4l{color:var(--muted);font-weight:400;overflow-wrap:anywhere}.row-health.svelte-l7un4l{display:flex;align-items:center;gap:9px;color:var(--muted);font-weight:400}.row-health.svelte-l7un4l .status-dot:where(.svelte-l7un4l){background:currentColor;flex-shrink:0}.row-health.ready.svelte-l7un4l{color:var(--ok)}.row-health.errored.svelte-l7un4l{color:var(--err)}.row-health.svelte-l7un4l{text-transform:capitalize}.readiness-summary.svelte-l7un4l{color:var(--muted);font-size:var(--text-body);margin:24px 0 48px}.managing.svelte-l7un4l{margin-top:32px}.muted.svelte-l7un4l{color:var(--muted)}.profiles.svelte-l7un4l{padding:18px;border:1px solid var(--border);border-radius:var(--radius);background:var(--bg-2)}.profiles[open].svelte-l7un4l summary:where(.svelte-l7un4l){margin-bottom:16px}@media(min-width:801px)and (max-width:1100px){.overview-row.svelte-l7un4l{grid-template-columns:48px minmax(0,1fr) auto;gap:16px}.technical-name.svelte-l7un4l{white-space:nowrap;display:none}.managing.svelte-l7un4l .service-card:where(.svelte-l7un4l){grid-template-columns:1fr}.managing.svelte-l7un4l .service-actions:where(.svelte-l7un4l){justify-content:flex-start;margin-top:16px}}@media(max-width:800px){.unavailable.svelte-l7un4l{align-items:stretch;flex-direction:column}.project-actions.svelte-l7un4l button:where(.svelte-l7un4l),.recovery-actions.svelte-l7un4l button:where(.svelte-l7un4l){flex:1}.service-grid.svelte-l7un4l{grid-template-columns:1fr}.service-card.svelte-l7un4l{grid-template-columns:1fr;padding:18px}.service-actions.svelte-l7un4l{justify-content:flex-start;margin-top:16px;gap:6px}.service-actions.svelte-l7un4l button:where(.svelte-l7un4l){padding:8px 10px}.launch-panel.svelte-l7un4l{align-items:flex-start;flex-direction:column;padding:20px}.list-heading.svelte-l7un4l{align-items:stretch;flex-direction:column}.service-search.svelte-l7un4l input:where(.svelte-l7un4l){width:100%}.project-actions.svelte-l7un4l{flex-wrap:wrap}.open-app.svelte-l7un4l{padding:7px 12px;font-size:var(--text-small)}.project-actions.svelte-l7un4l{gap:8px;flex-shrink:0}.manage-button.svelte-l7un4l{min-height:var(--control-height)}.project-address.svelte-l7un4l{padding:24px 0;margin-bottom:28px}.overview-row.svelte-l7un4l{grid-template-columns:40px minmax(0,1fr) auto;gap:12px}.service-icon.svelte-l7un4l{width:40px;height:40px}.technical-name.svelte-l7un4l{white-space:nowrap;display:none}.overview-row.svelte-l7un4l strong:where(.svelte-l7un4l){font-size:var(--text-label)}.row-health.svelte-l7un4l{font-size:var(--text-small)}.service-card.svelte-l7un4l{padding:18px 0}}.service-row.svelte-1h3c7zm{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:12px 24px;padding:20px 0;border-bottom:1px solid var(--border)}.service-info.svelte-1h3c7zm{display:grid;gap:5px;min-width:0}.service-heading.svelte-1h3c7zm{display:flex;align-items:center;gap:9px}strong.svelte-1h3c7zm{font-size:var(--text-label);font-weight:500}.status-dot.svelte-1h3c7zm{width:7px;height:7px;background:var(--muted);flex-shrink:0}.status-dot.running.svelte-1h3c7zm{background:var(--ok)}.service-status.svelte-1h3c7zm,.project-name.svelte-1h3c7zm{color:var(--muted);font-size:var(--text-small)}.service-status.svelte-1h3c7zm{margin-left:6px}.service-address.svelte-1h3c7zm{width:fit-content;max-width:100%;overflow-wrap:anywhere;color:var(--text)}.service-controls.svelte-1h3c7zm{display:flex;align-items:center;gap:8px;flex-wrap:wrap}button.svelte-1h3c7zm{display:inline-flex;justify-content:center;align-items:center;gap:7px}.action-error.svelte-1h3c7zm{grid-column:1 / -1;margin:0;color:var(--err);font-size:var(--text-small)}@media(max-width:900px){.service-row.svelte-1h3c7zm{grid-template-columns:minmax(0,1fr)}.service-controls.svelte-1h3c7zm{justify-content:flex-start}}.body-viewer.svelte-1eh4gal{min-width:0;margin:12px 0;border:1px solid var(--chrome-border)}.body-toolbar.svelte-1eh4gal{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:6px 10px;border-bottom:1px solid var(--chrome-border);color:var(--chrome-muted);font-size:.6875rem}button.svelte-1eh4gal{border:0;border-radius:0;background:transparent;color:var(--chrome-muted);min-height:28px;padding:3px 0;font-size:.6875rem}button.svelte-1eh4gal:hover{background:transparent;color:var(--chrome-text)}pre.svelte-1eh4gal{margin:0;padding:12px;max-height:440px;overflow:auto;white-space:pre;-moz-tab-size:2;tab-size:2;color:var(--chrome-text)}pre.svelte-1eh4gal,code.svelte-1eh4gal{font:.75rem/1.7 var(--mono)}.key.svelte-1eh4gal{color:#b6cbd7}.string.svelte-1eh4gal{color:#b6d598}.number.svelte-1eh4gal{color:#dfbc86}.literal.svelte-1eh4gal{color:#d4a8bb}p.svelte-1eh4gal{margin:8px 12px;color:var(--err)}.metadata.svelte-s74nzf{display:flex;flex-direction:column;margin:16px 0}details.svelte-s74nzf{min-width:0;border-bottom:1px solid var(--chrome-border)}summary.svelte-s74nzf{display:flex;align-items:center;justify-content:space-between;padding:10px 0;list-style:none;cursor:pointer;font-weight:600;color:var(--chrome-text)}summary.svelte-s74nzf::-webkit-details-marker{display:none}summary.svelte-s74nzf:after{content:"›";font-size:1rem}details[open].svelte-s74nzf>summary:where(.svelte-s74nzf):after{transform:rotate(90deg)}summary.svelte-s74nzf:hover{color:#fff}dl.svelte-s74nzf{margin:8px 0;font-family:var(--mono)}dl.svelte-s74nzf>div:where(.svelte-s74nzf){display:grid;grid-template-columns:minmax(90px,1fr) minmax(0,2fr);gap:12px;padding:5px 0;border-bottom:1px solid var(--chrome-border)}dt.svelte-s74nzf,dd.svelte-s74nzf{overflow-wrap:anywhere;white-space:pre-wrap}dd.svelte-s74nzf{margin:0;color:var(--chrome-muted)}h4.svelte-s74nzf{font-size:inherit;margin:12px 0 6px}p.svelte-s74nzf{color:var(--chrome-muted)}.requests-panel.svelte-tqqrb7{display:grid;grid-template-columns:minmax(0,1fr);flex:1;min-height:0;overflow:hidden;font:.75rem/1.6 var(--mono)}.requests-panel.inspecting.svelte-tqqrb7{grid-template-columns:minmax(260px,1fr) minmax(280px,.85fr)}.request-list.svelte-tqqrb7{min-height:0;min-width:0;overflow:auto}table.svelte-tqqrb7{font:inherit;width:100%;border-collapse:collapse;text-align:left;table-layout:fixed}th.svelte-tqqrb7,td.svelte-tqqrb7{padding:9px 14px;vertical-align:middle}th.svelte-tqqrb7{position:sticky;top:0;z-index:1;background:var(--chrome);color:var(--chrome-muted);font-size:.6875rem;font-weight:400;border-bottom:1px solid var(--chrome-border)}.numeric.svelte-tqqrb7{width:88px;text-align:right;white-space:nowrap;font-variant-numeric:tabular-nums}.service-column.svelte-tqqrb7{width:24%;color:var(--chrome-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.request-row.svelte-tqqrb7{cursor:pointer}.request-row.svelte-tqqrb7:nth-of-type(2n){background:#ffffff03}.request-row.svelte-tqqrb7:hover,.request-row.svelte-tqqrb7:focus-within{background:var(--bg-3)}.request-row.selected.svelte-tqqrb7{background:var(--bg-3);box-shadow:inset 2px 0 var(--accent)}button.svelte-tqqrb7{font:inherit;color:var(--chrome-text);background:transparent;border-radius:0}.request-cell.svelte-tqqrb7 button:where(.svelte-tqqrb7){display:flex;justify-content:flex-start;gap:10px;width:100%;min-height:24px;padding:0;border:0;text-align:left}.request-cell.svelte-tqqrb7 button:where(.svelte-tqqrb7):hover{background:transparent}.disclosure.svelte-tqqrb7{color:var(--chrome-muted);flex-shrink:0}.method.svelte-tqqrb7{width:6ch;flex-shrink:0;font-size:.6875rem;color:var(--chrome-muted)}.path.svelte-tqqrb7{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.status.svelte-tqqrb7{color:var(--chrome-text)}.status.failed.svelte-tqqrb7,.error.svelte-tqqrb7{color:var(--err)}.status.redirect.svelte-tqqrb7{color:var(--warn)}.duration.svelte-tqqrb7,.unit.svelte-tqqrb7{color:var(--chrome-muted)}.inspector.svelte-tqqrb7{min-width:0;min-height:0;overflow:auto;padding:0 20px 20px;background:var(--bg-2);border-left:1px solid var(--chrome-border);overflow-wrap:anywhere}.inspector.svelte-tqqrb7 header:where(.svelte-tqqrb7){position:sticky;top:0;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 0;margin-bottom:8px;background:var(--bg-2);z-index:2}.inspector.svelte-tqqrb7 h3:where(.svelte-tqqrb7){margin:0;font-size:inherit;font-weight:500}.close-inspector.svelte-tqqrb7{min-height:28px;width:28px;border:0;padding:0}.inspector.svelte-tqqrb7>strong:where(.svelte-tqqrb7){font-weight:500}.inspector.svelte-tqqrb7 p:where(.svelte-tqqrb7),.inspector.svelte-tqqrb7>span:where(.svelte-tqqrb7){color:var(--chrome-muted)}.replay.svelte-tqqrb7{border:1px solid var(--chrome-border);padding:6px 10px}.empty.svelte-tqqrb7{padding:28px 20px;color:var(--chrome-muted);text-align:center}.empty.svelte-tqqrb7 strong:where(.svelte-tqqrb7){color:var(--chrome-text);font-weight:500}.empty.svelte-tqqrb7 p:where(.svelte-tqqrb7){margin:6px 0 0}@media(max-width:900px){.requests-panel.inspecting.svelte-tqqrb7{grid-template-columns:minmax(0,1fr)}.inspecting.svelte-tqqrb7 .request-list:where(.svelte-tqqrb7){display:none}.inspector.svelte-tqqrb7{border-left:0}}@media(max-width:680px){th.svelte-tqqrb7,td.svelte-tqqrb7{padding:8px}.numeric.svelte-tqqrb7{width:65px}.service-column.svelte-tqqrb7{width:22%}.request-cell.svelte-tqqrb7 button:where(.svelte-tqqrb7){gap:5px}.inspector.svelte-tqqrb7{padding:16px}}.source-tabs-row.svelte-147la1m{display:flex;align-items:stretch;flex-shrink:0;min-width:0;border-bottom:1px solid var(--chrome-border)}.request-options.svelte-147la1m{position:relative;flex-shrink:0;margin-left:auto}.request-options.svelte-147la1m summary:where(.svelte-147la1m){height:100%;padding:8px 14px;border:0;border-left:1px solid var(--chrome-border);color:var(--chrome-muted)}.request-options-menu.svelte-147la1m{position:absolute;bottom:calc(100% + 8px);right:0;z-index:32;width:max-content;max-width:calc(100vw - 80px);padding:8px 12px;border:1px solid var(--chrome-border);background:var(--chrome);box-shadow:0 8px 24px #0005}.request-options-menu.svelte-147la1m label:where(.svelte-147la1m){display:flex;align-items:center;gap:8px;cursor:pointer;font-size:.75rem}.request-options-menu.svelte-147la1m input:where(.svelte-147la1m){flex-shrink:0}.logs-dock.svelte-147la1m{position:relative;display:flex;flex-direction:column;min-height:0;min-width:0;color:var(--chrome-text);background:var(--chrome);border-top:1px solid var(--chrome-border)}.resize-handle.svelte-147la1m{position:absolute;top:-4px;left:0;right:0;height:8px;cursor:ns-resize;touch-action:none;z-index:31}.resize-handle.svelte-147la1m:hover,.resize-handle.svelte-147la1m:focus-visible{background:var(--chrome-muted);outline:none}.logs-toolbar.svelte-147la1m{display:flex;align-items:center;gap:8px;padding:8px 14px;flex:0 0 auto}h2.svelte-147la1m{display:flex;align-items:center;gap:8px;margin:0 10px 0 0;font-size:.875rem;font-weight:500}button.svelte-147la1m,summary.svelte-147la1m{border-radius:0;display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:32px;color:var(--chrome-text);border-color:var(--chrome-border);font-size:.75rem;padding:5px 9px}button.svelte-147la1m:hover,summary.svelte-147la1m:hover{background:#ffffff0b;border-color:var(--chrome-muted)}button.svelte-147la1m:focus-visible,summary.svelte-147la1m:focus-visible,input.svelte-147la1m:focus-visible,.log-output.svelte-147la1m:focus-visible{outline:2px solid var(--chrome-muted);outline-offset:-2px}.source-picker.svelte-147la1m{position:relative;flex-shrink:0}summary.svelte-147la1m{list-style:none;border:1px solid var(--chrome-border)}summary.svelte-147la1m::-webkit-details-marker{display:none}.count.svelte-147la1m{color:var(--chrome-muted)}.source-options.svelte-147la1m{position:absolute;bottom:calc(100% + 8px);left:0;z-index:30;width:min(300px,calc(100vw - 40px));max-height:min(420px,calc(100dvh - var(--logs-height) - 64px));overflow:auto;border:1px solid var(--chrome-border);padding:8px;background:var(--chrome);box-shadow:0 8px 24px #0005}.source-group.svelte-147la1m{border:0;padding:0;margin:0;min-width:0}.source-group.svelte-147la1m+.source-group:where(.svelte-147la1m){border-top:1px solid var(--chrome-border);margin-top:8px;padding-top:8px}.source-group.svelte-147la1m legend:where(.svelte-147la1m){position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.source-options.svelte-147la1m .group-toggle:where(.svelte-147la1m){justify-content:space-between;gap:12px;font-weight:500}.group-toggle.svelte-147la1m>span:where(.svelte-147la1m):first-child{min-width:0;overflow-wrap:anywhere}.select-all.svelte-147la1m{display:inline-flex;align-items:center;gap:6px;flex-shrink:0;color:var(--chrome-muted);font-size:.6875rem;font-weight:400}.source-options.svelte-147la1m .service-choice:where(.svelte-147la1m){padding-left:22px}.source-options.svelte-147la1m input:where(.svelte-147la1m){flex-shrink:0}.source-options.svelte-147la1m label:where(.svelte-147la1m){display:flex;align-items:center;gap:9px;padding:6px 8px;cursor:pointer;font-size:.8125rem}.source-options.svelte-147la1m label:where(.svelte-147la1m):hover{background:#ffffff0b}.source-options.svelte-147la1m input:where(.svelte-147la1m){accent-color:var(--accent)}.filter.svelte-147la1m{display:flex;align-items:center;gap:7px;flex:1;min-width:110px;max-width:360px;color:var(--chrome-muted);border:1px solid var(--chrome-border);padding-left:9px}.filter.svelte-147la1m input:where(.svelte-147la1m){border-radius:0;min-width:0;width:100%;min-height:30px;border:0;padding:4px 8px 4px 0;font-size:.75rem;color:var(--chrome-text)}.filter.svelte-147la1m input:where(.svelte-147la1m)::placeholder{color:var(--chrome-muted)}.close.svelte-147la1m{margin-left:auto;width:32px;padding:0;flex-shrink:0;border:0;background:transparent;color:var(--chrome-muted)}.close.svelte-147la1m:hover{background:transparent;color:var(--chrome-text)}.source-tabs.svelte-147la1m{display:flex;gap:0;min-width:0;overflow-x:auto;padding:0 0 0 14px}.source-tab.svelte-147la1m,.source-tabs.svelte-147la1m .all-sources:where(.svelte-147la1m){display:flex;flex-shrink:0;align-items:center;border:0;border-right:1px solid var(--chrome-border);border-bottom:2px solid transparent;border-radius:0;color:var(--chrome-muted)}.source-tab.active.svelte-147la1m,.source-tabs.svelte-147la1m .all-sources.active:where(.svelte-147la1m){border-bottom-color:var(--accent);background:var(--bg-3);color:var(--chrome-text)}.source-tabs.svelte-147la1m button:where(.svelte-147la1m){border:0;border-radius:0;color:inherit;background:transparent;transform:none}.source-tabs.svelte-147la1m .all-sources:where(.svelte-147la1m){padding:8px 12px}.source-tabs.svelte-147la1m .source-select:where(.svelte-147la1m){align-self:stretch;padding:8px 8px 8px 12px}.source-tab.svelte-147la1m:hover,.source-tabs.svelte-147la1m .all-sources:where(.svelte-147la1m):hover{background:var(--bg-3);color:var(--chrome-text)}.source-tabs.svelte-147la1m .source-select:where(.svelte-147la1m):hover{background:transparent}.source-tabs.svelte-147la1m .clear-source:where(.svelte-147la1m){width:24px;min-height:28px;align-self:stretch;padding:0;margin:0;flex-shrink:0;color:var(--chrome-muted)}.source-tabs.svelte-147la1m .clear-source:where(.svelte-147la1m):hover:not(:disabled){color:var(--err);background:transparent}.source-tabs.svelte-147la1m .clear-source:where(.svelte-147la1m):active:not(:disabled){color:var(--err);background:transparent}.clear-source.svelte-147la1m:disabled{opacity:.4;cursor:wait}.project-name.svelte-147la1m{opacity:.7}.log-output.svelte-147la1m{flex:1;overflow:auto;min-height:0;padding:8px 0;font:.75rem/1.75 var(--mono)}.log-row.svelte-147la1m{display:grid;grid-template-columns:8ch minmax(12ch,22ch) 6ch minmax(0,1fr) 24px;gap:14px;padding:5px 14px;align-items:start}.log-row.single-source.svelte-147la1m{grid-template-columns:8ch 6ch minmax(0,1fr) 24px}.copy-line.svelte-147la1m{opacity:0;min-height:24px;width:24px;padding:0;border:0;color:var(--chrome-muted)}.log-row.svelte-147la1m:hover .copy-line:where(.svelte-147la1m),.copy-line.svelte-147la1m:focus-visible{opacity:1}.copy-line.svelte-147la1m:hover{background:transparent;color:var(--chrome-text)}.log-controls.svelte-147la1m{display:flex;gap:12px}.service-signal.svelte-147la1m{width:6px;height:6px;flex-shrink:0;background:var(--chrome-muted)}.service-signal.running.svelte-147la1m{background:var(--ok)}.service-signal.starting.svelte-147la1m{background:var(--warn)}.service-state.svelte-147la1m{margin-left:auto;color:var(--chrome-muted);font-size:.6875rem}@media(pointer:coarse){.copy-line.svelte-147la1m{opacity:1}}.log-row.svelte-147la1m:nth-child(2n){background:#ffffff03}.log-row.svelte-147la1m:hover{background:var(--bg-3)}time.svelte-147la1m{color:var(--chrome-muted);font-size:.6875rem;font-variant-numeric:tabular-nums;padding-top:1px}.source.svelte-147la1m{color:var(--chrome-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.6875rem;padding-top:1px}.stream.svelte-147la1m{color:var(--chrome-muted);font-size:.6875rem;padding-top:1px}.line.svelte-147la1m{min-width:0;white-space:pre-wrap;overflow-wrap:anywhere;-moz-tab-size:2;tab-size:2}.shared.svelte-147la1m .stream:where(.svelte-147la1m){color:var(--share)}.stderr.svelte-147la1m .stream:where(.svelte-147la1m){color:var(--warn)}@media(max-width:680px){.log-row.svelte-147la1m{grid-template-columns:8ch minmax(0,1fr) 6ch;gap:4px 10px;padding:7px 10px}.log-row.single-source.svelte-147la1m{grid-template-columns:8ch minmax(0,1fr)}.line.svelte-147la1m{grid-column:1 / -1}.copy-line.svelte-147la1m{grid-column:-2 / -1;justify-self:end;opacity:1}}.empty.svelte-147la1m{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100%;gap:4px;text-align:center;font-family:var(--sans)}.empty.svelte-147la1m strong:where(.svelte-147la1m){font-weight:500;font-size:.8125rem}.empty.svelte-147la1m span:where(.svelte-147la1m){color:var(--chrome-muted)}.history-error.svelte-147la1m{padding:8px 14px;color:var(--chrome-text);display:flex;align-items:center;gap:12px}.logs-status.svelte-147la1m{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-shrink:0;min-height:30px;padding:0 14px;border-top:1px solid var(--chrome-border);color:var(--chrome-muted);font-size:.6875rem}.logs-status.svelte-147la1m button:where(.svelte-147la1m){border:0;min-height:28px;font-size:.6875rem;padding:2px 5px}@media(max-width:680px){.logs-toolbar.svelte-147la1m{flex-wrap:wrap;gap:6px;padding:6px 10px}h2.svelte-147la1m{margin-right:0}.filter.svelte-147la1m{order:5;flex-basis:100%;max-width:none}.record-count.svelte-147la1m{display:none}}.layout.svelte-1n46o8q{position:relative;display:grid;grid-template-columns:var(--sidebar-width) minmax(0,1fr);grid-template-rows:minmax(0,1fr) auto auto;height:100dvh;min-height:0;background:var(--chrome)}.app-rail.svelte-1n46o8q{position:relative;grid-row:1 / 3;min-height:0;border-right:1px solid var(--chrome-border);display:flex;flex-direction:column;color:var(--chrome-text)}.brand.svelte-1n46o8q{letter-spacing:-.03em;display:flex;align-items:center;justify-content:space-between;padding:20px 16px;font:500 var(--text-section)/1.2 var(--sans);text-transform:none}.brand-identity.svelte-1n46o8q{display:flex;align-items:center;gap:10px;min-width:0}.brand-identity.svelte-1n46o8q img:where(.svelte-1n46o8q){display:block;flex-shrink:0}.brand-name.svelte-1n46o8q{font-size:var(--text-label)}.collapsed.svelte-1n46o8q .brand-name:where(.svelte-1n46o8q){display:none}.app-rail.svelte-1n46o8q nav:where(.svelte-1n46o8q){display:grid;grid-template-columns:minmax(0,1fr);gap:4px;padding:0 8px}.app-rail.svelte-1n46o8q :is(button:where(.svelte-1n46o8q),a:where(.svelte-1n46o8q)){display:flex;align-items:center;gap:10px;width:100%;min-height:44px;padding:12px 16px;font:500 var(--text-body)/1.4 var(--sans);text-transform:none;color:var(--chrome-muted);background:transparent;border:0;border-left:3px solid transparent;text-align:left}.app-rail.svelte-1n46o8q :where(.svelte-1n46o8q):is(button:where(.svelte-1n46o8q),a:where(.svelte-1n46o8q)):hover{color:var(--chrome-text);background:#ffffff0c}.app-rail.svelte-1n46o8q a:where(.svelte-1n46o8q){text-decoration:none}.app-rail.svelte-1n46o8q a.active:where(.svelte-1n46o8q){color:var(--accent);border-left-color:var(--accent);background:var(--selected)}.app-rail.svelte-1n46o8q :is(button:where(.svelte-1n46o8q),a:where(.svelte-1n46o8q)) svg{flex-shrink:0}main.svelte-1n46o8q{grid-column:2;grid-row:1;min-width:0;min-height:0;overflow:auto;display:flex;flex-direction:column;background:var(--bg);color:var(--text)}.logs-slot.svelte-1n46o8q{grid-column:2;grid-row:2;min-width:0}.statusbar.svelte-1n46o8q{grid-column:1 / -1;grid-row:3;min-height:40px;display:flex;align-items:center;gap:24px;border-top:1px solid var(--chrome-border);color:var(--chrome-muted);font-size:var(--text-small)}.runtime-label.svelte-1n46o8q{width:var(--sidebar-width);align-self:stretch;display:flex;align-items:center;flex-shrink:0;padding:0 20px;border-right:1px solid var(--chrome-border)}.collapsed.svelte-1n46o8q .runtime-label:where(.svelte-1n46o8q){width:64px;padding:0 8px;font-size:11px}.panel-controls.svelte-1n46o8q{display:flex;align-items:center;gap:8px;margin-left:auto;margin-right:16px}.statusbar.svelte-1n46o8q .logs-toggle:where(.svelte-1n46o8q){min-height:30px;color:var(--chrome-muted);border:0;background:transparent;text-decoration:underline;text-underline-offset:4px}.statusbar.svelte-1n46o8q .logs-toggle:where(.svelte-1n46o8q):hover,.statusbar.svelte-1n46o8q .logs-toggle[aria-expanded=true]:where(.svelte-1n46o8q){background:transparent;color:var(--chrome-text);text-decoration-thickness:2px}.connection.svelte-1n46o8q{display:flex;align-items:center;gap:14px}.connection.svelte-1n46o8q i:where(.svelte-1n46o8q){display:block;width:7px;height:7px;border-radius:50%;background:var(--muted)}.connection.connected.svelte-1n46o8q i:where(.svelte-1n46o8q){background:var(--orange)}.port-status.svelte-1n46o8q{padding-left:30px;border-left:1px solid var(--chrome-border)}.catalog-error.svelte-1n46o8q{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 24px;color:var(--err);background:var(--bg-2)}h2.svelte-1n46o8q{font:500 var(--text-section)/1.4 var(--sans)}.all-service-grid.svelte-1n46o8q{display:grid;margin-top:14px}.all-service-card.svelte-1n46o8q{display:grid;justify-content:stretch;min-width:0;padding:18px 16px;gap:6px;text-align:left;white-space:normal;background:transparent;border:0;border-bottom:1px solid var(--border);border-radius:0}.all-service-card.svelte-1n46o8q:hover{background:var(--bg-3)}.service-heading.svelte-1n46o8q strong:where(.svelte-1n46o8q){font:500 var(--text-label)/1.4 var(--sans)}.service-heading.svelte-1n46o8q{display:flex;flex-wrap:wrap;align-items:center;gap:8px}.service-status.svelte-1n46o8q{margin-left:auto;color:var(--muted);font:var(--text-small)/1.4 var(--sans);text-transform:none}.project-name.svelte-1n46o8q{color:var(--muted);font-size:var(--text-small)}.empty-state.svelte-1n46o8q{width:100%;padding:48px 32px;text-align:center;color:var(--muted)}.load-state.svelte-1n46o8q{display:block;color:var(--muted)}.empty-state.svelte-1n46o8q h2:where(.svelte-1n46o8q),.load-state.svelte-1n46o8q h1:where(.svelte-1n46o8q){color:var(--text)}.global-settings.svelte-1n46o8q{font-size:var(--text-body);line-height:1.8}.global-settings.svelte-1n46o8q h3:where(.svelte-1n46o8q){margin-top:40px;font:500 var(--text-section)/1.4 var(--sans)}.global-settings.svelte-1n46o8q label:where(.svelte-1n46o8q){display:flex;gap:12px;align-items:center}.forwarder-error.svelte-1n46o8q{color:var(--err)}.collapsed.svelte-1n46o8q{grid-template-columns:64px minmax(0,1fr)}.app-rail.svelte-1n46o8q .collapse-toggle:where(.svelte-1n46o8q){width:36px;min-height:44px;flex-shrink:0;padding:4px;border:0;justify-content:center}.collapsed.svelte-1n46o8q .brand:where(.svelte-1n46o8q){flex-direction:column;gap:12px;padding:16px 4px}.collapsed.svelte-1n46o8q nav:where(.svelte-1n46o8q) a:where(.svelte-1n46o8q){justify-content:center;padding:12px 0}.collapsed.svelte-1n46o8q nav:where(.svelte-1n46o8q) a:where(.svelte-1n46o8q) span:where(.svelte-1n46o8q){display:none}.palette-trigger.svelte-1n46o8q span:where(.svelte-1n46o8q){min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.palette-trigger.svelte-1n46o8q kbd:where(.svelte-1n46o8q){margin-left:auto;flex-shrink:0;font:11px var(--mono)}.collapsed.svelte-1n46o8q .palette-trigger:where(.svelte-1n46o8q){justify-content:center;padding:12px 0}.collapsed.svelte-1n46o8q .palette-trigger:where(.svelte-1n46o8q) span:where(.svelte-1n46o8q),.collapsed.svelte-1n46o8q .palette-trigger:where(.svelte-1n46o8q) kbd:where(.svelte-1n46o8q){display:none}.app-rail.svelte-1n46o8q .clean-urls-warning:where(.svelte-1n46o8q){margin-top:auto;border:0;border-top:1px solid var(--chrome-border);padding:16px 20px;color:#d1b78d;flex-shrink:0;justify-content:flex-start;white-space:normal}.app-rail.svelte-1n46o8q .clean-urls-warning:where(.svelte-1n46o8q):hover{color:#ead5ac;background:#ffffff0c;text-decoration:none}.clean-urls-warning.svelte-1n46o8q strong:where(.svelte-1n46o8q),.clean-urls-warning.svelte-1n46o8q small:where(.svelte-1n46o8q){display:block}.clean-urls-warning.svelte-1n46o8q strong:where(.svelte-1n46o8q){font-size:var(--text-small);font-weight:500}.clean-urls-warning.svelte-1n46o8q small:where(.svelte-1n46o8q){color:var(--chrome-muted);font-size:var(--text-small)}.collapsed.svelte-1n46o8q .clean-urls-warning:where(.svelte-1n46o8q){justify-content:center;padding:16px 0}.collapsed.svelte-1n46o8q .clean-urls-warning:where(.svelte-1n46o8q) span:where(.svelte-1n46o8q){display:none}.project-shortcuts.svelte-1n46o8q{overflow:auto;padding:24px 8px}.project-shortcuts.svelte-1n46o8q p:where(.svelte-1n46o8q){padding:0 12px;color:var(--chrome-muted);font:var(--text-small)/1.4 var(--sans);text-transform:none}.project-shortcuts.svelte-1n46o8q button:where(.svelte-1n46o8q){text-transform:none;overflow:hidden;text-overflow:ellipsis;display:block;min-height:36px;padding:8px 12px}.project-shortcuts.svelte-1n46o8q button.current:where(.svelte-1n46o8q){color:var(--accent);background:var(--selected)}.sidebar-resizer.svelte-1n46o8q{position:absolute;right:-3px;top:0;bottom:0;width:7px;cursor:col-resize;touch-action:none;z-index:10}.sidebar-resizer.svelte-1n46o8q:hover,.sidebar-resizer.svelte-1n46o8q:focus-visible{background:var(--orange)}.all-search.svelte-1n46o8q{display:flex;align-items:center;gap:16px;margin-top:24px;color:var(--muted)}.all-search.svelte-1n46o8q input:where(.svelte-1n46o8q){width:min(360px,100%)}@media(max-width:760px){.layout.svelte-1n46o8q,.layout.collapsed.svelte-1n46o8q{grid-template-columns:64px minmax(0,1fr)}.layout.svelte-1n46o8q:not(.collapsed) .app-rail:where(.svelte-1n46o8q){position:absolute;inset:0 auto 0 0;width:min(var(--sidebar-width),calc(100vw - 64px));z-index:20;background:var(--chrome)}.sidebar-resizer.svelte-1n46o8q{display:none}.statusbar.svelte-1n46o8q{gap:10px;font-size:11px}.runtime-label.svelte-1n46o8q{width:64px;padding:0 8px;font-size:11px}.panel-controls.svelte-1n46o8q{gap:0;margin-right:8px}.statusbar.svelte-1n46o8q .logs-toggle:where(.svelte-1n46o8q){padding:4px 8px}.port-status.svelte-1n46o8q{padding-left:10px}.connection.svelte-1n46o8q{gap:6px}.connection.svelte-1n46o8q i:where(.svelte-1n46o8q){width:6px;height:6px}.all-search.svelte-1n46o8q{align-items:stretch;flex-direction:column;gap:6px}}