runcastle 1.3.3 → 1.3.5
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/bin/runcastle.js +2025 -983
- package/drizzle/0035_feature_tickets_ready_lap.sql +1 -0
- package/drizzle/0036_project_drive_instructions.sql +1 -0
- package/drizzle/0037_finding_carry_and_provenance.sql +5 -0
- package/drizzle/0037_project_sandbox_image.sql +1 -0
- package/drizzle/meta/0036_snapshot.json +1128 -0
- package/drizzle/meta/_journal.json +7 -0
- package/index.js +2019 -979
- package/package.json +1 -1
- package/skills/burner/review-ticket.md +33 -13
- package/skills/burner/verify-fixes.md +9 -1
- package/skills/packs/runcastle/skills/prepare/SKILL.md +40 -2
- package/skills/packs/runcastle/skills/revisit/SKILL.md +10 -2
- package/skills/packs/runcastle/skills/tickets/SKILL.md +3 -1
- package/web/assets/index-D697YlOb.css +1 -0
- package/web/assets/index-Vbh17gX3.js +186 -0
- package/web/index.html +2 -2
- package/web/assets/index-5D6uCZUU.css +0 -1
- package/web/assets/index-C2XRT4ng.js +0 -185
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@ You review it in **exactly one of two modes**, and you pick which before you do
|
|
|
11
11
|
|
|
12
12
|
**One mode, never both.** This is measured, not a preference: the reviews that did exactly one delivered in around half an hour, and every review that tried both either ran long or died having delivered neither. Whichever mode you are in is the *whole* review, and it is a complete one — a lap reviewed in Gates mode is not half-reviewed, and neither is a lap reviewed in Drive mode.
|
|
13
13
|
|
|
14
|
-
You leave two deliverables behind: the **findings** (one report per finding, typed) and the **digest** (the lap's
|
|
14
|
+
You leave two deliverables behind: the **findings** (one report per finding, typed) and the **digest** (the lap's account — see step 5; it is not an afterthought). Its first line is a standalone one-liner naming the lap, what landed, the counts and the mode you ran: that line is the one the review page renders on arrival, and the account behind it is what the human opens when they want more.
|
|
15
15
|
|
|
16
16
|
You are **not** implementing anything. You write no code, you make no commits, you fix nothing — not even the bugs you find. Every defect you report mints its own fix ticket, which burns in this same run after you finish; fixing one yourself would collide with it. Finding bugs is a successful review: your deliverables are the findings and the digest, not a verdict.
|
|
17
17
|
|
|
@@ -68,13 +68,20 @@ Both yes → **Drive mode**, step 2a. Anything else → **Gates mode**, step 2b.
|
|
|
68
68
|
|
|
69
69
|
### 2a. Drive mode — walk the app
|
|
70
70
|
|
|
71
|
+
{{DRIVE_INSTRUCTIONS}}
|
|
72
|
+
|
|
71
73
|
**Boot the app.** Call `mcp__runcastle__review_drive({ action: "start" })`. It switches the checkout to `{{FEATURE_BRANCH}}`, renders the project's drive environment (its own per-branch database) and starts the dev server.
|
|
72
74
|
|
|
73
75
|
The URL is **not** ready when `start` returns — the dev server has to print it first. Poll `mcp__runcastle__review_drive({ action: "status" })` until `drive.devUrl` appears, waiting a few seconds between calls. Give it a couple of minutes before you conclude it is never coming.
|
|
74
76
|
|
|
75
|
-
**A refusal
|
|
77
|
+
**A refusal comes back classified — read `retriable` before you decide what to do about it.** There are two of them, and they want opposite things:
|
|
78
|
+
|
|
79
|
+
- **`deniedCode: "slot_held"` (`retriable: true`)** — somebody else holds the machine-wide drive slot: the human's own drive, another review's, or a preparation dry run. It frees itself when they finish, so wait it out. Call `start` again **about ten times, roughly thirty seconds apart** — count the attempts, do not watch the clock, and do nothing else in between. If one of them takes, you are driving; carry on. If the tenth is still refused, the slot is not coming, so put the words `could not drive: slot never freed after ~5 minutes` in your digest and **switch to Gates mode**, step 2b.
|
|
80
|
+
- **`deniedCode: "dirty"` (`retriable: false`)** — the human's own uncommitted files block the checkout switch, and no amount of waiting clears them. Do not call `start` a second time. Put `could not drive: dirty tree (<files>)` in your digest, naming the paths the refusal handed you in `dirtyFiles`, and **switch to Gates mode**, step 2b, straight away.
|
|
81
|
+
|
|
82
|
+
Either way: report an observation saying the drive could not start and which of the two it was, run the step 4 cleanup for whatever you got as far as starting, and spend the whole review in Gates mode. That is a complete review too. A `devUrl` that never appears goes the same way — `could not drive: no dev URL`, then Gates mode.
|
|
76
83
|
|
|
77
|
-
**Never build your own environment to drive in.** When `review_drive` refuses, or never yields a URL, the drive is over — an app you reached some other way is not the app the human runs, so what it shows you is not evidence about their machine. Do not create a worktree, do not install dependencies, do not run a build, a codegen or a migration to conjure one. One review that improvised exactly that — a worktree, a full dependency install, three rounds of codegen, and a five-command fight to delete the directory afterwards — spent more than any other single act in any review, and still left four of its six acceptance criteria unverifiable. Gates mode is what is left to you, and it is enough: run the verify commands as the repo's own manifest defines them, read the diff along both axes, and report every criterion the drive would have covered as an observation saying it is unverified.
|
|
84
|
+
**Never build your own environment to drive in.** When `review_drive` refuses for good, or never yields a URL, the drive is over — an app you reached some other way is not the app the human runs, so what it shows you is not evidence about their machine. Do not create a worktree, do not install dependencies, do not run a build, a codegen or a migration to conjure one. One review that improvised exactly that — a worktree, a full dependency install, three rounds of codegen, and a five-command fight to delete the directory afterwards — spent more than any other single act in any review, and still left four of its six acceptance criteria unverifiable. Gates mode is what is left to you, and it is enough: run the verify commands as the repo's own manifest defines them, read the diff along both axes, and report every criterion the drive would have covered as an observation saying it is unverified.
|
|
78
85
|
|
|
79
86
|
**Walk the app with `agent-browser`.** Its core loop, which you repeat:
|
|
80
87
|
|
|
@@ -152,13 +159,17 @@ mcp__runcastle__report_finding({
|
|
|
152
159
|
|
|
153
160
|
Findings from **either** mode go through it — a cited Standards or Spec finding, or a failed gate, is a finding exactly as a drive bug is. One call per finding, never one call carrying three. Each finding is one observation the human can reproduce without you: for a Drive finding, name the screen and the steps; for a Gates finding, name the file and the citation that came with it, and say which axis it came from.
|
|
154
161
|
|
|
155
|
-
|
|
162
|
+
**A finding is a `defect` when the human's problem is not actually solved** — even when every acceptance criterion passes. The criteria describe the change that was asked for; the defect boundary is the outcome the human wanted. The canonical case, from a real project: the fix lands correctly at the store seam, but the controller endpoint builds its own response map and never calls the repaired path, so the operator-facing surface shows exactly what it showed before. Every criterion passes and the problem is untouched — that is a defect, and its `reproStep` is the human's own path to the unchanged surface.
|
|
163
|
+
|
|
164
|
+
A defect is also what a fix ticket can act on, so it carries something to act *from*: a cited hunk, a failing gate, or a drive step that reproduces. Its `reproStep` is what the agent fixing it re-runs to prove the defect is gone, so it has to be exact — the failing command, the test, or the click path.
|
|
165
|
+
|
|
166
|
+
**`observation` is everything else**, and that is a narrow bucket: your summary of the pass, scope deliberately deferred, something you could not verify, a warning that a surface is only half built, and findings that are clearly inert — an environment quirk like "no local Maven on the host", metric drift trivia. **Unsure whether the human's problem is solved → defect.** Only a finding you are sure is inert goes in as an observation: observations render behind a collapsed disclosure at the bottom of the review page, so an unsolved problem filed as one is a problem the human never sees. A false defect costs a fix ticket; a misfiled real one costs the feature.
|
|
156
167
|
|
|
157
|
-
**Severity is `high` when an acceptance criterion is unmet
|
|
168
|
+
**Severity is `high` when an acceptance criterion is unmet, when data/flow is broken, or when every criterion passes and the human's problem is still not solved**; `medium` for a real defect that is not that, `low` for the rest. It orders and labels; it never gates.
|
|
158
169
|
|
|
159
170
|
**Report defects highest severity first.** Each defect mints a fix ticket that burns in this same run, and only the first {{AUTO_FIX_CAP}} do — everything after the cap is stored for the human to decide on, so the order you report in decides what gets fixed.
|
|
160
171
|
|
|
161
|
-
Report as you find things, never in a batch at the end: a finding you have sent survives an iteration that ends early, and one you were saving up does not. There is no closing wrap-up call — the digest (step 5) is the summary, and your observations render
|
|
172
|
+
Report as you find things, never in a batch at the end: a finding you have sent survives an iteration that ends early, and one you were saving up does not. There is no closing wrap-up call — the digest (step 5) is the summary, and your observations render inside the page's collapsed *Full account* disclosure, alongside the digest's long account.
|
|
162
173
|
|
|
163
174
|
If some of this feature's implementation tickets failed — you are reviewing it anyway, on purpose, and the signature is a surface that is missing outright rather than misbehaving — report that as an observation and say it in the digest too: the human must know they are reading a review of a partially-built feature.
|
|
164
175
|
|
|
@@ -172,24 +183,32 @@ At exactly:
|
|
|
172
183
|
|
|
173
184
|
`{{DIGEST_PATH}}`
|
|
174
185
|
|
|
175
|
-
**Open with one short line naming the mode**,
|
|
186
|
+
**Open with one short line naming the mode**, the lap, what it landed and the counts — a single standalone line, then a blank line, then the rest. The review page lifts that first line out and renders it alone as the lap account, so it has to stand on its own: one line, no heading, no markdown, no lead-in, and nothing that reads as half a sentence needing the paragraph after it.
|
|
187
|
+
|
|
188
|
+
Its shape — `Lap <N>: <what landed, in the language of the product> · <X> defects found, <Y> fixed in-run · <Drive|Gates> mode`:
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
Lap 2: the review page now opens on state and one action · 3 defects found, 2 fixed in-run · Gates mode
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
The counts are the ones you know as you write: how many defects you reported, and how many of those fall inside the auto-fix cap and so burn as fix tickets in this same run. The lap number is `lap` on `mcp__runcastle__get_feature_context`. If you could not drive, the line still names the mode you actually ran.
|
|
176
195
|
|
|
177
|
-
**The rest is not a review log. It is the lap's
|
|
196
|
+
**The rest is not a review log. It is the lap's long account**, and the page keeps it behind a collapsed *Full account* disclosure at the bottom, with your observations — it is what the human opens when the one-liner is not enough, so it is neither the first thing they read nor rendered verbatim at the top. Write it anyway and write it well: they arrive wanting one question answered — *what did this lap actually do?* — and you are the agent best placed to answer it: you ran last, you hold the spec, and you have every implementer's own account above.
|
|
178
197
|
|
|
179
198
|
So write **prose**, roughly 10–15 lines, for a reader who has none of your context:
|
|
180
199
|
|
|
181
200
|
- **What the lap delivered**, in the language of the product, not the codebase. "The tickets ledger and the notes panel now group by lap, with prior laps collapsed" — not "modified TicketList.tsx and NotesPanel.tsx".
|
|
182
201
|
- **Synthesize, don't enumerate.** Not a ticket-by-ticket walk, not a changed-files list, not a commit log — those all exist elsewhere on the page. Say what the lap adds up to, and where the shape that landed differs from what the spec promised.
|
|
183
|
-
- **Say what it means for them**: what they can now do that they could not before, and what is worth their attention — the thing the drive was rough at, the deferred scope, the criterion you could not verify. In Gates mode, say whether the gates passed and the worst issue *within each axis* — never one winner across the two. If the drive never started, say `could not drive:
|
|
202
|
+
- **Say what it means for them**: what they can now do that they could not before, and what is worth their attention — the thing the drive was rough at, the deferred scope, the criterion you could not verify. In Gates mode, say whether the gates passed and the worst issue *within each axis* — never one winner across the two. If the drive never started, say why in the words step 2a gives you — `could not drive: slot never freed after ~5 minutes` or `could not drive: dirty tree (<files>)` — so the human knows at a glance whether the machine was busy or their own uncommitted files are what stopped it.
|
|
184
203
|
- **Plain sentences.** No headings, no bullet lists, no "I did X then Y", no tool names, no `<promise>` markers, no acceptance-criteria checklists. If it reads like an agent's log, rewrite it as something you would say out loud.
|
|
185
204
|
|
|
186
|
-
Findings belong in `report_finding`, not here — your observations
|
|
205
|
+
Findings belong in `report_finding`, not here — your observations sit inside the same disclosure as this prose, so repeating them costs the reader twice. One honest line about the headline problem is right; the catalogue is not.
|
|
187
206
|
|
|
188
207
|
Write it at that path and nowhere else — **never inside the repo**, which is the human's real working tree. This is the last thing you do before signalling COMPLETE.
|
|
189
208
|
|
|
190
209
|
## Could not review
|
|
191
210
|
|
|
192
|
-
The bar is high, because Gates mode needs almost nothing: no app, no browser, no drive slot. Finding bugs is not failure, and **neither is a drive that would not start** — that is an observation, a switch to Gates mode, and a line in the digest.
|
|
211
|
+
The bar is high, because Gates mode needs almost nothing: no app, no browser, no drive slot. Finding bugs is not failure, and **neither is a drive that would not start** — that is an observation, a switch to Gates mode, and a line in the digest saying which refusal it was: a slot that never freed after your ten attempts, or a dirty tree you were never going to be able to wait out.
|
|
193
212
|
|
|
194
213
|
The review **failed** only when Gates mode itself could not run and so there was nowhere to fall back to:
|
|
195
214
|
|
|
@@ -206,8 +225,9 @@ When that happens: run the step 4 cleanup for whatever you got as far as startin
|
|
|
206
225
|
- **Never merge or re-rank the two review axes**, and never report a finding without its citation.
|
|
207
226
|
- **Never let a sub-agent spawn more agents.** The guard line goes in both briefs, every time.
|
|
208
227
|
- **Never leave the drive — or the recorder — running.** Stop both on every path, including the one where you gave up on the drive.
|
|
209
|
-
- **Never build your own environment.** No worktrees, no dependency installs, no builds, no generated artifacts. If `review_drive` did not hand you the app, the drive did not happen: say `could not drive
|
|
228
|
+
- **Never build your own environment.** No worktrees, no dependency installs, no builds, no generated artifacts. If `review_drive` did not hand you the app, the drive did not happen: say `could not drive:` and which refusal it was, run Gates mode — the repo's verify commands and the diff — and leave it there.
|
|
229
|
+
- **Never wait out a refusal that will not clear.** The ten polls are for `retriable: true` — a held slot — and nothing else. Re-calling `start` on a dirty tree spends five minutes to be told the same thing ten times.
|
|
210
230
|
- **Never report a finding you did not observe.** Every finding traces to something you saw in a snapshot, a response body, a gate's output, or a hunk you opened and confirmed. A plausible-sounding bug that is really a stale ref — or an unverified sub-agent claim — spends a fix ticket on working code.
|
|
211
231
|
- **Never report a defect without a repro step**, and never one you would not stake a code change on. If it does not reproduce, it is an observation.
|
|
212
|
-
- **Never write the digest as a log.**
|
|
232
|
+
- **Never write the digest as a log.** Its first line is the standalone lap account the page renders on arrival; after it comes the lap's prose summary, which the human opens behind a disclosure.
|
|
213
233
|
- **Stay inside this ticket.** Review what it names and the lap it landed. Adjacent things you notice are observations, not a sprawl of speculative defects.
|
|
@@ -4,6 +4,12 @@ You are running a bounded verification pass on `{{FEATURE_BRANCH}}` against `{{B
|
|
|
4
4
|
|
|
5
5
|
{{DRIVE_AVAILABILITY}}
|
|
6
6
|
|
|
7
|
+
## How you run
|
|
8
|
+
|
|
9
|
+
You run **non-interactively** — your agent CLI in print/exec mode, no terminal, no human. So:
|
|
10
|
+
|
|
11
|
+
- **Signal completion.** Print exactly `<promise>COMPLETE</promise>` as the last line of your final message, whether the pass went well or you could not run it at all. It is the only completion signal there is, and it is read from your message — a marker written into a file is invisible, and without one in your message this same pass runs again from the top.
|
|
12
|
+
|
|
7
13
|
## What landed
|
|
8
14
|
|
|
9
15
|
{{LANDED_FIXES}}
|
|
@@ -30,10 +36,12 @@ Run digests:
|
|
|
30
36
|
|
|
31
37
|
In **Drive mode**, call `mcp__runcastle__review_drive({ action: "start" })`, start the recorder at `{{WALKTHROUGH_PATH}}`, and walk every acceptance criterion's user-facing surface once at pace. Keep the recorder running for the whole tour. Scrutinise only the landed fixes: check whether each listed repro step still reproduces and inspect the surfaces those fixes touched. Report anything plainly broken during the tour, but do not hunt for unrelated defects. Stop the recorder and drive when finished.
|
|
32
38
|
|
|
39
|
+
{{DRIVE_INSTRUCTIONS}}
|
|
40
|
+
|
|
33
41
|
In **Gates mode**, read each fix diff against its finding and run the configured gates exactly once. Do not perform a second two-axis review of the whole branch.
|
|
34
42
|
|
|
35
43
|
{{GATE_NOTES}}
|
|
36
44
|
|
|
37
45
|
Report findings through `mcp__runcastle__report_finding` as usual. Verification findings remain open for the human and never mint fix tickets. The ordinary review auto-fix cap is {{AUTO_FIX_CAP}}.
|
|
38
46
|
|
|
39
|
-
Write `{{DIGEST_PATH}}`. Its first line must name the inherited mode and say "verification pass" (for example, `Drive verification pass`). Summarise which fixes held, which did not, and anything plainly broken on the tour. If the pass cannot run at all, write `{{BLOCKED_PATH}}` with the precise reason instead.
|
|
47
|
+
Write `{{DIGEST_PATH}}`. Its first line must name the inherited mode and say "verification pass" (for example, `Drive verification pass`). Summarise which fixes held, which did not, and anything plainly broken on the tour. No `<promise>` markers inside the digest — the completion signal is a line in your message, never a line in this file. If the pass cannot run at all, write `{{BLOCKED_PATH}}` with the precise reason instead. Either way, the file you write is the last thing you do before signalling COMPLETE.
|
|
@@ -15,11 +15,12 @@ Your system prompt carries the per-session facts — the repo path, which keys a
|
|
|
15
15
|
1. Open by naming what is still open and what you need from the human for each. Do not survey the repo first; the prompt already told you the gap.
|
|
16
16
|
2. Work the keys **one at a time**: propose, ask, run it if they agree, record it.
|
|
17
17
|
3. If the open keys touch the drive loop, author the machinery (below) before you record the two hook commands — the settings are invocation lines for scripts that must exist.
|
|
18
|
-
4.
|
|
18
|
+
4. If the repo builds with a toolchain the sandbox image does not carry, author its Dockerfile (below) — the sandbox keys are worth nothing in an image that cannot run them.
|
|
19
|
+
5. Close by proposing a dry-run drive (below). Values that have never been driven look exactly as trustworthy as values that run perfectly.
|
|
19
20
|
|
|
20
21
|
**Ask before you act.** Anything that starts or stops a service, creates or migrates a database, installs software, or writes outside the repo needs the human to agree first: say what you are about to run and why, then wait. Their own stack is running next to yours.
|
|
21
22
|
|
|
22
|
-
## The
|
|
23
|
+
## The eight keys
|
|
23
24
|
|
|
24
25
|
Four describe the drive loop and can only be settled here:
|
|
25
26
|
|
|
@@ -33,6 +34,12 @@ Three describe the **sandbox** a burn agent works in, and no amount of running t
|
|
|
33
34
|
- **`verifyCommands`** — the exact typecheck/test/lint lines a burn agent should use, one per line. Unset, agents guess workspace filter names and burn whole suite runs discovering the right one.
|
|
34
35
|
- **`knownFailures`** — what already fails on the main branch, so an agent can tell its own breakage from the repo's. Free text; a count plus the suite names is enough.
|
|
35
36
|
|
|
37
|
+
The image those three run in is not a key: runcastle sets it itself. What can fall to you is authoring the Dockerfile it builds — see the sandbox image, below.
|
|
38
|
+
|
|
39
|
+
The eighth is what a later agent needs once the app is actually up:
|
|
40
|
+
|
|
41
|
+
- **`driveInstructions`** — free text describing how to **exercise** this app in a drive, injected verbatim into every drive-mode review and verification prompt. What belongs in it: the sample project, seeded account or scratch data a driver should use and may freely change; how to reach the deep states worth reviewing rather than only the front page; and what a driver may and may not touch inside the running app. Write it as standing instructions from the project's owner — they authorize actions *inside the app under test* and nothing else, so do not write anything meant to relax a reviewing agent's own rules. Its evidence is the dry-run drive below: you just drove this app, so record what you had to know to get anywhere. Unset, a review agent boots the app cold, finds nothing it is allowed to touch, and verifies nothing.
|
|
42
|
+
|
|
36
43
|
## The drive contract
|
|
37
44
|
|
|
38
45
|
A drive is a script **you** write, committed to the project, plus the two things only the server can do. Everything else — ports, database names, redis indexes, compose project names, URLs — the script computes for itself. Runcastle mandates these seven points and nothing else:
|
|
@@ -67,6 +74,37 @@ The overlay is process environment, which beats a `.env` file in dotenv, Prisma
|
|
|
67
74
|
|
|
68
75
|
Grep the app's entry points and config for env loading and decide, for each, which side wins. Where the process environment loses: get it fixed — you may not edit app code from this session, so propose the change (usually dropping `override`) and let the human make it — or, if it must stay, record the finding with `record_event` naming the file and what it breaks, so the first confusing drive is not a mystery.
|
|
69
76
|
|
|
77
|
+
## The sandbox image
|
|
78
|
+
|
|
79
|
+
Burn agents do not work on this host; they work in a container. The image runcastle builds carries a JavaScript toolchain and the agent CLIs — Node, Bun, git, curl — and nothing beyond that, so a repo that builds with a JDK, a Python, a Go compiler or a Rust toolchain cannot run its own `setupCommand` there: the burn dies on `mvn: not found`. The fix is a Dockerfile committed at **`.runcastle/sandbox/Dockerfile`**. Runcastle detects it, builds it as this project's image, and every burn runs in that image from then on.
|
|
80
|
+
|
|
81
|
+
Deciding whether this project needs one is part of this session — you are in the real checkout, which is where the evidence is. Read the manifests at the root and in each workspace:
|
|
82
|
+
|
|
83
|
+
- `pom.xml`, `mvnw` — a JDK and Maven
|
|
84
|
+
- `build.gradle`, `build.gradle.kts`, `gradlew` — a JDK and Gradle
|
|
85
|
+
- `pyproject.toml`, `requirements.txt` — Python and its installer (pip, or uv where the project uses it)
|
|
86
|
+
- `go.mod` — Go
|
|
87
|
+
- `Cargo.toml` — Rust
|
|
88
|
+
- `Gemfile` — Ruby
|
|
89
|
+
|
|
90
|
+
A mixed repo gets the union: a service in Go beside a Java client needs both. Anything else the project shells out to in its setup or verify commands and the stock image lacks belongs here too — a database client, a protobuf compiler — on the same evidence, that you saw it in the repo.
|
|
91
|
+
|
|
92
|
+
**A JavaScript-only repo gets no Dockerfile.** The stock image already covers it, and an unnecessary project image is one more thing to build, rebuild and keep fresh in exchange for nothing. Do not write one to be helpful.
|
|
93
|
+
|
|
94
|
+
When the project does need one, what you write:
|
|
95
|
+
|
|
96
|
+
- **It starts `FROM sandcastle:runcastle`** and layers onto it. That base is what keeps the agent CLIs, git and Node present; a Dockerfile from any other base is not a runcastle sandbox, and burns in it fail on the agent binary before they ever reach the toolchain.
|
|
97
|
+
- **Read the stock Dockerfile before you write a single install line**, rather than assuming its distro or package manager. It is the build context runcastle scaffolds at `~/.runcastle/sandbox-build/Dockerfile` once the image has been built on this machine, and it also ships inside the installed runcastle package as `sandcastle-template/Dockerfile`. Follow its idioms — the same package manager, the same flags, the same cleanup at the end of the layer. If you cannot find it, ask the human instead of guessing what you are layering onto.
|
|
98
|
+
- **The toolchain only, never the project's dependencies.** Install the JDK and Maven; do not run `mvn install` or `go mod download` at build time. Dependencies are what `setupCommand` installs per burn, from the branch's own manifests — anything baked into the image is stale the first time a branch adds a package.
|
|
99
|
+
- **No package caches in layers.** Do not prime `~/.m2`, `~/.gradle`, `~/.cache/pip` or the Go module cache in a `RUN` step. Download caches are mounted into the sandbox from the host, which is how they stay current across burns; a cache baked into a layer is weight the image carries and wrong the moment a lockfile moves.
|
|
100
|
+
- **Keep it minimal** — one `RUN` block where the package manager allows it, versions pinned only where the project pins them, nothing added "while we're here". Every line is a line someone maintains.
|
|
101
|
+
|
|
102
|
+
It is committed project machinery, exactly like the drive scripts, for the same reason: a branch that changes the toolchain amends its own Dockerfile, and burns on that branch get the amended image. Writing it falls under the same exception — `.runcastle/` and `.gitignore`, nothing else — and the same courtesy: show the human the file before you commit it.
|
|
103
|
+
|
|
104
|
+
If `.runcastle/sandbox/Dockerfile` is already there, read it and **edit conservatively**. Someone chose those lines, and a customization you do not recognize is still a decision. Say what you probed and what you think is missing — "I see `pyproject.toml` but no Python in the image" — and let the human decide. An existing Dockerfile that covers what you found needs no edit at all.
|
|
105
|
+
|
|
106
|
+
**You never build the image.** That is a watched terminal action the human takes: the Enable AFK burns card offers **Build image**, and on a successful build runcastle points this project at the image itself — there is no image setting for you to work out or record. So end on it. Tell them the Dockerfile is written (or already right), that the card now offers Build image, and that burns use the project image after that click; until then they keep running in whatever image they run in today.
|
|
107
|
+
|
|
70
108
|
## Recording what you establish
|
|
71
109
|
|
|
72
110
|
One `record_finding` call per key, and `evidence` is not optional in spirit: record what you ran and what it printed, or what the human told you. A value with no account of itself is a guess with a source field.
|
|
@@ -34,8 +34,16 @@ Your kickoff line reads `LAP <n> REVIEW ITERATION`. The human burned the last la
|
|
|
34
34
|
3. **Never re-emit a promoted note.** Notes the human already promoted from the review checklist are tickets in *this* lap and arrive as ids in your context. However well such a note reads as a ticket, if its id is in front of you the work is already carded — emitting it again gives the burner the same job twice.
|
|
35
35
|
4. **Grill, briefly.** A small rethink is a short grilling: a few questions, one at a time, each with your recommended answer attached. Prune and promote `## Later laps` entries with the human as part of that conversation — what the drive taught is usually what decides which deferred scope this lap picks up and which stays parked.
|
|
36
36
|
5. **Amend the docs.** Append this lap's learning to `docs/features/<slug>/decisions.md` under a `## Lap <n>` heading (the convention) — never rewrite old decisions, supersede them. Then amend `spec.md` in place: the sections this lap changes, plus the pruned `## Later laps`.
|
|
37
|
-
6. **Emit this lap's tickets.** `mcp__runcastle__emit_tickets({ tickets })` — only the work this lap will burn; the rest stays in `## Later laps`. Reconcile stale pending tickets with `update_ticket` / `cancel_ticket`; `done` work that is now wrong gets a NEW ticket, as always.
|
|
38
|
-
|
|
37
|
+
6. **Emit this lap's tickets, dispositioning the defects as you do.** `mcp__runcastle__emit_tickets({ tickets })` — only the work this lap will burn; the rest stays in `## Later laps`. Reconcile stale pending tickets with `update_ticket` / `cancel_ticket`; `done` work that is now wrong gets a NEW ticket, as always.
|
|
38
|
+
|
|
39
|
+
The defects an **earlier** lap's review left open arrive in your context as `openDefects` (`carriedDefects` are the ones a lap already parked — agenda, not obligation). Each open one needs exactly one of three answers, and the tickets gate refuses by name until every one has had it:
|
|
40
|
+
|
|
41
|
+
- **Link** — this lap is carding the work that fixes it: emit that ticket with `originFindingId: "<the defect's id>"`. Nothing else to do; the burn closes the finding itself when the ticket lands.
|
|
42
|
+
- **Carry** — nobody is answering it this lap: `mcp__runcastle__resolve_finding({ findingId, disposition: "carry" })`. It leaves the open count, stays visible, and only the human reopens it.
|
|
43
|
+
- **Close as addressed** — this lap's work already answers it and no ticket names it: `mcp__runcastle__resolve_finding({ findingId, disposition: "addressed", note: "<what addressed it>" })`. The note is required and is your attestation, so make it specific ("lap 2's ticket 7 rewrote the endpoint").
|
|
44
|
+
|
|
45
|
+
Judge each against what you and the human just settled — you are the only party that knows whether this lap's tickets touch a defect, which is why this is yours and not a dialog. If one genuinely is not this lap's business, carry it; do not close what you have not established.
|
|
46
|
+
7. **Advance the pipeline.** `mcp__runcastle__complete_phase` through `ideation` → `spec` → `tickets`, here, without opening another session. It will not cross into implementation: the `tickets` call comes back `ok: true` with `waitingOn: "human burn"` and the feature parks at `tickets` instead of advancing — that gate (G3) is the human's Burn click, which is the point. If it comes back refusing over un-dispositioned defects, move 6's triage is unfinished — answer the ones it names and call again.
|
|
39
47
|
8. **Hand to Burn.** Tell the human in a line or two what this lap does, then:
|
|
40
48
|
|
|
41
49
|
> Lap `<n>` is specced and carded. Review the ticket cards and click **Burn** — I'll stop here.
|
|
@@ -42,6 +42,8 @@ Close the batch with **one review ticket** (`kind: "review"`), blocked by every
|
|
|
42
42
|
|
|
43
43
|
**Every batch closes with one, unconditionally.** Not "when there is something to exercise" — every batch, no exceptions, exactly one (more per feature comes later). Whatever the lap turned out to be, there is always a review the agent can run: a diff is the one thing every batch produces by definition. A lap that ships without a review ticket is a lap nobody looked at, and its absence is invisible on the review page — which is precisely the silence this rule exists to end.
|
|
44
44
|
|
|
45
|
+
The server enforces this too, so a refusal here is the seatbelt working, not a bug: G3 refuses a lap whose tickets include no `kind: "review"` one, and `emit_tickets` refuses a batch outright when a ticket is *titled* like the review but carries another kind — set the kind (or retitle it) and re-emit.
|
|
46
|
+
|
|
45
47
|
The agent reviews in **exactly one of two modes**, never both — a browser **Drive** of the app against your acceptance criteria, or **Gates**: the project's verify commands plus a two-axis read of the diff. Reviews that attempted both ran long or died having delivered neither, so the burner prompt makes the agent choose up front and spend the whole review inside the choice.
|
|
46
48
|
|
|
47
49
|
Your job is to make that choice obvious. Prescribe a walkthrough only when there is genuinely a surface to walk, in plain prose ("open the settings flow, add a project, check the empty state"), and write the `acceptanceCriteria` as the steps of that walk. When the lap changed nothing a human could drive — prompt contracts, docs, an internal refactor, a backend-only change — say so in the ticket, and write criteria the gates-and-diff mode can actually check off. Do not ask for both; do not ask for a browser walk of something with no UI.
|
|
@@ -89,7 +91,7 @@ There is no in-session quiz — the human's review is the **Burn** gate in the r
|
|
|
89
91
|
6. Does the batch close with exactly one `kind: "review"` ticket, blocked by every implementation ticket? It is not optional and there is no feature that skips it.
|
|
90
92
|
|
|
91
93
|
Then:
|
|
92
|
-
- `mcp__runcastle__emit_tickets({ tickets: [...] })` — **emit the array; do NOT write ticket files.** It returns `{ stored, ids }` and logs the timeline event itself; do not record one of your own.
|
|
94
|
+
- `mcp__runcastle__emit_tickets({ tickets: [...] })` — **emit the array; do NOT write ticket files.** It returns `{ stored, ids }` and logs the timeline event itself; do not record one of your own. Emit the **whole batch, fully enriched, in one call** — large payloads are supported, so a batch of long `context` fields is fine. Never emit placeholder contexts ("Context follows via `update_ticket`.") to enrich ticket by ticket afterwards: a Burn landing mid-enrichment burns agents on the placeholders.
|
|
93
95
|
- `mcp__runcastle__complete_phase({ phase: "tickets" })`. If the gate returns `ok: false`, fix what it names and retry.
|
|
94
96
|
|
|
95
97
|
Return control to **the session skill that invoked you** — `/runcastle:ideate` for a linear feature, `/runcastle:converge` for a mapped one — and let it close out the session. Do **not** invoke a session skill yourself to hand back: you are already inside one, and loading another session's entry skill would drop a whole procedure this session is not running (a converge session in particular is forbidden to grill) into the window.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.xterm{cursor:text;-webkit-user-select:none;user-select:none;position:relative}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{z-index:5;position:absolute;top:0}.xterm .xterm-helper-textarea{opacity:0;z-index:-5;white-space:nowrap;resize:none;border:0;width:0;height:0;margin:0;padding:0;position:absolute;top:0;left:-9999em;overflow:hidden}.xterm .composition-view{color:#fff;white-space:nowrap;z-index:1;background:#000;display:none;position:absolute}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{cursor:default;background-color:#000;position:absolute;inset:0;overflow-y:scroll}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;top:0;left:0}.xterm-char-measure-element{visibility:hidden;line-height:normal;display:inline-block;position:absolute;top:0;left:-9999em}.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{z-index:10;color:#0000;pointer-events:none;position:absolute;inset:0}.xterm .xterm-accessibility-tree:not(.debug) ::selection{color:#0000}.xterm .xterm-accessibility-tree{-webkit-user-select:text;user-select:text;white-space:pre;font-family:monospace}.xterm .xterm-accessibility-tree>div{transform-origin:0;width:fit-content}.xterm .live-region{width:1px;height:1px;position:absolute;left:-9999px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{-webkit-text-decoration:underline double;text-decoration:underline double}.xterm-underline-3{-webkit-text-decoration:underline wavy;text-decoration:underline wavy}.xterm-underline-4{-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.xterm-underline-5{-webkit-text-decoration:underline dashed;text-decoration:underline dashed}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:underline overline}.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;pointer-events:none;position:absolute;top:0;right:0}.xterm-decoration-top{z-index:2;position:relative}.xterm .xterm-scrollable-element>.scrollbar{cursor:default}.xterm .xterm-scrollable-element>.scrollbar>.scra{cursor:pointer;font-size:11px!important}.xterm .xterm-scrollable-element>.visible{opacity:1;z-index:11;background:0 0;transition:opacity .1s linear}.xterm .xterm-scrollable-element>.invisible{opacity:0;pointer-events:none}.xterm .xterm-scrollable-element>.invisible.fade{transition:opacity .8s linear}.xterm .xterm-scrollable-element>.shadow{display:none;position:absolute}.xterm .xterm-scrollable-element>.shadow.top{width:100%;height:3px;box-shadow:var(--vscode-scrollbar-shadow,#000) 0 6px 6px -6px inset;display:block;top:0;left:3px}.xterm .xterm-scrollable-element>.shadow.left{width:3px;height:100%;box-shadow:var(--vscode-scrollbar-shadow,#000) 6px 0 6px -6px inset;display:block;top:3px;left:0}.xterm .xterm-scrollable-element>.shadow.top-left-corner{width:3px;height:3px;display:block;top:0;left:0}.xterm .xterm-scrollable-element>.shadow.top.left{box-shadow:var(--vscode-scrollbar-shadow,#000) 6px 0 6px -6px inset}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2)format("woff2-variations");unicode-range:U+460-52F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2)format("woff2-variations");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2)format("woff2-variations");unicode-range:U+1F??}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/inter-greek-wght-normal-CkhJZR-_.woff2)format("woff2-variations");unicode-range:U+370-377,U+37A-37F,U+384-38A,U+38C,U+38E-3A1,U+3A3-3FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2)format("woff2-variations");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/inter-latin-wght-normal-Dx4kXJAl.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(data:font/woff2;base64,d09GMgABAAAAAAfsABQAAAAAEAwAAAeCAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhwbHhwoP0hWQVJbBmA/U1RBVIFiJyYAdC9qEQgKhGSEAAsgADCGCAE2AiQDOgQgBYlMB4EUDAcbLQ4onoexrSC/2ZyLAa8p8VHB8/x3Vue+V0hVJalMJg2nx/TCrQXxBeqLjQG7FyM1WEa/X1tEXN7cFz9EJEMmMUz3RihWSSKeQCbcIou0izz/C8v+fq3VfajEa9gDD11CImXS7qL/RJFVzC1qiB6KmKeD6TZdQ6IRGv78dL6uSVVCfgni5mzu7kcgQBgAEAQTQRCoL++STTYybkJxNfQxAAIAGu8OdEB9teW2jh4BpgDqFjAeSEByW3zFP0CBBgNMsMCGEDjgggdhiEAUAeIIED7ABTDUEnkIE9Q9ahFgKttcVhApo4ACB4qobHaccgDfEjFO6aaWUhjMLt2SyIvHKoDqoA4CSUwEIYQCEjhAO9R1G6keDeDZGjNo+AhxOjCEGTr1WeIF3kYBiLAOKvkJSMiKX0VdAyQt3SDJClCkxJCHkCzfqyVTriJZLcolS32JZHUekq2TYNkYtCtjYHMQXSxGjXDz2t/yLWXzDzxz+o3zFwDEaN23F+13pyMdQAEaSKAR9vcGq4A4MTSKCElGW+M7UcY7xqkggITb28ZJhlqc9q2twYKTt0NjixBgYvO9BIihEBLYuOFXQzfIQ7dXGUEEEgFDooBfAzqiQbpJrhiWSuKJCRFKYbHCyJKI2G5GiZbNAvgAu5pc3vwx4G+g3aDkhklABiSz0BICXrYghtYhx/cdJ+44rY2oZ0aMNRFz3VZjb6W33F3gzltqtOCV8tTHSpOeXuItfvr5lCdfzFpqtEitvqdcdGGFd28ZqqC0tPbeChGXgrIlnhSWu/eUso4uKWFLugyDzQJhflY4659+WjQ++6x72WUMv9G8mw6QJl7BVxX5fe/kpUsOvnZwee9uQ0cGXYd0o89XB2748sDSnt8d2VphdOTTgceDVvOds0v9P/s7HPq15aGun/6Vllb56f1dl0t1LejqrNkpdRZsG8TOnM5vkBG5oiVyVGnS8LHps5cfNWJs6qKPfaNSxiQNBUm3cKNWROr0GSur7Za31k1vieq7LH11VF+jXdRIasRKflc7jkobm1Z9te1IyZA0pDkhLR98+H37Zf1c/8at+dB7x+7GfVyTfJMPiYztsnl59Y5l4j+0n1RXlpHnF3Tq7HecmNF/CJodEMAikruxiyJaGLvHOdAfoA+oDvpjBm2b91cHGRZMU9n25xEU0A8fgEEAdKI3Q1iDtc034sug5YVMkE2jsE+BIkwSoQ3gxXMqz9tELp48bd0cFKOKS7xYjEuXBnZP5ia7DyiO/X/YI+PQSbt2uSdqAkWL9nQbV1XB94/+uPfdZz8dnXYFBYrcTl2SIR/ybxJNJPz/Gupb0JaZeens2ekC7EKr8t+Ls/P5VJPYJdHKyqfg2nqU6bhlidzcddQV/7MmecTzJ5VPcKXkNKSEogHjYFx6QZ7rQ+FSe8njaiNuOnXS8H2ScQ619c2mC3VTtauL0rRbXd/CkSOP37FY9Zkjz8+GibYUMOEWF+RdrFS8Ecv1SHOpPUPZGEIpjPvFyU5cXKjd6OXqorTqy9GwRd++HVufPGnVsW+aO3vggKZ18jR9sXaTC1PWTEsVUaK0FkNySbTQDqlm2PfDjZcu4aalnSLKjnOoYQ0nUlqqXcGpPu/4VgV/xU2pAqW4BW3qzhQ8/hFKhV2qE3+BKAtDqBXjfgnVdH4y0wg5tbVNRenNdTWOrenWLcupQdmsbq5b+18piTe/xRdp1xbILxNPJGInm2z6hoB21Lal0i+ePTtd7B45+3XhFJ329evskXm7qurUVREotqSluSo/L29d3qDhI4YOQqWhI4YNvBNfsMHeXKemXrxQfKeuPOGRVayA3JtkJKEgbPp+dXUDluddutRYLFoXGXWX6N3WFaGLbQtRSitVYNacTNSdy7AaG/HSaUEANcBoGXNdcZvZsOqQ1icBDv21/gzAoYPHH/WDW0qNR3QTYKEAEHig6o13NXbND06CQPlRtYjGNnSktRc09k1mAMDvAlDKfQjgy6fssInlfzmNAjKkDxoxHOBLdVRAIVt9j4qo+hA1w9T1aNBNTUOTTNUHLbqokE+UAfJXCIGw/IxCSL5GRUJeR40rL/UxTm4Q08H6MbCs70ObuNyIIXrINHQYInF06UUlevTjbQzTh5upiDMzMMogUtEnjPs/Y7jAHCJeB0GBHh04tC6FiB6ZFB1oArUSIoFoqhzCeAN6lHwm0T4C3VVPWvjpSMXReuWesMEcoqrmgtNBGd2noWeV0hNAz9rFeShNJxHGsPa3HXeKTk8b55hahySYHaYKKFFLpCfN8rsoaJn01CR04Gkc+5k7KVTCmClX8Q10HCrUEkVlSX+XO33oQR9609tJ516H497WSobWs5Up6TLaS10/dessIskgJSLiDlWvHVUywpkQ7hdPZqGyiEF0uVQerVcPamT1A3eKXdyI1vG9OoflrSXihZ1qqGE3nhmAgiIbRCQgPLEPtOM3UQwTLYaYYomNlpA44opnjV6jkD6id80OOrzf6BzmMD6eEa1zKyeYG1fzfEf16V6jw9XYOaar1/b2kP/IYX8oR2mcFvv2GtBV3JXgd437AQAA)format("woff2-variations");unicode-range:U+460-52F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2)format("woff2-variations");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2)format("woff2-variations");unicode-range:U+370-377,U+37A-37F,U+384-38A,U+38C,U+38E-3A1,U+3A3-3FF}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2)format("woff2-variations");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial;--tw-content:""}}}@layer theme{:root,:host{--font-sans:"Inter Variable", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;--font-mono:"JetBrains Mono Variable", "Cascadia Code", Consolas, ui-monospace, monospace;--spacing:.25rem;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-normal:0em;--tracking-wide:.025em;--tracking-wider:.05em;--leading-tight:1.25;--leading-snug:1.375;--leading-normal:1.5;--leading-relaxed:1.625;--ease-out:cubic-bezier(0, 0, .2, 1);--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--aspect-video:16 / 9;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--color-bg:#090b10;--color-panel:#0e1117;--color-panel-2:#0b0e14;--color-panel-3:#12151d;--color-panel-inset:#07080b;--color-hairline:#1c2230;--color-hairline-soft:#151a26;--color-hairline-strong:#2a3242;--color-text:#dde3ed;--color-text-2:#96a0b0;--color-text-3:#5f6a7a;--color-text-4:#3a4354;--color-accent:#7c6cf6;--color-accent-hi:#a49bff;--color-accent-2:#8f80f8;--color-accent-ink:#0d0722;--color-accent-soft:#161329;--color-accent-line:#3d3670;--color-ph-ideation:#8b7cf8;--color-ph-spec:#8a94a2;--color-ph-tickets:#d7a94a;--color-ph-implementation:#f0883e;--color-ph-review:#58a6ff;--color-ph-shipped:#3fb950;--color-danger:#f4594e;--color-needs:#d7a94a;--color-warn:var(--color-needs);--color-ok:#3fb950;--color-drive:#58a6ff;--text-xs:11px;--text-xs--line-height:1.45;--text-sm:12px;--text-sm--line-height:1.5;--text-base:14px;--text-base--line-height:1.5;--text-lg:16px;--text-lg--line-height:1.4;--text-xl:20px;--text-xl--line-height:1.3;--radius-sm:6px;--radius-md:8px;--radius-lg:12px;--radius-pill:999px;--shadow-menu:0 8px 28px -10px #000000b3, 0 2px 8px -2px #00000080;--shadow-overlay:0 24px 70px -24px #000000d9, 0 8px 24px -12px #0009;--ease-app:cubic-bezier(.22, .61, .24, 1);--ease-out-app:cubic-bezier(.16, 1, .3, 1);--animate-toast-in:toastIn var(--dur-3) var(--ease-out-app);--animate-backdrop-in:backdropIn var(--dur-2) var(--ease-out-app);--animate-overlay-in:cmdkIn var(--dur-2) var(--ease-out-app);--animate-dot-glow:dotGlow 2.2s var(--ease-app) infinite;--control-h:32px;--sidebar-w:300px;--inspector-w:300px;--maprail-w:300px;--artifact-w:380px;--content-max:1060px;--dur-1:.12s;--dur-2:.19s;--dur-3:.32s;--ring:0 0 0 2px var(--color-bg), 0 0 0 4px #7c6cf680}}@layer base{button{appearance:none;background:0 0;border:0;padding:0}}@layer components;@layer utilities{.pointer-events-auto{pointer-events:auto}.pointer-events-none{pointer-events:none}.collapse{visibility:collapse}.invisible{visibility:hidden}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:0}.inset-x-0{inset-inline:0}.-top-1\.5{top:calc(var(--spacing) * -1.5)}.-top-6{top:calc(var(--spacing) * -6)}.top-0{top:0}.top-2{top:calc(var(--spacing) * 2)}.top-2\.5{top:calc(var(--spacing) * 2.5)}.top-4{top:calc(var(--spacing) * 4)}.top-5\.5{top:calc(var(--spacing) * 5.5)}.top-6\.5{top:calc(var(--spacing) * 6.5)}.top-\[calc\(100\%\+6px\)\]{top:calc(100% + 6px)}.-right-\[3px\]{right:-3px}.right-2{right:calc(var(--spacing) * 2)}.right-4{right:calc(var(--spacing) * 4)}.bottom-0{bottom:0}.bottom-1\.5{bottom:calc(var(--spacing) * 1.5)}.bottom-8\.5{bottom:calc(var(--spacing) * 8.5)}.left-0{left:0}.left-2\.5{left:calc(var(--spacing) * 2.5)}.z-10{z-index:10}.z-20{z-index:20}.z-\[200\]{z-index:200}.z-\[300\]{z-index:300}.z-\[400\]{z-index:400}.col-span-2{grid-column:span 2/span 2}.col-span-full{grid-column:1/-1}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.m-0{margin:0}.-mx-3{margin-inline:calc(var(--spacing) * -3)}.mx-3{margin-inline:calc(var(--spacing) * 3)}.mx-auto{margin-inline:auto}.my-1{margin-block:var(--spacing)}.my-1\.5{margin-block:calc(var(--spacing) * 1.5)}.my-2\.5{margin-block:calc(var(--spacing) * 2.5)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-2\.5{margin-top:calc(var(--spacing) * 2.5)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-3\.5{margin-top:calc(var(--spacing) * 3.5)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-7{margin-top:calc(var(--spacing) * 7)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mt-9{margin-top:calc(var(--spacing) * 9)}.mt-auto{margin-top:auto}.mt-px{margin-top:1px}.mr-1\.5{margin-right:calc(var(--spacing) * 1.5)}.mr-auto{margin-right:auto}.mb-0{margin-bottom:0}.mb-0\.5{margin-bottom:calc(var(--spacing) * .5)}.mb-1{margin-bottom:var(--spacing)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-2\.5{margin-bottom:calc(var(--spacing) * 2.5)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.mb-7{margin-bottom:calc(var(--spacing) * 7)}.-ml-2\.5{margin-left:calc(var(--spacing) * -2.5)}.ml-1{margin-left:var(--spacing)}.ml-1\.5{margin-left:calc(var(--spacing) * 1.5)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-3{margin-left:calc(var(--spacing) * 3)}.ml-auto{margin-left:auto}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-clamp-3{-webkit-line-clamp:3;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.aspect-video{aspect-ratio:var(--aspect-video)}.size-1\.5{width:calc(var(--spacing) * 1.5);height:calc(var(--spacing) * 1.5)}.size-1\.75{width:calc(var(--spacing) * 1.75);height:calc(var(--spacing) * 1.75)}.size-2{width:calc(var(--spacing) * 2);height:calc(var(--spacing) * 2)}.size-2\.5{width:calc(var(--spacing) * 2.5);height:calc(var(--spacing) * 2.5)}.size-3{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.size-3\.5{width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5)}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.size-5\.5{width:calc(var(--spacing) * 5.5);height:calc(var(--spacing) * 5.5)}.size-6{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6)}.size-7{width:calc(var(--spacing) * 7);height:calc(var(--spacing) * 7)}.size-8{width:calc(var(--spacing) * 8);height:calc(var(--spacing) * 8)}.size-9{width:calc(var(--spacing) * 9);height:calc(var(--spacing) * 9)}.size-10{width:calc(var(--spacing) * 10);height:calc(var(--spacing) * 10)}.size-\[7px\]{width:7px;height:7px}.h-\(--control-h\){height:var(--control-h)}.h-0\.75{height:calc(var(--spacing) * .75)}.h-1{height:var(--spacing)}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-5\.5{height:calc(var(--spacing) * 5.5)}.h-6{height:calc(var(--spacing) * 6)}.h-6\.5{height:calc(var(--spacing) * 6.5)}.h-7{height:calc(var(--spacing) * 7)}.h-7\.5{height:calc(var(--spacing) * 7.5)}.h-8{height:calc(var(--spacing) * 8)}.h-11{height:calc(var(--spacing) * 11)}.h-12{height:calc(var(--spacing) * 12)}.h-14{height:calc(var(--spacing) * 14)}.h-16{height:calc(var(--spacing) * 16)}.h-70{height:calc(var(--spacing) * 70)}.h-105{height:calc(var(--spacing) * 105)}.h-\[18px\]{height:18px}.h-\[54px\]{height:54px}.h-\[66vh\]{height:66vh}.h-\[clamp\(300px\,calc\(100dvh-420px\)\,1200px\)\]{height:clamp(300px,100dvh - 420px,1200px)}.h-\[min\(700px\,80vh\)\]{height:min(700px,80vh)}.h-auto{height:auto}.h-full{height:100%}.h-px{height:1px}.max-h-\(--radix-dropdown-menu-content-available-height\){max-height:var(--radix-dropdown-menu-content-available-height)}.max-h-\(--radix-popover-content-available-height\){max-height:var(--radix-popover-content-available-height)}.max-h-\(--radix-select-content-available-height\){max-height:var(--radix-select-content-available-height)}.max-h-55{max-height:calc(var(--spacing) * 55)}.max-h-64{max-height:calc(var(--spacing) * 64)}.max-h-65{max-height:calc(var(--spacing) * 65)}.max-h-96{max-height:calc(var(--spacing) * 96)}.max-h-120{max-height:calc(var(--spacing) * 120)}.max-h-\[46vh\]{max-height:46vh}.max-h-\[80vh\]{max-height:80vh}.max-h-\[82vh\]{max-height:82vh}.max-h-\[260px\]{max-height:260px}.max-h-\[340px\]{max-height:340px}.max-h-\[calc\(100vh-320px\)\]{max-height:calc(100vh - 320px)}.max-h-\[clamp\(300px\,calc\(100dvh-340px\)\,1200px\)\]{max-height:clamp(300px,100dvh - 340px,1200px)}.min-h-\(--control-h\){min-height:var(--control-h)}.min-h-0{min-height:0}.min-h-7\.5{min-height:calc(var(--spacing) * 7.5)}.min-h-10{min-height:calc(var(--spacing) * 10)}.min-h-11{min-height:calc(var(--spacing) * 11)}.min-h-12{min-height:calc(var(--spacing) * 12)}.min-h-14{min-height:calc(var(--spacing) * 14)}.min-h-16{min-height:calc(var(--spacing) * 16)}.min-h-24{min-height:calc(var(--spacing) * 24)}.min-h-38{min-height:calc(var(--spacing) * 38)}.min-h-65{min-height:calc(var(--spacing) * 65)}.w-\(--artifact-w\){width:var(--artifact-w)}.w-\(--maprail-w\){width:var(--maprail-w)}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-2{width:calc(var(--spacing) * 2)}.w-2\.5{width:calc(var(--spacing) * 2.5)}.w-3\.5{width:calc(var(--spacing) * 3.5)}.w-4{width:calc(var(--spacing) * 4)}.w-5\.5{width:calc(var(--spacing) * 5.5)}.w-6{width:calc(var(--spacing) * 6)}.w-9{width:calc(var(--spacing) * 9)}.w-10{width:calc(var(--spacing) * 10)}.w-11{width:calc(var(--spacing) * 11)}.w-20{width:calc(var(--spacing) * 20)}.w-23{width:calc(var(--spacing) * 23)}.w-24{width:calc(var(--spacing) * 24)}.w-30{width:calc(var(--spacing) * 30)}.w-40{width:calc(var(--spacing) * 40)}.w-48{width:calc(var(--spacing) * 48)}.w-75{width:calc(var(--spacing) * 75)}.w-80{width:calc(var(--spacing) * 80)}.w-90{width:calc(var(--spacing) * 90)}.w-105{width:calc(var(--spacing) * 105)}.w-\[230px\]{width:230px}.w-\[300px\]{width:300px}.w-fit{width:fit-content}.w-full{width:100%}.max-w-\(--radix-popover-content-available-width\){max-width:var(--radix-popover-content-available-width)}.max-w-56{max-width:calc(var(--spacing) * 56)}.max-w-60{max-width:calc(var(--spacing) * 60)}.max-w-85{max-width:calc(var(--spacing) * 85)}.max-w-90{max-width:calc(var(--spacing) * 90)}.max-w-95{max-width:calc(var(--spacing) * 95)}.max-w-140{max-width:calc(var(--spacing) * 140)}.max-w-\[34vw\]{max-width:34vw}.max-w-\[36ch\]{max-width:36ch}.max-w-\[42ch\]{max-width:42ch}.max-w-\[46ch\]{max-width:46ch}.max-w-\[52ch\]{max-width:52ch}.max-w-\[56ch\]{max-width:56ch}.max-w-\[60ch\]{max-width:60ch}.max-w-\[62ch\]{max-width:62ch}.max-w-\[68ch\]{max-width:68ch}.max-w-\[80\%\]{max-width:80%}.max-w-\[460px\]{max-width:460px}.max-w-\[560px\]{max-width:560px}.max-w-\[620px\]{max-width:620px}.max-w-\[640px\]{max-width:640px}.max-w-\[780px\]{max-width:780px}.max-w-\[940px\]{max-width:940px}.max-w-\[1100px\]{max-width:1100px}.max-w-\[calc\(var\(--content-max\)\+56px\)\]{max-width:calc(var(--content-max) + 56px)}.max-w-full{max-width:100%}.min-w-\(--radix-select-trigger-width\){min-width:var(--radix-select-trigger-width)}.min-w-0{min-width:0}.min-w-5{min-width:calc(var(--spacing) * 5)}.min-w-32{min-width:calc(var(--spacing) * 32)}.min-w-40{min-width:calc(var(--spacing) * 40)}.min-w-56{min-width:calc(var(--spacing) * 56)}.min-w-60{min-width:calc(var(--spacing) * 60)}.min-w-64{min-width:calc(var(--spacing) * 64)}.flex-1{flex:1}.flex-none{flex:none}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.basis-\[26rem\]{flex-basis:26rem}.basis-full{flex-basis:100%}.border-collapse{border-collapse:collapse}.-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.rotate-90{rotate:90deg}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-\[backdropIn_var\(--dur-2\)_var\(--ease-out-app\)\]{animation:backdropIn var(--dur-2) var(--ease-out-app)}.animate-\[cmdkIn_var\(--dur-2\)_var\(--ease-out-app\)\]{animation:cmdkIn var(--dur-2) var(--ease-out-app)}.animate-\[dotGlow_2\.4s_ease-in-out_infinite\]{animation:2.4s ease-in-out infinite dotGlow}.animate-\[fadeUp_220ms_ease-out\]{animation:.22s ease-out fadeUp}.animate-\[fadeUp_var\(--dur-2\)_var\(--ease-out-app\)\]{animation:fadeUp var(--dur-2) var(--ease-out-app)}.animate-\[fadeUp_var\(--dur-3\)_ease-out\]{animation:fadeUp var(--dur-3) ease-out}.animate-\[popIn_var\(--dur-3\)_ease-out\]{animation:popIn var(--dur-3) ease-out}.animate-\[pulse_1\.1s_ease-in-out_infinite\]{animation:1.1s ease-in-out infinite pulse}.animate-\[pulse_1\.3s_ease-in-out_infinite\]{animation:1.3s ease-in-out infinite pulse}.animate-\[pulse_1\.4s_ease-in-out_infinite\]{animation:1.4s ease-in-out infinite pulse}.animate-\[pulse_1\.5s_ease-in-out_infinite\]{animation:1.5s ease-in-out infinite pulse}.animate-\[pulse_1s_ease-in-out_infinite\]{animation:1s ease-in-out infinite pulse}.animate-\[spin_1\.2s_linear_infinite\]{animation:1.2s linear infinite spin}.animate-backdrop-in{animation:var(--animate-backdrop-in)}.animate-dot-glow{animation:var(--animate-dot-glow)}.animate-overlay-in{animation:var(--animate-overlay-in)}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.animate-toast-in{animation:var(--animate-toast-in)}.cursor-col-resize{cursor:col-resize}.cursor-crosshair{cursor:crosshair}.cursor-default{cursor:default}.cursor-help{cursor:help}.cursor-pointer{cursor:pointer}.cursor-text{cursor:text}.touch-none{touch-action:none}.resize{resize:both}.resize-none{resize:none}.resize-y{resize:vertical}.list-disc{list-style-type:disc}.list-none{list-style-type:none}.appearance-none{appearance:none}.grid-cols-\[1fr_250px_84px_24px\]{grid-template-columns:1fr 250px 84px 24px}.grid-cols-\[1fr_auto_auto\]{grid-template-columns:1fr auto auto}.grid-cols-\[18px_minmax\(160px\,1fr\)_auto\]{grid-template-columns:18px minmax(160px,1fr) auto}.grid-cols-\[168px_86px_minmax\(140px\,1fr\)_118px_92px_24px\]{grid-template-columns:168px 86px minmax(140px,1fr) 118px 92px 24px}.grid-cols-\[184px_1fr\]{grid-template-columns:184px 1fr}.grid-cols-\[210px_1fr\]{grid-template-columns:210px 1fr}.grid-cols-\[auto_1fr\]{grid-template-columns:auto 1fr}.grid-cols-\[minmax\(0\,1fr\)_150px_minmax\(0\,1\.2fr\)_auto\]{grid-template-columns:minmax(0,1fr) 150px minmax(0,1.2fr) auto}.grid-cols-\[repeat\(auto-fill\,minmax\(280px\,1fr\)\)\]{grid-template-columns:repeat(auto-fill,minmax(280px,1fr))}.grid-cols-\[var\(--sidebar-w\)_1fr\]{grid-template-columns:var(--sidebar-w) 1fr}.grid-cols-\[var\(--sidebar-w\)_1fr_var\(--inspector-w\)\]{grid-template-columns:var(--sidebar-w) 1fr var(--inspector-w)}.grid-rows-\[44px_1fr_28px\]{grid-template-rows:44px 1fr 28px}.grid-rows-\[48px_minmax\(0\,1fr\)\]{grid-template-rows:48px minmax(0,1fr)}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-start{justify-content:flex-start}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-5\.5{gap:calc(var(--spacing) * 5.5)}.gap-6{gap:calc(var(--spacing) * 6)}.gap-8{gap:calc(var(--spacing) * 8)}.gap-\[7px\]{gap:7px}.gap-\[9px\]{gap:9px}.gap-\[18px\]{gap:18px}.gap-px{gap:1px}.gap-x-2\.5{column-gap:calc(var(--spacing) * 2.5)}.gap-x-4{column-gap:calc(var(--spacing) * 4)}.gap-x-4\.5{column-gap:calc(var(--spacing) * 4.5)}.gap-y-1{row-gap:var(--spacing)}.gap-y-1\.5{row-gap:calc(var(--spacing) * 1.5)}.gap-y-2{row-gap:calc(var(--spacing) * 2)}.self-center{align-self:center}.self-end{align-self:flex-end}.self-start{align-self:flex-start}.justify-self-center{justify-self:center}.justify-self-start{justify-self:flex-start}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-clip{overflow:clip}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.overscroll-contain{overscroll-behavior:contain}.rounded-\[2px\]{border-radius:2px}.rounded-\[3px\]{border-radius:3px}.rounded-\[4px\]{border-radius:4px}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-pill{border-radius:var(--radius-pill)}.rounded-sm{border-radius:var(--radius-sm)}.rounded-tl-sm{border-top-left-radius:var(--radius-sm)}.rounded-r-md{border-top-right-radius:var(--radius-md);border-bottom-right-radius:var(--radius-md)}.rounded-tr-sm{border-top-right-radius:var(--radius-sm)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-\[1\.4px\]{border-style:var(--tw-border-style);border-width:1.4px}.border-\[1\.6px\]{border-style:var(--tw-border-style);border-width:1.6px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-accent{border-color:var(--color-accent)}.border-accent-line{border-color:var(--color-accent-line)}.border-danger{border-color:var(--color-danger)}.border-danger\/30{border-color:#f4594e4d}@supports (color:color-mix(in lab, red, red)){.border-danger\/30{border-color:color-mix(in oklab, var(--color-danger) 30%, transparent)}}.border-danger\/35{border-color:#f4594e59}@supports (color:color-mix(in lab, red, red)){.border-danger\/35{border-color:color-mix(in oklab, var(--color-danger) 35%, transparent)}}.border-danger\/40{border-color:#f4594e66}@supports (color:color-mix(in lab, red, red)){.border-danger\/40{border-color:color-mix(in oklab, var(--color-danger) 40%, transparent)}}.border-danger\/45{border-color:#f4594e73}@supports (color:color-mix(in lab, red, red)){.border-danger\/45{border-color:color-mix(in oklab, var(--color-danger) 45%, transparent)}}.border-danger\/55{border-color:#f4594e8c}@supports (color:color-mix(in lab, red, red)){.border-danger\/55{border-color:color-mix(in oklab, var(--color-danger) 55%, transparent)}}.border-drive\/35{border-color:#58a6ff59}@supports (color:color-mix(in lab, red, red)){.border-drive\/35{border-color:color-mix(in oklab, var(--color-drive) 35%, transparent)}}.border-drive\/40{border-color:#58a6ff66}@supports (color:color-mix(in lab, red, red)){.border-drive\/40{border-color:color-mix(in oklab, var(--color-drive) 40%, transparent)}}.border-hairline{border-color:var(--color-hairline)}.border-hairline-soft{border-color:var(--color-hairline-soft)}.border-hairline-strong{border-color:var(--color-hairline-strong)}.border-needs\/40{border-color:#d7a94a66}@supports (color:color-mix(in lab, red, red)){.border-needs\/40{border-color:color-mix(in oklab, var(--color-needs) 40%, transparent)}}.border-ok\/30{border-color:#3fb9504d}@supports (color:color-mix(in lab, red, red)){.border-ok\/30{border-color:color-mix(in oklab, var(--color-ok) 30%, transparent)}}.border-ok\/35{border-color:#3fb95059}@supports (color:color-mix(in lab, red, red)){.border-ok\/35{border-color:color-mix(in oklab, var(--color-ok) 35%, transparent)}}.border-ok\/40{border-color:#3fb95066}@supports (color:color-mix(in lab, red, red)){.border-ok\/40{border-color:color-mix(in oklab, var(--color-ok) 40%, transparent)}}.border-ok\/45{border-color:#3fb95073}@supports (color:color-mix(in lab, red, red)){.border-ok\/45{border-color:color-mix(in oklab, var(--color-ok) 45%, transparent)}}.border-ok\/50{border-color:#3fb95080}@supports (color:color-mix(in lab, red, red)){.border-ok\/50{border-color:color-mix(in oklab, var(--color-ok) 50%, transparent)}}.border-ph-implementation{border-color:var(--color-ph-implementation)}.border-ph-implementation\/45{border-color:#f0883e73}@supports (color:color-mix(in lab, red, red)){.border-ph-implementation\/45{border-color:color-mix(in oklab, var(--color-ph-implementation) 45%, transparent)}}.border-ph-review\/40{border-color:#58a6ff66}@supports (color:color-mix(in lab, red, red)){.border-ph-review\/40{border-color:color-mix(in oklab, var(--color-ph-review) 40%, transparent)}}.border-transparent{border-color:#0000}.border-warn{border-color:var(--color-warn)}.border-warn\/35{border-color:#d7a94a59}@supports (color:color-mix(in lab, red, red)){.border-warn\/35{border-color:color-mix(in oklab, var(--color-warn) 35%, transparent)}}.border-warn\/40{border-color:#d7a94a66}@supports (color:color-mix(in lab, red, red)){.border-warn\/40{border-color:color-mix(in oklab, var(--color-warn) 40%, transparent)}}.border-warn\/45{border-color:#d7a94a73}@supports (color:color-mix(in lab, red, red)){.border-warn\/45{border-color:color-mix(in oklab, var(--color-warn) 45%, transparent)}}.border-t-accent{border-top-color:var(--color-accent)}.border-t-transparent{border-top-color:#0000}.border-b-accent{border-bottom-color:var(--color-accent)}.border-b-transparent{border-bottom-color:#0000}.border-l-accent-line{border-left-color:var(--color-accent-line)}.border-l-danger{border-left-color:var(--color-danger)}.border-l-hairline{border-left-color:var(--color-hairline)}.border-l-hairline-strong{border-left-color:var(--color-hairline-strong)}.border-l-ok{border-left-color:var(--color-ok)}.border-l-ph-implementation{border-left-color:var(--color-ph-implementation)}.border-l-warn{border-left-color:var(--color-warn)}.bg-\[rgba\(4\,6\,10\,0\.55\)\]{background-color:#04060a8c}.bg-accent{background-color:var(--color-accent)}.bg-accent-hi{background-color:var(--color-accent-hi)}.bg-accent-line{background-color:var(--color-accent-line)}.bg-accent-soft{background-color:var(--color-accent-soft)}.bg-accent\/12{background-color:#7c6cf61f}@supports (color:color-mix(in lab, red, red)){.bg-accent\/12{background-color:color-mix(in oklab, var(--color-accent) 12%, transparent)}}.bg-bg{background-color:var(--color-bg)}.bg-bg\/15{background-color:#090b1026}@supports (color:color-mix(in lab, red, red)){.bg-bg\/15{background-color:color-mix(in oklab, var(--color-bg) 15%, transparent)}}.bg-bg\/55{background-color:#090b108c}@supports (color:color-mix(in lab, red, red)){.bg-bg\/55{background-color:color-mix(in oklab, var(--color-bg) 55%, transparent)}}.bg-bg\/70{background-color:#090b10b3}@supports (color:color-mix(in lab, red, red)){.bg-bg\/70{background-color:color-mix(in oklab, var(--color-bg) 70%, transparent)}}.bg-bg\/85{background-color:#090b10d9}@supports (color:color-mix(in lab, red, red)){.bg-bg\/85{background-color:color-mix(in oklab, var(--color-bg) 85%, transparent)}}.bg-current{background-color:currentColor}.bg-danger{background-color:var(--color-danger)}.bg-danger\/5{background-color:#f4594e0d}@supports (color:color-mix(in lab, red, red)){.bg-danger\/5{background-color:color-mix(in oklab, var(--color-danger) 5%, transparent)}}.bg-danger\/6{background-color:#f4594e0f}@supports (color:color-mix(in lab, red, red)){.bg-danger\/6{background-color:color-mix(in oklab, var(--color-danger) 6%, transparent)}}.bg-danger\/8{background-color:#f4594e14}@supports (color:color-mix(in lab, red, red)){.bg-danger\/8{background-color:color-mix(in oklab, var(--color-danger) 8%, transparent)}}.bg-danger\/9{background-color:#f4594e17}@supports (color:color-mix(in lab, red, red)){.bg-danger\/9{background-color:color-mix(in oklab, var(--color-danger) 9%, transparent)}}.bg-danger\/15{background-color:#f4594e26}@supports (color:color-mix(in lab, red, red)){.bg-danger\/15{background-color:color-mix(in oklab, var(--color-danger) 15%, transparent)}}.bg-drive{background-color:var(--color-drive)}.bg-drive\/10{background-color:#58a6ff1a}@supports (color:color-mix(in lab, red, red)){.bg-drive\/10{background-color:color-mix(in oklab, var(--color-drive) 10%, transparent)}}.bg-hairline{background-color:var(--color-hairline)}.bg-hairline-soft{background-color:var(--color-hairline-soft)}.bg-hairline-strong{background-color:var(--color-hairline-strong)}.bg-needs{background-color:var(--color-needs)}.bg-ok{background-color:var(--color-ok)}.bg-ok\/10{background-color:#3fb9501a}@supports (color:color-mix(in lab, red, red)){.bg-ok\/10{background-color:color-mix(in oklab, var(--color-ok) 10%, transparent)}}.bg-panel{background-color:var(--color-panel)}.bg-panel-2{background-color:var(--color-panel-2)}.bg-panel-3{background-color:var(--color-panel-3)}.bg-panel-inset{background-color:var(--color-panel-inset)}.bg-panel\/90{background-color:#0e1117e6}@supports (color:color-mix(in lab, red, red)){.bg-panel\/90{background-color:color-mix(in oklab, var(--color-panel) 90%, transparent)}}.bg-panel\/95{background-color:#0e1117f2}@supports (color:color-mix(in lab, red, red)){.bg-panel\/95{background-color:color-mix(in oklab, var(--color-panel) 95%, transparent)}}.bg-ph-ideation{background-color:var(--color-ph-ideation)}.bg-ph-implementation{background-color:var(--color-ph-implementation)}.bg-ph-implementation\/8{background-color:#f0883e14}@supports (color:color-mix(in lab, red, red)){.bg-ph-implementation\/8{background-color:color-mix(in oklab, var(--color-ph-implementation) 8%, transparent)}}.bg-ph-review{background-color:var(--color-ph-review)}.bg-ph-review\/8{background-color:#58a6ff14}@supports (color:color-mix(in lab, red, red)){.bg-ph-review\/8{background-color:color-mix(in oklab, var(--color-ph-review) 8%, transparent)}}.bg-ph-shipped{background-color:var(--color-ph-shipped)}.bg-ph-spec{background-color:var(--color-ph-spec)}.bg-ph-tickets{background-color:var(--color-ph-tickets)}.bg-text-3{background-color:var(--color-text-3)}.bg-text-4{background-color:var(--color-text-4)}.bg-transparent{background-color:#0000}.bg-warn{background-color:var(--color-warn)}.bg-warn\/7{background-color:#d7a94a12}@supports (color:color-mix(in lab, red, red)){.bg-warn\/7{background-color:color-mix(in oklab, var(--color-warn) 7%, transparent)}}.bg-warn\/8{background-color:#d7a94a14}@supports (color:color-mix(in lab, red, red)){.bg-warn\/8{background-color:color-mix(in oklab, var(--color-warn) 8%, transparent)}}.object-contain{object-fit:contain}.object-cover{object-fit:cover}.p-0{padding:0}.p-0\.5{padding:calc(var(--spacing) * .5)}.p-1{padding:var(--spacing)}.p-1\.5{padding:calc(var(--spacing) * 1.5)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.px-0{padding-inline:0}.px-0\.5{padding-inline:calc(var(--spacing) * .5)}.px-1{padding-inline:var(--spacing)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-3\.5{padding-inline:calc(var(--spacing) * 3.5)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-4\.5{padding-inline:calc(var(--spacing) * 4.5)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-5\.5{padding-inline:calc(var(--spacing) * 5.5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-7{padding-inline:calc(var(--spacing) * 7)}.px-\[7px\]{padding-inline:7px}.px-\[9px\]{padding-inline:9px}.px-\[11px\]{padding-inline:11px}.px-\[clamp\(20px\,6vw\,72px\)\]{padding-inline:clamp(20px,6vw,72px)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-3\.5{padding-block:calc(var(--spacing) * 3.5)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-7{padding-block:calc(var(--spacing) * 7)}.py-10{padding-block:calc(var(--spacing) * 10)}.py-11{padding-block:calc(var(--spacing) * 11)}.py-\[5px\]{padding-block:5px}.py-\[7px\]{padding-block:7px}.py-px{padding-block:1px}.pt-1{padding-top:var(--spacing)}.pt-1\.5{padding-top:calc(var(--spacing) * 1.5)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-2\.5{padding-top:calc(var(--spacing) * 2.5)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pt-4\.5{padding-top:calc(var(--spacing) * 4.5)}.pt-6{padding-top:calc(var(--spacing) * 6)}.pt-10{padding-top:calc(var(--spacing) * 10)}.pt-12{padding-top:calc(var(--spacing) * 12)}.pt-\[8vh\]{padding-top:8vh}.pt-\[12vh\]{padding-top:12vh}.pr-1{padding-right:var(--spacing)}.pr-2{padding-right:calc(var(--spacing) * 2)}.pr-3{padding-right:calc(var(--spacing) * 3)}.pr-7{padding-right:calc(var(--spacing) * 7)}.pb-0\.5{padding-bottom:calc(var(--spacing) * .5)}.pb-1{padding-bottom:var(--spacing)}.pb-1\.5{padding-bottom:calc(var(--spacing) * 1.5)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-2\.5{padding-bottom:calc(var(--spacing) * 2.5)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pb-7{padding-bottom:calc(var(--spacing) * 7)}.pb-8{padding-bottom:calc(var(--spacing) * 8)}.pb-14{padding-bottom:calc(var(--spacing) * 14)}.pl-0\.5{padding-left:calc(var(--spacing) * .5)}.pl-2\.5{padding-left:calc(var(--spacing) * 2.5)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-4{padding-left:calc(var(--spacing) * 4)}.pl-5{padding-left:calc(var(--spacing) * 5)}.pl-5\.5{padding-left:calc(var(--spacing) * 5.5)}.pl-6{padding-left:calc(var(--spacing) * 6)}.pl-7{padding-left:calc(var(--spacing) * 7)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.align-\[-1px\]{vertical-align:-1px}.font-mono{font-family:var(--font-mono)}.font-sans{font-family:var(--font-sans)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[9\.5px\]{font-size:9.5px}.text-\[10\.5px\]{font-size:10.5px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.leading-4{--tw-leading:calc(var(--spacing) * 4);line-height:calc(var(--spacing) * 4)}.leading-5{--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5)}.leading-6{--tw-leading:calc(var(--spacing) * 6);line-height:calc(var(--spacing) * 6)}.leading-\[1\.45\]{--tw-leading:1.45;line-height:1.45}.leading-none{--tw-leading:1;line-height:1}.leading-normal{--tw-leading:var(--leading-normal);line-height:var(--leading-normal)}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[-0\.01em\]{--tw-tracking:-.01em;letter-spacing:-.01em}.tracking-\[0\.1em\]{--tw-tracking:.1em;letter-spacing:.1em}.tracking-\[0\.04em\]{--tw-tracking:.04em;letter-spacing:.04em}.tracking-\[0\.06em\]{--tw-tracking:.06em;letter-spacing:.06em}.tracking-\[0\.07em\]{--tw-tracking:.07em;letter-spacing:.07em}.tracking-\[0\.08em\]{--tw-tracking:.08em;letter-spacing:.08em}.tracking-\[0\.09em\]{--tw-tracking:.09em;letter-spacing:.09em}.tracking-\[0\.12em\]{--tw-tracking:.12em;letter-spacing:.12em}.tracking-normal{--tw-tracking:var(--tracking-normal);letter-spacing:var(--tracking-normal)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.text-pretty{text-wrap:pretty}.break-words{overflow-wrap:break-word}.text-ellipsis{text-overflow:ellipsis}.whitespace-normal{white-space:normal}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-accent{color:var(--color-accent)}.text-accent-2{color:var(--color-accent-2)}.text-accent-hi{color:var(--color-accent-hi)}.text-accent-ink{color:var(--color-accent-ink)}.text-danger{color:var(--color-danger)}.text-drive{color:var(--color-drive)}.text-needs{color:var(--color-needs)}.text-ok{color:var(--color-ok)}.text-ph-ideation{color:var(--color-ph-ideation)}.text-ph-implementation{color:var(--color-ph-implementation)}.text-ph-review{color:var(--color-ph-review)}.text-ph-shipped{color:var(--color-ph-shipped)}.text-ph-spec{color:var(--color-ph-spec)}.text-ph-tickets{color:var(--color-ph-tickets)}.text-text{color:var(--color-text)}.text-text-2{color:var(--color-text-2)}.text-text-3{color:var(--color-text-3)}.text-text-4{color:var(--color-text-4)}.text-warn{color:var(--color-warn)}.capitalize{text-transform:capitalize}.lowercase{text-transform:lowercase}.normal-case{text-transform:none}.uppercase{text-transform:uppercase}.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,)}.line-through{text-decoration-line:line-through}.no-underline{text-decoration-line:none}.underline{text-decoration-line:underline}.decoration-accent-line{-webkit-text-decoration-color:var(--color-accent-line);-webkit-text-decoration-color:var(--color-accent-line);-webkit-text-decoration-color:var(--color-accent-line);text-decoration-color:var(--color-accent-line)}.decoration-dotted{text-decoration-style:dotted}.underline-offset-2{text-underline-offset:2px}.accent-accent{accent-color:var(--color-accent)}.opacity-0{opacity:0}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.opacity-85{opacity:.85}.opacity-100{opacity:1}.shadow-\[0_0_0_3px_rgba\(124\,108\,246\,0\.2\)\]{--tw-shadow:0 0 0 3px var(--tw-shadow-color,#7c6cf633);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_12px_30px_-14px_rgba\(0\,0\,0\,0\.8\)\]{--tw-shadow:0 12px 30px -14px var(--tw-shadow-color,#000c);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-menu{--tw-shadow:0 8px 28px -10px var(--tw-shadow-color,#000000b3), 0 2px 8px -2px var(--tw-shadow-color,#00000080);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-overlay{--tw-shadow:0 24px 70px -24px var(--tw-shadow-color,#000000d9), 0 8px 24px -12px var(--tw-shadow-color,#0009);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-3{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.inset-ring,.inset-ring-1{--tw-inset-ring-shadow:inset 0 0 0 1px var(--tw-inset-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-ok\/15{--tw-ring-color:#3fb95026}@supports (color:color-mix(in lab, red, red)){.ring-ok\/15{--tw-ring-color:color-mix(in oklab, var(--color-ok) 15%, transparent)}}.ring-warn\/15{--tw-ring-color:#d7a94a26}@supports (color:color-mix(in lab, red, red)){.ring-warn\/15{--tw-ring-color:color-mix(in oklab, var(--color-warn) 15%, transparent)}}.inset-ring-accent-line{--tw-inset-ring-color:var(--color-accent-line)}.inset-ring-text-4{--tw-inset-ring-color:var(--color-text-4)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.outline-2{outline-style:var(--tw-outline-style);outline-width:2px}.outline-offset-2{outline-offset:2px}.outline-accent{outline-color:var(--color-accent)}.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,)}.backdrop-blur-\[2px\]{--tw-backdrop-blur:blur(2px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[background-color\,color\,border-color\]{transition-property:background-color,color,border-color;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[border-color\,background-color\]{transition-property:border-color,background-color;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[border-color\]{transition-property:border-color;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[color\,background-color\,border-color\,box-shadow\,transform\,opacity\]{transition-property:color,background-color,border-color,box-shadow,transform,opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[color\,background-color\,border-color\]{transition-property:color,background-color,border-color;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[opacity\,box-shadow\]{transition-property:opacity,box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-\(--dur-1\){--tw-duration:var(--dur-1);transition-duration:var(--dur-1)}.duration-\(--dur-2\){--tw-duration:var(--dur-2);transition-duration:var(--dur-2)}.ease-app{--tw-ease:var(--ease-app);transition-timing-function:var(--ease-app)}.ease-out-app{--tw-ease:var(--ease-out-app);transition-timing-function:var(--ease-out-app)}.outline-none{--tw-outline-style:none;outline-style:none}.select-all{-webkit-user-select:all;user-select:all}.select-none{-webkit-user-select:none;user-select:none}.\[writing-mode\:vertical-rl\]{writing-mode:vertical-rl}.group-focus-within\:opacity-100:is(:where(.group):focus-within *){opacity:1}.group-focus-within\/info\:block:is(:where(.group\/info):focus-within *){display:block}@media (hover:hover){.group-hover\:border-hairline:is(:where(.group):hover *){border-color:var(--color-hairline)}.group-hover\:text-text:is(:where(.group):hover *){color:var(--color-text)}.group-hover\:text-text-2:is(:where(.group):hover *){color:var(--color-text-2)}.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}.group-hover\/info\:block:is(:where(.group\/info):hover *){display:block}.peer-hover\:visible:is(:where(.peer):hover~*){visibility:visible}}.peer-focus-visible\:visible:is(:where(.peer):focus-visible~*){visibility:visible}.marker\:text-text-4 ::marker{color:var(--color-text-4)}.marker\:text-text-4::marker{color:var(--color-text-4)}.marker\:text-text-4 ::-webkit-details-marker{color:var(--color-text-4)}.marker\:text-text-4::-webkit-details-marker{color:var(--color-text-4)}.placeholder\:text-text-3::placeholder{color:var(--color-text-3)}.placeholder\:text-text-4::placeholder{color:var(--color-text-4)}.placeholder\:italic::placeholder{font-style:italic}.before\:shrink-0:before{content:var(--tw-content);flex-shrink:0}.before\:text-text-4:before{content:var(--tw-content);color:var(--color-text-4)}.before\:content-\[\'▸\'\]:before{--tw-content:"▸";content:var(--tw-content)}.group-open\:before\:content-\[\'▾\'\]:is(:where(.group):is([open],:popover-open,:open) *):before{--tw-content:"▾";content:var(--tw-content)}.first\:mt-2:first-child{margin-top:calc(var(--spacing) * 2)}.first\:border-t-0:first-child{border-top-style:var(--tw-border-style);border-top-width:0}.first\:pt-0:first-child{padding-top:0}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}@media (hover:hover){.hover\:border-accent-line:hover{border-color:var(--color-accent-line)}.hover\:border-hairline:hover{border-color:var(--color-hairline)}.hover\:border-hairline-strong:hover{border-color:var(--color-hairline-strong)}.hover\:border-text-3:hover{border-color:var(--color-text-3)}.hover\:bg-accent-line:hover{background-color:var(--color-accent-line)}.hover\:bg-accent-soft:hover{background-color:var(--color-accent-soft)}.hover\:bg-danger\/12:hover{background-color:#f4594e1f}@supports (color:color-mix(in lab, red, red)){.hover\:bg-danger\/12:hover{background-color:color-mix(in oklab, var(--color-danger) 12%, transparent)}}.hover\:bg-panel:hover{background-color:var(--color-panel)}.hover\:bg-panel-3:hover{background-color:var(--color-panel-3)}.hover\:bg-panel-inset:hover{background-color:var(--color-panel-inset)}.hover\:text-accent:hover{color:var(--color-accent)}.hover\:text-accent-2:hover{color:var(--color-accent-2)}.hover\:text-accent-hi:hover{color:var(--color-accent-hi)}.hover\:text-danger:hover{color:var(--color-danger)}.hover\:text-text:hover{color:var(--color-text)}.hover\:text-text-2:hover{color:var(--color-text-2)}.hover\:underline:hover{text-decoration-line:underline}.hover\:decoration-accent-hi:hover{-webkit-text-decoration-color:var(--color-accent-hi);-webkit-text-decoration-color:var(--color-accent-hi);-webkit-text-decoration-color:var(--color-accent-hi);text-decoration-color:var(--color-accent-hi)}.hover\:opacity-100:hover{opacity:1}}.focus\:border-accent:focus{border-color:var(--color-accent)}.focus\:border-accent-line:focus{border-color:var(--color-accent-line)}.focus\:border-danger:focus{border-color:var(--color-danger)}.focus\:bg-panel-inset:focus{background-color:var(--color-panel-inset)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus-visible\:opacity-100:focus-visible{opacity:1}.active\:scale-\[0\.97\]:active{scale:.97}@media (hover:hover){.enabled\:hover\:border-accent-2:enabled:hover{border-color:var(--color-accent-2)}.enabled\:hover\:border-danger:enabled:hover{border-color:var(--color-danger)}.enabled\:hover\:border-hairline:enabled:hover{border-color:var(--color-hairline)}.enabled\:hover\:border-hairline-strong:enabled:hover{border-color:var(--color-hairline-strong)}.enabled\:hover\:bg-accent-2:enabled:hover{background-color:var(--color-accent-2)}.enabled\:hover\:bg-danger\/12:enabled:hover{background-color:#f4594e1f}@supports (color:color-mix(in lab, red, red)){.enabled\:hover\:bg-danger\/12:enabled:hover{background-color:color-mix(in oklab, var(--color-danger) 12%, transparent)}}.enabled\:hover\:bg-panel:enabled:hover{background-color:var(--color-panel)}.enabled\:hover\:bg-panel-3:enabled:hover{background-color:var(--color-panel-3)}.enabled\:hover\:text-text:enabled:hover{color:var(--color-text)}}.enabled\:active\:scale-\[0\.99\]:enabled:active{scale:.99}.disabled\:cursor-default:disabled{cursor:default}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:bg-panel-2:disabled{background-color:var(--color-panel-2)}.disabled\:text-text-3:disabled{color:var(--color-text-3)}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.aria-\[current\=true\]\:text-text[aria-current=true]{color:var(--color-text)}.data-disabled\:cursor-not-allowed[data-disabled]{cursor:not-allowed}.data-disabled\:opacity-40[data-disabled]{opacity:.4}.data-highlighted\:bg-accent-soft[data-highlighted]{background-color:var(--color-accent-soft)}.data-highlighted\:bg-danger\/12[data-highlighted]{background-color:#f4594e1f}@supports (color:color-mix(in lab, red, red)){.data-highlighted\:bg-danger\/12[data-highlighted]{background-color:color-mix(in oklab, var(--color-danger) 12%, transparent)}}.data-highlighted\:text-text[data-highlighted]{color:var(--color-text)}.data-\[selected\=true\]\:bg-accent-soft[data-selected=true]{background-color:var(--color-accent-soft)}.data-\[selected\=true\]\:text-text[data-selected=true],.data-\[state\=checked\]\:text-text[data-state=checked]{color:var(--color-text)}.\[\&_li\]\:rounded-pill li{border-radius:var(--radius-pill)}.\[\&_li\]\:border li{border-style:var(--tw-border-style);border-width:1px}.\[\&_li\]\:border-hairline li{border-color:var(--color-hairline)}.\[\&_li\]\:bg-panel-3 li{background-color:var(--color-panel-3)}.\[\&_li\]\:px-2 li{padding-inline:calc(var(--spacing) * 2)}.\[\&_li\]\:py-\[3px\] li{padding-block:3px}.\[\&_li\]\:text-xs li{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.\[\&_li\]\:text-text-3 li{color:var(--color-text-3)}.\[\&\:\:-webkit-details-marker\]\:hidden::-webkit-details-marker{display:none}.\[\&\>\*\+\*\]\:col-start-2>*+*{grid-column-start:2}.\[\&\>\*\+\*\]\:border-t>*+*{border-top-style:var(--tw-border-style);border-top-width:1px}.\[\&\>\*\+\*\]\:border-hairline>*+*{border-color:var(--color-hairline)}.\[\&\>\*\:first-child\]\:mt-0>:first-child{margin-top:0}.\[\&\>\*\:last-child\]\:mb-0>:last-child{margin-bottom:0}.\[\&\>code\]\:border-0>code{border-style:var(--tw-border-style);border-width:0}.\[\&\>code\]\:bg-transparent>code{background-color:#0000}.\[\&\>code\]\:p-0>code{padding:0}.\[\&\>code\]\:text-text-2>code{color:var(--color-text-2)}}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}@keyframes dotGlow{0%,to{box-shadow:0 0 0 3px #7c6cf638}50%{box-shadow:0 0 0 5px #7c6cf614}}@keyframes fadeUp{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}@keyframes bodyIn{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}@keyframes detailIn{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}@keyframes popIn{0%{opacity:0;transform:scale(.96)}to{opacity:1;transform:scale(1)}}@keyframes cmdkIn{0%{opacity:0;transform:translateY(-10px)scale(.985)}to{opacity:1;transform:translateY(0)scale(1)}}@keyframes backdropIn{0%{opacity:0}to{opacity:1}}@keyframes toastIn{0%{opacity:0;transform:translate(16px)scale(.98)}to{opacity:1;transform:translate(0)scale(1)}}@media (prefers-reduced-motion:reduce){*,:before,:after{transition-duration:.001ms!important;animation-duration:.001ms!important;animation-iteration-count:1!important}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}:root{--bg:var(--color-bg);--panel:var(--color-panel);--panel-2:var(--color-panel-2);--panel-3:var(--color-panel-3);--panel-inset:var(--color-panel-inset);--hairline:var(--color-hairline);--hairline-soft:var(--color-hairline-soft);--hairline-strong:var(--color-hairline-strong);--text:var(--color-text);--text-2:var(--color-text-2);--text-3:var(--color-text-3);--text-4:var(--color-text-4);--accent:var(--color-accent);--accent-hi:var(--color-accent-hi);--accent-2:var(--color-accent-2);--accent-ink:var(--color-accent-ink);--accent-soft:var(--color-accent-soft);--accent-line:var(--color-accent-line);--ph-ideation:var(--color-ph-ideation);--ph-spec:var(--color-ph-spec);--ph-tickets:var(--color-ph-tickets);--ph-implementation:var(--color-ph-implementation);--ph-review:var(--color-ph-review);--ph-shipped:var(--color-ph-shipped);--danger:var(--color-danger);--needs:var(--color-needs);--warn:var(--color-warn);--ok:var(--color-ok);--drive:var(--color-drive);--mono:var(--font-mono);--sans:var(--font-sans);--radius:var(--radius-md);--ease:var(--ease-app);--ease-out:var(--ease-out-app)}*{box-sizing:border-box}html,body,#root{height:100%;margin:0;padding:0}body{background:var(--bg);color:var(--text);font-family:var(--sans);font-size:var(--text-base);letter-spacing:.004em;font-feature-settings:"tnum" 1, "cv05" 1;-webkit-font-smoothing:antialiased;text-rendering:optimizelegibility;line-height:1.5;overflow:hidden}button{color:inherit;font-family:inherit}:focus-visible{box-shadow:var(--ring);border-radius:var(--radius-sm);outline:none}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-thumb{background:#1c2230 padding-box padding-box;border:2px solid #0000;border-radius:5px}::-webkit-scrollbar-thumb:hover{background:#2a3242 padding-box padding-box;border:2px solid #0000}::-webkit-scrollbar-track{background:0 0}.mono{font-family:var(--mono);font-size:12.5px}.dim{color:var(--text-3)}.dim-line{color:var(--text-3);font-family:var(--mono);padding:2px 0;font-size:12.5px}.section-title{text-transform:uppercase;letter-spacing:.09em;color:var(--text-3);padding:4px 0;font-size:11px;font-weight:600}.btn{height:var(--control-h);border-radius:var(--radius);border:1px solid var(--hairline);color:var(--text);cursor:pointer;white-space:nowrap;transition:border-color var(--dur-1) var(--ease), background var(--dur-1) var(--ease), color var(--dur-1) var(--ease), transform var(--dur-1) var(--ease), box-shadow var(--dur-2) var(--ease), opacity var(--dur-1);background:0 0;justify-content:center;align-items:center;gap:6px;padding:0 12px;font-size:12.5px;display:inline-flex}.btn:disabled{opacity:.4;cursor:not-allowed}.btn:active:not(:disabled){transform:translateY(.5px)scale(.99)}.btn-ghost:hover:not(:disabled){border-color:var(--hairline-strong);background:var(--panel);color:var(--text)}.btn-solid{background:var(--accent);border-color:var(--accent);color:#fff;font-weight:600}.btn-solid:hover:not(:disabled){background:var(--accent-2);border-color:var(--accent-2);transform:translateY(-1px);box-shadow:0 4px 16px -6px #7c6cf6b3}.btn-solid:active:not(:disabled){box-shadow:none;transform:translateY(0)}.btn-danger{border-color:color-mix(in srgb, var(--danger) 55%, var(--hairline));color:var(--danger)}.btn-danger:hover:not(:disabled){border-color:var(--danger);background:#f4594e1f}.btn-xs{border-radius:var(--radius-sm);height:22px;padding:0 9px;font-size:11.5px}.btn-lg{height:32px;padding:0 16px;font-size:13px}.ghost-link{color:var(--text-2);cursor:pointer;transition:color var(--dur-1) var(--ease);background:0 0;border:none;padding:2px 0;font-size:12.5px}.ghost-link:hover:not(:disabled){color:var(--accent-hi)}.ghost-link:disabled{opacity:.4;cursor:not-allowed}.chip{border-radius:var(--radius-pill);border:1px solid var(--hairline);height:19px;font-family:var(--mono);color:var(--text-2);white-space:nowrap;align-items:center;gap:5px;padding:0 8px;font-size:10.5px;display:inline-flex}.chip-neutral{color:var(--text-2)}.chip-blocked{color:var(--needs);border-color:color-mix(in srgb, var(--needs) 40%, transparent)}.tag{font-family:var(--mono);text-transform:lowercase;font-size:12px;font-weight:600}.spinner,.spin-ring{border:1.6px solid var(--ph-implementation);border-top-color:#0000;border-radius:50%;flex:none;width:12px;height:12px;animation:.8s linear infinite spin;display:inline-block}.wordmark{font-family:var(--mono);letter-spacing:-.25px;white-space:nowrap;font-size:13px;font-weight:600;line-height:1}.wordmark.is-lg{letter-spacing:-.5px;font-size:21px}.wordmark-run{color:var(--accent-hi)}.wordmark-castle{color:var(--text)}.workspace{background:var(--bg);flex-direction:column;min-width:0;min-height:0;display:flex;position:relative}.ws-empty{flex-direction:column;height:100%;display:flex;overflow-y:auto}.ws-empty-inner{min-height:100%;color:var(--text-3);flex-direction:column;justify-content:center;align-items:center;gap:12px;display:flex}.ws-empty-logo{opacity:.85;justify-content:center;align-items:center;display:flex}.ws-empty-title{color:var(--text-2);font-size:14px;font-weight:500}.ws-empty-sub{color:var(--text-3);text-align:center;max-width:40ch;font-size:12.5px}.ws-empty-actions{gap:10px;display:flex}.ws-empty-hint{color:var(--text-4);text-align:center;max-width:44ch;font-size:12px;line-height:1.5}.talk-door{color:var(--text-3);cursor:pointer;border-radius:var(--radius-sm);transition:color var(--dur-1) var(--ease);background:0 0;border:none;padding:2px 4px;font-size:12px}.talk-door:hover:not(:disabled){color:var(--accent-hi)}.talk-door:disabled{opacity:.5;cursor:default}.ws-head,.ws-banner,.ws-body-inner{width:100%;max-width:calc(var(--content-max) + 56px);margin-left:auto;margin-right:auto;padding-left:28px;padding-right:28px}.ws-head{flex:none;padding-top:18px}.ws-title-row{align-items:center;gap:10px;display:flex}.ws-title{letter-spacing:-.01em;color:var(--text);font-size:17px;font-weight:600}.ws-title-spacer{flex:1}.ws-banner{border:1px solid color-mix(in srgb, var(--danger) 55%, var(--hairline));border-radius:var(--radius);background:color-mix(in srgb, var(--danger) 8%, var(--panel-2));color:var(--danger);cursor:pointer;animation:fadeUp var(--dur-2) var(--ease-out);align-items:center;gap:10px;margin-top:10px;padding:8px 14px;font-size:12.5px;display:flex}.ws-banner.is-offline{cursor:default;border-color:color-mix(in srgb, var(--warn,#d9a441) 45%, var(--hairline));background:color-mix(in srgb, var(--warn,#d9a441) 7%, var(--panel-2));color:var(--warn,#d9a441)}.ws-banner.is-offline .ws-banner-tag{border-color:color-mix(in srgb, var(--warn,#d9a441) 40%, var(--hairline))}.ws-banner.is-broken{cursor:default;align-items:flex-start;animation:none}.broken-detail{flex-wrap:wrap;align-items:center;gap:10px;padding:0 14px;display:flex}.ws-banner-tag{font-family:var(--mono);letter-spacing:.06em;border:1px solid color-mix(in srgb, var(--danger) 45%, var(--hairline));border-radius:4px;flex-shrink:0;padding:1px 6px;font-size:10px}.ws-body{flex:1;min-height:0;padding:18px 0 32px;overflow-y:auto}.ws-body-inner{animation:bodyIn var(--dur-3) var(--ease-out)}.body-title{align-items:baseline;gap:10px;margin-bottom:12px;display:flex}.body-title .section-title{padding:0}.body-meta{font-family:var(--mono);color:var(--text-2);font-size:11.5px}.surface{border:1px solid var(--hairline);border-radius:var(--radius-lg);background:var(--panel-2);overflow:hidden}.grill-panel{border:1px solid var(--hairline);border-radius:var(--radius-lg);background:var(--panel-2);flex-direction:column;display:flex;overflow:hidden}.grill-strip{background:var(--panel);border-bottom:1px solid var(--hairline-soft);flex:0 0 34px;align-items:center;gap:10px;height:34px;padding:0 12px;display:flex}.grill-kind{border-radius:var(--radius-pill);border:1px solid var(--accent-line);background:var(--accent-soft);height:18px;color:var(--accent-hi);font-family:var(--mono);align-items:center;padding:0 8px;font-size:10.5px;display:inline-flex}.grill-sid{font-family:var(--mono);color:var(--text-3);font-size:11px}.grill-strip-spacer{flex:1}.grill-term{background:var(--panel-inset);position:relative}.tickets-session{margin-bottom:18px}.tickets-session .grill-term{height:clamp(300px,100dvh - 420px,1200px)}.grill-live-label{color:var(--text-3);font-size:11.5px}.ledger{border:1px solid var(--hairline);border-radius:var(--radius-lg);background:var(--panel-2);overflow:hidden}.ledger-row+.ledger-row{border-top:1px solid var(--hairline-soft)}.ledger-head{cursor:pointer;text-align:left;width:100%;transition:background var(--dur-1);background:0 0;border:none;align-items:center;gap:10px;padding:10px 14px;display:flex}.ledger-head:hover{background:var(--panel-3)}.lg-caret{color:var(--text-4);width:12px;transition:transform var(--dur-2) var(--ease);flex:none;align-items:center;display:inline-flex}.ledger-row.is-open .lg-caret{transform:rotate(90deg)}.lg-title{min-width:0;color:var(--text);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:13px;overflow:hidden}.ledger-detail{background:var(--panel-inset);border-top:1px solid var(--hairline-soft);animation:detailIn var(--dur-2) var(--ease-out);padding:2px 16px 16px 46px;overflow:hidden}.td-section{margin-top:12px}.td-body{color:var(--text);white-space:pre-wrap;word-break:break-word;text-wrap:pretty;max-width:640px;line-height:1.55}.commit-sha{font-family:var(--mono);color:var(--ph-shipped);border:1px solid var(--hairline);cursor:pointer;transition:border-color var(--dur-1);background:0 0;border-radius:4px;padding:1px 6px;font-size:11px}.commit-sha:hover{border-color:var(--ph-shipped)}.drive-pulse{background:var(--drive);border-radius:50%;width:8px;height:8px;animation:1.4s ease-in-out infinite pulse}.shipped-session .grill-term{height:clamp(300px,100dvh - 420px,1200px)}.settings-badge{letter-spacing:.04em;text-transform:uppercase;border:1px solid var(--hairline-strong);color:var(--text-3);border-radius:999px;padding:1px 6px;font-size:9.5px}.settings-badge.is-override{color:var(--accent-hi);border-color:var(--accent-line)}.settings-badge.is-verified{color:var(--ok);border-color:color-mix(in srgb, var(--ok) 40%, transparent)}.settings-badge.is-unverified{color:var(--needs);border-color:color-mix(in srgb, var(--needs) 40%, transparent)}.settings-input{background:var(--panel-inset);border:1px solid var(--hairline);border-radius:var(--radius);width:100%;height:32px;color:var(--text);transition:border-color var(--dur-1);outline:none;padding:0 10px;font-family:inherit;font-size:12.5px}.settings-input:focus{border-color:var(--accent)}.settings-input:disabled{opacity:.6;cursor:progress}.settings-clear{color:var(--text-3);cursor:pointer;text-underline-offset:2px;background:0 0;border:none;align-self:flex-start;margin-top:2px;padding:0;font-size:11px;text-decoration:underline}.settings-clear:hover:not(:disabled){color:var(--accent-hi)}.settings-clear:disabled{opacity:.5;cursor:default}.app-loading{justify-content:center;align-items:center;height:100%;display:flex}
|