wicked-studio 0.4.13 → 0.4.15

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/README.md CHANGED
@@ -2,166 +2,163 @@
2
2
 
3
3
  > [![npm](https://img.shields.io/npm/v/wicked-studio)](https://www.npmjs.com/package/wicked-studio) · [![CI](https://github.com/mikeparcewski/wicked-studio/actions/workflows/ci.yml/badge.svg)](https://github.com/mikeparcewski/wicked-studio/actions/workflows/ci.yml) · [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
4
4
 
5
- **The coder-facing skin of the wicked experience plane.** A React SPA that is a *pure HTTP/WS
6
- client* of the [wicked-crew](https://github.com/mikeparcewski/wicked-crew) daemon: launch and
7
- steer governed agent runs, answer human gates, watch live CoreEvent streams, browse projects,
8
- repo intelligence, evidence, coverage, and the decisions ledger everything the daemon exposes
9
- on `/api/v1` and `/ws`, and nothing else.
10
-
11
- ## What the skin surfaces (0.4.x)
12
-
13
- Every capability below is a real `/api/v1` or `/ws` wire — no invented routes — verified by a
14
- 21-scenario functional campaign against an isolated daemon (21/21 PASS, evidence-graded;
15
- `estate-review/STUDIO-CAMPAIGN.md`). Legs the campaign could only prove over the wire rather
16
- than through the UI are marked as such below.
17
-
18
- - **Projects** create/rename/archive/restore, attach and detach members (repos, runs, chats,
19
- docs), a merged activity feed with a prompt inbox, a per-project dashboard, and a four-mode
20
- project shell (chat / build / document / video) with deep-linkable routes (`/p/:id/…`).
21
- - **Repo intelligence** register a local path or clone from a URL; either launches a governed
22
- onboarding run (`index` `annotate`, two tool units) that builds the repo's code graph. Then:
23
- graph view with ego-focus navigation, **blast radius** for any symbol, hotspots, the domain
24
- graph + coverage view, and a requirements browser with operator overrides (PATCH
25
- title/notes/status/risk).
26
- - **Governed runs** the composer (Ask / Balanced / Autonomous, seat selection, repo binding,
27
- PR delivery), run list/detail/timeline with event backfill on reload, **HITL steering gates**
28
- (approve / approve-with-steer / reject, plus keyboard batch triage), elicitation prompts,
29
- durable pre-gate guidance notes, and the lifecycle verbs the UI wires today: cancel, inject
30
- a message, unarchive, retry lineage. (Resume and archive exist as typed client wires,
31
- campaign-verified over the API — the UI affordances are a filed gap, not yet shipped.)
32
- - **Evidence** — per-unit transcripts, the worktree file & diff viewer, and one-click
33
- **evidence bundle download** for any run. The skin surfaces the gates; it never grades.
34
- - **Group chat** fan one question out to your whole warm CLI roster and watch each seat
35
- answer side by side.
36
- - **Governed PTY terminals** — real terminals (xterm over `/ws/terminals/:id`), including the
37
- seat sign-in flow from settings.
38
- - **Workflow builder** — inspect and create WorkflowDefs (phases, gates, validation) and their
39
- inline tool scripts, then launch runs against them.
40
- - **Governance** policies, conformance rules (with facet preview), the decisions/claims
41
- ledger, and the audit view.
42
- - **Settings** daemon settings plus `studio.*` namespaced keys: appearance/theme (including
43
- brand-learn), notifications, composer preferences.
44
- - **Document & Video modes** — the merged creator surface, riding crew's proxied interactive
45
- bridge under `/api/v1/projects/:id/interactive/*`.
46
- - **Command palette + deep links** Cmd+K verbs (open terminal, answer prompts), bookmarkable
47
- routes throughout, desktop gate notifications.
5
+ **The cockpit for AI coding agents you can actually trust.** wicked-studio is a browser UI for
6
+ running coding-agent CLIs (Claude Code, Codex, Antigravity, and more) as *governed* workers:
7
+ you give an intent, the agents do the work behind verification gates, and you approve the
8
+ decisions that matter with the evidence behind every "done" one click away.
9
+
10
+ It's the human surface of the [wicked](https://github.com/mikeparcewski/wicked-crew) platform.
11
+ The agents run headless in the background; studio is where you point them at your repos, watch
12
+ them work in real time, unblock them when they need a human, and see what actually happened.
13
+
14
+ ---
15
+
16
+ ## Why you'd want it
17
+
18
+ Coding agents are fast but unsupervised they assert "done," grade their own work, and bury the
19
+ reasoning in a scrollback you'll never read. wicked-studio flips that:
20
+
21
+ - **Direct, don't babysit.** Launch runs across many repos and projects at once, then let them
22
+ work. Attention comes to *you* when a run hits a gate — you don't sit watching one terminal.
23
+ - **Approve what matters.** Human-in-the-loop gates surface the real decisions (approve, approve
24
+ with a steer, or reject) with keyboard batch triage when several pile up.
25
+ - **"Done" is proven, not claimed.** The evaluator is never the creator. Every run leaves
26
+ transcripts, diffs, and a downloadable evidence bundle; studio shows you the gate outcomes, it
27
+ never grades the work itself.
28
+ - **Understand the code first.** Onboard a repo and studio builds its graph — then blast-radius
29
+ for any symbol, hotspots, the domain/requirements view, and a searchable map of what calls what.
30
+
31
+ ## What you can do
32
+
33
+ - **Run governed agents on your repos** register a local path or clone a URL; studio builds the
34
+ code graph, then you launch runs (ask / balanced / autonomous), pick which agent seats join, and
35
+ bind a repo with optional PR delivery.
36
+ - **Steer runs live** — a real-time timeline of every run, human gates with approve / steer /
37
+ reject, elicitation prompts, pre-gate guidance notes, and lifecycle controls (cancel, inject a
38
+ message, retry).
39
+ - **See the evidence** — per-step transcripts, a worktree file + diff viewer, and one-click
40
+ evidence-bundle download for any run.
41
+ - **Explore your codebase** — graph view with focus navigation, blast radius, hotspots, and the
42
+ domain graph with coverage.
43
+ - **Ask your whole model roster at once** — fan one question out to every warm CLI and compare the
44
+ answers side by side.
45
+ - **Govern the work** — author steering rules and policies, browse the decisions ledger, and review
46
+ what the platform has learned about your repos.
47
+ - **Work in projects** — group repos, runs, chats, and docs; a merged activity feed and dashboard
48
+ per project; deep-linkable routes throughout.
49
+ - **Plus** governed terminals, a Cmd+K command palette, document & video creation modes, and
50
+ desktop notifications when a run needs you.
51
+
52
+ ---
53
+
54
+ ## Get started
55
+
56
+ Studio ships **inside** wicked-crew — one command gives you the API, the engine, and this UI on a
57
+ single port:
48
58
 
59
+ ```sh
60
+ npx wicked-crew serve
61
+ # then open the URL it prints (default http://127.0.0.1:7701)
49
62
  ```
50
- ┌─────────────────────┐ HTTP /api/v1 + WS /ws ┌──────────────────────┐
51
- │ wicked-studio ───────────────────────────────────────▶ │ wicked-crew daemon │
52
- │ (this repo, SPA) │ ◀─────────────────────────────────────── │ (control plane:
53
- │ the skin │ wire contract: wicked-crew-api-types │ API/engine/gates) │
54
- └─────────────────────┘ └──────────────────────┘
63
+
64
+ That's the whole install for most people — no separate studio setup. Prefer a guided setup, or
65
+ want the rest of the wicked family too? Use the installer:
66
+
67
+ ```sh
68
+ npx wicked-installer
55
69
  ```
56
70
 
57
- ## The division of labor
71
+ It installs and wires wicked-crew (which serves this UI) alongside the other wicked-\* tools,
72
+ across whichever coding-agent CLIs you already use.
58
73
 
59
- - **wicked-crew is the control plane** — the daemon, the `/api/v1` REST surface, the `/ws`
60
- event stream, the wicked-core engine underneath, the gates and the evidence. It is fully
61
- functional headless.
62
- - **wicked-studio is the skin** — a client of that control plane, developed, versioned, and
63
- released as its own product. It imports **zero** crew source; the only thing the two share is
64
- the published wire contract, [`wicked-crew-api-types`](https://github.com/mikeparcewski/wicked-crew/tree/main/packages/crew-api-types).
65
- - **Crew still ships a default skin.** wicked-crew's release build (`build:with-studio`) copies
66
- this package's built `dist/` into the daemon's serving tree, so `npx wicked-crew serve` keeps
67
- the one-command local UX — UI and API same-origin on one port. The dependency direction is
68
- *control-plane-ships-a-dist-artifact*: crew depends on studio's build output, never on its
69
- source; studio depends on crew's wire contract, never on its internals.
74
+ ## Keeping it up to date
70
75
 
71
- ## Pairing with a daemon
76
+ Studio rides along with crew, so you update it by updating crew:
72
77
 
73
- The connection surface is deliberately small (`src/api/client.ts`):
78
+ ```sh
79
+ npm i -g wicked-crew@latest # or: npx wicked-installer (updates the whole family)
80
+ ```
74
81
 
75
- | Mode | How the SPA finds the daemon |
76
- |---|---|
77
- | **Bundled / same-origin** (production) | `window.location.origin` — whatever origin the daemon serves the SPA from is where the SPA calls back to. `--port` / `CREW_PORT` just work; no host is baked into the bundle. |
78
- | **Split dev or standalone** | `VITE_API_HOST` (host:port, no scheme), baked at build time by Vite. `.env.development` sets `127.0.0.1:7701` — the crew daemon's default — for the `npm run dev` server on :4200. |
82
+ Each wicked-crew release bundles the matching studio build, so a fresh crew is a fresh UI. To see
83
+ what changed, check the [releases](https://github.com/mikeparcewski/wicked-crew/releases).
79
84
 
80
- The daemon's loopback CORS admits any `http://localhost:*` / `http://127.0.0.1:*` origin, so a
81
- standalone studio on its own port can drive a local daemon out of the box.
85
+ ## Requirements
82
86
 
83
- ## Install
87
+ - **Node.js ≥ 22**, npm ≥ 10
88
+ - A running **wicked-crew daemon, v0.7.0+** (bundled and started for you by `npx wicked-crew serve`
89
+ — you only need this floor if you point a standalone studio at your own daemon)
90
+ - A modern browser — Chrome, Edge, or Firefox on macOS, Linux, or Windows (or Safari on macOS)
84
91
 
85
- You rarely install studio directly: **`npx wicked-crew serve` ships this UI bundled**,
86
- same-origin on one port. Or use the family installer — [`npx wicked-installer`](https://www.npmjs.com/package/wicked-installer)
87
- installs/updates the whole wicked-\* family (wicked-crew, which serves this skin, included).
88
- For a studio you build and host yourself, see [Standalone build](#standalone-build).
92
+ ---
89
93
 
90
- ## Develop
94
+ ## For developers
91
95
 
92
- ```sh
93
- # a running control plane (defaults to 127.0.0.1:7701)
94
- npx wicked-crew serve
96
+ Studio is a Vite/React SPA and a *pure HTTP/WS client* of the wicked-crew daemon — it talks only to
97
+ crew's published `/api/v1` REST surface and `/ws` event stream, and imports **zero** crew source.
98
+ The one thing the two share is the wire-contract package
99
+ [`wicked-crew-api-types`](https://github.com/mikeparcewski/wicked-crew/tree/main/packages/crew-api-types).
100
+
101
+ ```
102
+ ┌─────────────────┐ HTTP /api/v1 + WS /ws ┌────────────────────┐
103
+ │ wicked-studio │ ───────────────────────────▶ │ wicked-crew daemon │
104
+ │ (React SPA) │ ◀─────────────────────────── │ API · engine · │
105
+ │ │ contract: wicked-crew-api-types │ gates · evidence │
106
+ └─────────────────┘ └────────────────────┘
107
+ ```
108
+
109
+ ### Develop
95
110
 
96
- # then, in this repo
111
+ ```sh
112
+ npx wicked-crew serve # a control plane on :7701 for the SPA to talk to
97
113
  npm install
98
- npm run dev # vite on http://127.0.0.1:4200, pointed at :7701 via .env.development
114
+ npm run dev # vite on http://127.0.0.1:4200, pointed at :7701
99
115
  ```
100
116
 
101
117
  `npm test` (vitest + testing-library), `npm run typecheck`, `npm run lint`, `npm run build`
102
- (tsc + vite → `dist/`). CI runs all four on every PR.
118
+ (tsc + vite → `dist/`). CI runs all four on ubuntu / macos / windows for every PR.
119
+
120
+ ### Standalone build
103
121
 
104
- ## Standalone build
122
+ You can build studio and host it yourself, pointed at any reachable daemon:
105
123
 
106
124
  ```sh
107
125
  VITE_API_HOST=127.0.0.1:7701 npm run build
108
- # serve dist/ from ANY static server (SPA fallback to index.html), e.g.:
109
- npx serve dist # or python -m http.server -d dist
126
+ npx serve dist # any static server with SPA fallback works
110
127
  ```
111
128
 
112
- `e2e/studio_standalone_test.py` is the scripted proof of this mode: it builds the SPA, serves
113
- `dist/` from a plain static server on its own port, points it at a live daemon, and drives a
114
- real flow (list runs open a run approve a human gate → watch CoreEvents over WS) with a
115
- real browser. See the header of that file for prerequisites and knobs.
116
-
117
- ## Releasing / how crew consumes this
118
-
119
- The npm package ships `dist/` only (`files: ["dist"]`). wicked-crew declares `wicked-studio` as
120
- a devDependency and its `build:with-studio` copies `node_modules/wicked-studio/dist` into
121
- `packages/crew/dist/studio`, which the daemon serves same-origin (headless fallback when
122
- absent). Installs from git get a fresh `dist/` via the `prepare` hook
123
- (`scripts/prepare-dist.mjs`); publishers run `npm run build && npm publish` so the tarball is
124
- built from the tagged source.
125
-
126
- ### The data-testid contract (`testid-inventory.json`)
127
-
128
- `testid-inventory.json` (repo root, committed; emitted into `dist/testid-inventory.json` by the
129
- build) is the machine-readable inventory of every `data-testid` the UI declares — the selector
130
- contract that test generators and the model-free campaign runner build against, versioned with
131
- this package. `tests/testidInventory.test.ts` re-scans `src/` and fails CI on any drift, so a
132
- testid change (or a `package.json` version bump — the artifact carries `studioVersion`) ships
133
- only together with a reviewed `npm run manifest:testids` regeneration. The drift-handling
134
- doctrine downstream is embedded in the file's `$doc` header: a selector miss fails the
135
- deterministic run; the authoring agent re-authors against the live DOM; the runner re-records;
136
- the substitution lands in the spec diff. No agentic fallback inside the runner.
137
-
138
- ## Provenance
139
-
140
- Extracted from the wicked-crew monorepo (`packages/studio`) as its own product — the carve kept
141
- the code as-is and preserved the package's full in-monorepo history via `git subtree split`
142
- (92 commits). An earlier, pre-consolidation incarnation of this product is archived read-only at
143
- [wicked-studio-archived](https://github.com/mikeparcewski/wicked-studio-archived).
129
+ The SPA finds its daemon two ways: **bundled/same-origin** (production) calls back to
130
+ `window.location.origin`, so `--port` / `CREW_PORT` just work with no host baked in; **standalone**
131
+ uses `VITE_API_HOST` (host:port, no scheme) fixed at build time. The daemon's loopback CORS admits
132
+ any `localhost` / `127.0.0.1` origin, so a standalone studio drives a local daemon out of the box.
133
+ `e2e/studio_standalone_test.py` is the scripted proof of this mode.
144
134
 
145
- ## Requirements
135
+ ### How crew ships this UI
136
+
137
+ The npm package publishes `dist/` only. wicked-crew declares `wicked-studio` as a devDependency and
138
+ its `build:with-studio` step copies `node_modules/wicked-studio/dist` into the daemon's serving
139
+ tree, so `npx wicked-crew serve` is same-origin UI + API on one port (with a headless fallback when
140
+ the dist is absent). A studio release therefore also bumps crew's devDep pin.
146
141
 
147
- - Node.js 22.0.0
148
- - npm 10 (for workspaces and `prepare` hooks)
149
- - A running [wicked-crew](https://github.com/mikeparcewski/wicked-crew) daemon (**v0.7.0+**) for
150
- the SPA to connect to. The floor is real, not ceremonial: the UI calls routes that first
151
- shipped in crew 0.7.0 — `PUT /runs/:id/guidance` (the durable pre-gate note) exists only
152
- there, and the projects surface, `/audit`, and run archiving need ≥ 0.6.0 — so an older
153
- daemon 404s on surfaces the skin treats as present.
154
- - A modern browser (Chrome, Edge, Firefox, Safari)
155
- - macOS, Linux, or Windows
142
+ The repo also carries a `data-testid` selector contract (`testid-inventory.json`, regenerated with
143
+ `npm run manifest:testids` and drift-checked in CI) that the test generators build against — see
144
+ [`CLAUDE.md`](./CLAUDE.md) for the full contributor doctrine.
156
145
 
157
- ## Contributing
146
+ ### Contributing
158
147
 
159
- 1. Fork the repo and create a feature branch.
148
+ 1. Fork and branch.
160
149
  2. `npm install && npm run dev` — SPA on `:4200`, daemon on `:7701`.
161
150
  3. `npm test && npm run typecheck && npm run lint` before committing.
162
151
  4. Open a PR; CI runs all four gates on ubuntu / macos / windows.
163
152
 
164
- The only external coupling is the wire contract (`wicked-crew-api-types`). Studio imports **zero** crew source — all crew interaction goes through `/api/v1` and `/ws`. Keep it that way.
153
+ Keep the wire-contract boundary intact: all crew interaction goes through `/api/v1` and `/ws`, never
154
+ a crew-source import — if a type is missing, it lands in `wicked-crew-api-types` first.
155
+
156
+ ### Provenance
157
+
158
+ Studio was extracted from the wicked-crew monorepo (`packages/studio`) as its own product,
159
+ preserving the full in-monorepo history via `git subtree split`. An earlier, pre-consolidation
160
+ incarnation is archived read-only at
161
+ [wicked-studio-archived](https://github.com/mikeparcewski/wicked-studio-archived).
165
162
 
166
163
  ## License
167
164
 
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Copyright (c) 2014 The xterm.js authors. All rights reserved.
3
+ * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
4
+ * https://github.com/chjj/term.js
5
+ * @license MIT
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in
15
+ * all copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ * THE SOFTWARE.
24
+ *
25
+ * Originally forked from (with the author's permission):
26
+ * Fabrice Bellard's javascript vt100 for jslinux:
27
+ * http://bellard.org/jslinux/
28
+ * Copyright (c) 2011 Fabrice Bellard
29
+ * The original design remains. The terminal itself
30
+ * has been extended to include xterm CSI codes, among
31
+ * other features.
32
+ */.xterm{cursor:text;position:relative;-moz-user-select:none;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::-moz-selection{color:transparent}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{-webkit-user-select:text;-moz-user-select:text;user-select:text;white-space:pre}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{-webkit-text-decoration:double underline;text-decoration:double underline}.xterm-underline-3{-webkit-text-decoration:wavy underline;text-decoration:wavy underline}.xterm-underline-4{-webkit-text-decoration:dotted underline;text-decoration:dotted underline}.xterm-underline-5{-webkit-text-decoration:dashed underline;text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{-webkit-text-decoration:overline double underline;text-decoration:overline double underline}.xterm-overline.xterm-underline-3{-webkit-text-decoration:overline wavy underline;text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{-webkit-text-decoration:overline dotted underline;text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{-webkit-text-decoration:overline dashed underline;text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}:root{--_surface-0: #09090f;--_surface-1: #11111a;--_surface-2: #1a1a26;--_surface-3: #242433;--_surface-4: #2e2e40;--surface-base: var(--_surface-0);--surface-rail: var(--_surface-1);--surface-card: var(--_surface-2);--surface-raised: var(--_surface-3);--surface-overlay: var(--_surface-4);--_ink-a35: rgba(255, 255, 255, .35);--_ink-a55: rgba(255, 255, 255, .55);--_ink-a80: rgba(255, 255, 255, .8);--_ink-100: #ffffff;--ink-dim: var(--_ink-a35);--ink-muted: var(--_ink-a55);--ink-body: var(--_ink-a80);--ink-high: var(--_ink-100);--_accent-h: 258;--_accent-s: 72%;--_accent-l: 62%;--accent: hsl(var(--_accent-h) var(--_accent-s) var(--_accent-l));--accent-dim: hsl(var(--_accent-h) var(--_accent-s) calc(var(--_accent-l) - 18%));--accent-subtle: hsl(var(--_accent-h) calc(var(--_accent-s) * .35) calc(var(--_accent-l) - 30%));--accent-fg: var(--ink-high);--_sg-h: 45;--_sf-h: 4;--_sr-h: 148;--status-gate: hsl(var(--_sg-h) 90% 68%);--status-gate-dim: hsl(var(--_sg-h) 55% 22%);--status-fail: hsl(var(--_sf-h) 88% 62%);--status-fail-dim: hsl(var(--_sf-h) 45% 18%);--status-run: hsl(var(--_sr-h) 58% 58%);--status-run-dim: hsl(var(--_sr-h) 38% 16%);--status-done: var(--_ink-a35);--status-done-dim: transparent;--space-1: 4px;--space-2: 8px;--space-3: 12px;--space-4: 16px;--space-5: 20px;--space-6: 24px;--space-8: 32px;--space-10: 40px;--space-12: 48px;--space-16: 64px;--font-sans: "Inter", system-ui, -apple-system, sans-serif;--font-mono: "JetBrains Mono", "Fira Code", ui-monospace, monospace;--text-2xs: 10px;--text-xs: 11px;--text-sm: 13px;--text-md: 15px;--text-lg: 18px;--text-xl: 22px;--text-2xl: 28px;--weight-normal: 400;--weight-medium: 500;--weight-semi: 600;--weight-bold: 700;--leading-tight: 1.2;--leading-body: 1.5;--leading-loose: 1.75;--radius-sm: 4px;--radius-md: 8px;--radius-lg: 12px;--radius-xl: 16px;--radius-full: 9999px;--shadow-card: 0 1px 3px rgba(0,0,0,.5), 0 0 0 1px rgba(255,255,255,.05);--shadow-raised: 0 4px 12px rgba(0,0,0,.6), 0 0 0 1px rgba(255,255,255,.08);--shadow-overlay: 0 8px 24px rgba(0,0,0,.7), 0 0 0 1px rgba(255,255,255,.1);--scrim: rgba(0, 0, 0, .6);--ease-out: cubic-bezier(.16, 1, .3, 1);--ease-spring: cubic-bezier(.34, 1.56, .64, 1);--ease-in-out: cubic-bezier(.4, 0, .2, 1);--dur-instant: 80ms;--dur-fast: .12s;--dur-base: .22s;--dur-slow: .3s;--dur-slower: .38s}[data-theme=light]{--_surface-0: #f4f4f8;--_surface-1: #eeeef4;--_surface-2: #e5e5ef;--_surface-3: #d8d8e8;--_surface-4: #ccccdc;--_ink-a35: rgba(0, 0, 0, .3);--_ink-a55: rgba(0, 0, 0, .52);--_ink-a80: rgba(0, 0, 0, .78);--_ink-100: #080810;--status-gate-dim: hsl(var(--_sg-h) 80% 88%);--status-fail-dim: hsl(var(--_sf-h) 75% 91%);--status-run-dim: hsl(var(--_sr-h) 55% 88%)}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.container{width:100%}@media(min-width:640px){.container{max-width:640px}}@media(min-width:768px){.container{max-width:768px}}@media(min-width:1024px){.container{max-width:1024px}}@media(min-width:1280px){.container{max-width:1280px}}@media(min-width:1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.inset-y-0{top:0;bottom:0}.bottom-0{bottom:0}.bottom-full{bottom:100%}.left-0{left:0}.right-0{right:0}.right-1{right:.25rem}.right-1\.5{right:.375rem}.right-4{right:1rem}.top-1{top:.25rem}.top-1\.5{top:.375rem}.top-6{top:1.5rem}.top-8{top:2rem}.top-full{top:100%}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.m-0{margin:0}.m-4{margin:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.mb-0\.5{margin-bottom:.125rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-0\.5{margin-left:.125rem}.ml-1{margin-left:.25rem}.ml-1\.5{margin-left:.375rem}.ml-2{margin-left:.5rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-2{margin-top:.5rem}.mt-2\.5{margin-top:.625rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-8{margin-top:2rem}.mt-auto{margin-top:auto}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.block{display:block}.inline-block{display:inline-block}.\!inline{display:inline!important}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.\!hidden{display:none!important}.hidden{display:none}.h-1{height:.25rem}.h-1\.5{height:.375rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-56{height:14rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-7{height:1.75rem}.h-72{height:18rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-\[80vh\]{height:80vh}.h-\[92vh\]{height:92vh}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-36{max-height:9rem}.max-h-48{max-height:12rem}.max-h-56{max-height:14rem}.max-h-64{max-height:16rem}.max-h-72{max-height:18rem}.max-h-96{max-height:24rem}.max-h-\[28rem\]{max-height:28rem}.max-h-\[60\%\]{max-height:60%}.max-h-\[60vh\]{max-height:60vh}.max-h-\[86vh\]{max-height:86vh}.min-h-0{min-height:0px}.min-h-\[3\.5rem\]{min-height:3.5rem}.min-h-\[3rem\]{min-height:3rem}.min-h-\[4rem\]{min-height:4rem}.w-1{width:.25rem}.w-1\.5{width:.375rem}.w-10{width:2.5rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-16{width:4rem}.w-2{width:.5rem}.w-2\.5{width:.625rem}.w-20{width:5rem}.w-24{width:6rem}.w-28{width:7rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-40{width:10rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-52{width:13rem}.w-56{width:14rem}.w-6{width:1.5rem}.w-60{width:15rem}.w-64{width:16rem}.w-7{width:1.75rem}.w-72{width:18rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-96{width:24rem}.w-\[26rem\]{width:26rem}.w-\[280px\]{width:280px}.w-\[28rem\]{width:28rem}.w-\[34rem\]{width:34rem}.w-\[380px\]{width:380px}.w-\[420px\]{width:420px}.w-\[90vw\]{width:90vw}.w-\[92vw\]{width:92vw}.w-full{width:100%}.w-px{width:1px}.min-w-0{min-width:0px}.min-w-64{min-width:16rem}.min-w-\[10rem\]{min-width:10rem}.min-w-\[12rem\]{min-width:12rem}.min-w-\[14rem\]{min-width:14rem}.min-w-\[16rem\]{min-width:16rem}.min-w-\[3\.5rem\]{min-width:3.5rem}.min-w-\[4rem\]{min-width:4rem}.min-w-\[60px\]{min-width:60px}.min-w-\[8rem\]{min-width:8rem}.min-w-max{min-width:-moz-max-content;min-width:max-content}.max-w-2xl{max-width:42rem}.max-w-3xl{max-width:48rem}.max-w-5xl{max-width:64rem}.max-w-\[14rem\]{max-width:14rem}.max-w-\[70\%\]{max-width:70%}.max-w-\[72\%\]{max-width:72%}.max-w-\[80\%\]{max-width:80%}.max-w-\[80px\]{max-width:80px}.max-w-\[85\%\]{max-width:85%}.max-w-\[90\%\]{max-width:90%}.max-w-\[92vw\]{max-width:92vw}.max-w-full{max-width:100%}.max-w-md{max-width:28rem}.max-w-sm{max-width:24rem}.max-w-xl{max-width:36rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.table-fixed{table-layout:fixed}.border-collapse{border-collapse:collapse}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.cursor-grab{cursor:grab}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.resize-y{resize:vertical}.resize{resize:both}.list-inside{list-style-position:inside}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.list-none{list-style-type:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.gap-x-1\.5{-moz-column-gap:.375rem;column-gap:.375rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.gap-x-8{-moz-column-gap:2rem;column-gap:2rem}.gap-y-0\.5{row-gap:.125rem}.gap-y-1\.5{row-gap:.375rem}.gap-y-4{row-gap:1rem}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.self-start{align-self:flex-start}.self-end{align-self:flex-end}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre{white-space:pre}.whitespace-pre-wrap{white-space:pre-wrap}.text-wrap{text-wrap:wrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-0{border-width:0px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-t{border-top-width:1px}.bg-surface-base{background-color:var(--surface-base)}.bg-surface-raised{background-color:var(--surface-raised)}.bg-transparent{background-color:transparent}.p-0{padding:0}.p-0\.5{padding:.125rem}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-10{padding:2.5rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-3\.5{padding:.875rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-0\.5{padding-left:.125rem;padding-right:.125rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-3\.5{padding-left:.875rem;padding-right:.875rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-24{padding-top:6rem;padding-bottom:6rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-3\.5{padding-top:.875rem;padding-bottom:.875rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-px{padding-top:1px;padding-bottom:1px}.pb-0\.5{padding-bottom:.125rem}.pb-1{padding-bottom:.25rem}.pb-1\.5{padding-bottom:.375rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pb-4{padding-bottom:1rem}.pb-8{padding-bottom:2rem}.pl-0{padding-left:0}.pl-1{padding-left:.25rem}.pl-3{padding-left:.75rem}.pl-5{padding-left:1.25rem}.pl-8{padding-left:2rem}.pr-1{padding-right:.25rem}.pr-2{padding-right:.5rem}.pr-3{padding-right:.75rem}.pr-4{padding-right:1rem}.pr-5{padding-right:1.25rem}.pt-0\.5{padding-top:.125rem}.pt-1{padding-top:.25rem}.pt-1\.5{padding-top:.375rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.pt-6{padding-top:1.5rem}.pt-8{padding-top:2rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-top{vertical-align:top}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12\.5px\]{font-size:12.5px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-\[9px\]{font-size:9px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-light{font-weight:300}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.capitalize{text-transform:capitalize}.italic{font-style:italic}.ordinal{--tw-ordinal: ordinal;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-5{line-height:1.25rem}.leading-6{line-height:1.5rem}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.leading-snug{line-height:1.375}.leading-tight{line-height:1.25}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.tracking-widest{letter-spacing:.1em}.text-ink-muted{color:var(--ink-muted)}.underline{text-decoration-line:underline}.line-through{text-decoration-line:line-through}.opacity-0{opacity:0}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.ring{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.blur{--tw-blur: blur(8px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-200{transition-duration:.2s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}html,body,#root{background:var(--surface-base);color:var(--ink-body);height:100%;font-family:var(--font-sans);-webkit-font-smoothing:antialiased}code,pre,.font-mono{font-family:var(--font-mono)}@keyframes wk-live-pulse{0%,to{opacity:.5}50%{opacity:1}}.wk-live-edge{position:absolute;left:0;top:0;bottom:0;width:2px;background:var(--status-run);box-shadow:0 0 8px var(--status-run-dim);animation:wk-live-pulse 2s ease-in-out infinite;pointer-events:none}.wk-live-edge--static{animation:none;opacity:1;width:3px}@media(prefers-reduced-motion:reduce){.wk-live-edge{animation:none;opacity:1;width:3px}}.wk-live-edge--gate{width:3px;background:var(--status-gate);box-shadow:0 0 10px var(--status-gate-dim);animation:none;opacity:1}.wk-live-edge--pill{left:3px;top:4px;bottom:4px;width:2px;border-radius:1px;box-shadow:none}@keyframes wk-palette-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}.wk-palette-in{animation:wk-palette-in var(--dur-fast) var(--ease-out)}@media(prefers-reduced-motion:reduce){.wk-palette-in{animation:none}}@keyframes wk-sheet-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}.wk-sheet-in{animation:wk-sheet-in var(--dur-fast) var(--ease-out)}@media(prefers-reduced-motion:reduce){.wk-sheet-in{animation:none}}@keyframes wk-feed-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}.wk-feed-line{animation:wk-feed-in var(--dur-fast) var(--ease-out)}.wk-feed-block{animation:wk-feed-in var(--dur-base) var(--ease-out)}@media(prefers-reduced-motion:reduce){.wk-feed-line,.wk-feed-block{animation:none}}.wk-fade-in{animation:wk-feed-in var(--dur-fast) var(--ease-out)}.wk-disclose{animation:wk-feed-in var(--dur-base) var(--ease-out)}.wk-composer:focus,.wk-composer:focus-within{outline:none;box-shadow:0 0 0 2px var(--accent-dim)}.wk-chip-x{color:var(--ink-dim)}.wk-chip-x:hover{color:var(--ink-high)}@keyframes wk-anchor-flash{0%{background-color:var(--accent-subtle)}to{background-color:transparent}}.wk-anchor-flash{animation:wk-anchor-flash 1s var(--ease-out)}@media(prefers-reduced-motion:reduce){.wk-fade-in,.wk-disclose,.wk-anchor-flash{animation:none}}.wk-river-gate-waiting{animation:wk-live-pulse 2s ease-in-out infinite}@media(prefers-reduced-motion:reduce){.wk-river-gate-waiting{animation:none;opacity:1}}.wk-reject-note::-moz-placeholder{color:var(--ink-dim)}.wk-reject-note::placeholder{color:var(--ink-dim)}.wk-annotate::-moz-placeholder{color:var(--ink-muted)}.wk-annotate::placeholder{color:var(--ink-muted)}.wk-switcher-row:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}.wk-feed-link{color:var(--ink-body);text-decoration:none;display:block}.wk-feed-link:hover{color:var(--ink-high)}.wk-feed-link:after{content:"↗";opacity:0;transition:opacity var(--dur-instant) var(--ease-out);margin-left:4px}.wk-feed-link:hover:after{opacity:1}.skip-link{position:fixed;top:-100px;left:12px;z-index:100;padding:6px 12px;border-radius:var(--radius-md);background:var(--accent);color:var(--accent-fg);font-size:12px;font-weight:600;text-decoration:none;transition:top .1s ease-out}.skip-link:focus{top:12px;outline:2px solid var(--accent-dim);outline-offset:2px}.last\:mb-0:last-child{margin-bottom:0}.last\:border-0:last-child{border-width:0px}.last\:border-b-0:last-child{border-bottom-width:0px}.hover\:bg-\[var\(--surface-raised\)\]:hover{background-color:var(--surface-raised)}.hover\:bg-surface-card:hover{background-color:var(--surface-card)}.hover\:bg-surface-raised:hover{background-color:var(--surface-raised)}.hover\:text-ink-body:hover{color:var(--ink-body)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.hover\:opacity-70:hover{opacity:.7}.hover\:opacity-80:hover{opacity:.8}.hover\:opacity-90:hover{opacity:.9}.focus\:opacity-100:focus{opacity:1}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus-visible\:bg-surface-card:focus-visible{background-color:var(--surface-card)}.focus-visible\:bg-surface-raised:focus-visible{background-color:var(--surface-raised)}.focus-visible\:text-ink-body:focus-visible{color:var(--ink-body)}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:outline:focus-visible{outline-style:solid}.focus-visible\:outline-2:focus-visible{outline-width:2px}.focus-visible\:outline-accent:focus-visible{outline-color:var(--accent)}.focus-visible\:ring-1:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-accent-dim:focus-visible{--tw-ring-color: var(--accent-dim)}.active\:cursor-grabbing:active{cursor:grabbing}.disabled\:cursor-default:disabled{cursor:default}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-30:disabled{opacity:.3}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-60:disabled{opacity:.6}.group:hover .group-hover\:opacity-100{opacity:1}@media(min-width:640px){.sm\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}}@media(min-width:768px){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(min-width:1024px){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}