@adonis-agora/durable 0.25.0 → 0.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/dist/assets/spa/assets/{index-CV232q_B.js → index-ClD9G7pa.js} +10 -10
- package/dist/assets/spa/assets/index-ClD9G7pa.js.map +1 -0
- package/dist/assets/spa/assets/index-Ds6dCWMa.css +1 -0
- package/dist/assets/spa/index.html +2 -2
- package/dist/src/dashboard/index.d.ts +1 -1
- package/dist/src/dashboard/index.js +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/package.json +5 -2
- package/skills/durable-cluster/SKILL.md +308 -0
- package/skills/durable-determinism/SKILL.md +260 -0
- package/skills/durable-reliability/SKILL.md +352 -0
- package/skills/durable-setup/SKILL.md +293 -0
- package/skills/durable-transports-stores/SKILL.md +296 -0
- package/skills/durable-workflows/SKILL.md +399 -0
- package/dist/assets/spa/assets/index-CTsYsi6p.css +0 -1
- package/dist/assets/spa/assets/index-CV232q_B.js.map +0 -1
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: durable-workflows
|
|
3
|
+
description: >-
|
|
4
|
+
Author durable workflows and steps with @adonis-agora/durable: BaseWorkflow
|
|
5
|
+
classes under app/workflows (static workflow, constructor @inject DI,
|
|
6
|
+
dispatch/start statics, make:workflow), step handlers via @Step decorators,
|
|
7
|
+
defineStep, string names or transport.handle, ctx.localStep vs always-
|
|
8
|
+
dispatched ctx.step, durable sleeps (ctx.sleep/sleepUntil), signals
|
|
9
|
+
(waitForSignal/signal/signalWithStart), named events (waitForEvent/
|
|
10
|
+
publishEvent/eventBatch/onEvent/idempotent opts.id), webhooks (ctx.webhook),
|
|
11
|
+
external tasks (ctx.task/completeTask/failTask), transactional steps
|
|
12
|
+
(ctx.transaction), breakpoints, child workflows (child/startChild/all/
|
|
13
|
+
continueAsNew/GatherError), singleton workflows, entities (registerEntity/
|
|
14
|
+
callEntity), scheduling (ScheduledWorkflow/static schedule/@Scheduled),
|
|
15
|
+
tags and search attributes. Use when writing or composing workflow logic.
|
|
16
|
+
license: MIT
|
|
17
|
+
metadata:
|
|
18
|
+
type: core
|
|
19
|
+
library: "@adonis-agora/durable"
|
|
20
|
+
library_version: "0.25.0"
|
|
21
|
+
framework: adonisjs
|
|
22
|
+
sources:
|
|
23
|
+
- 'DavideCarvalho/adonis-durable:docs/authoring/app-workflows.mdx'
|
|
24
|
+
- 'DavideCarvalho/adonis-durable:docs/concepts/workflows-and-steps.mdx'
|
|
25
|
+
- 'DavideCarvalho/adonis-durable:docs/concepts/sleep-and-signals.mdx'
|
|
26
|
+
- 'DavideCarvalho/adonis-durable:docs/authoring/child-workflows.mdx'
|
|
27
|
+
- 'DavideCarvalho/adonis-durable:docs/authoring/webhooks.mdx'
|
|
28
|
+
- 'DavideCarvalho/adonis-durable:docs/authoring/entities.mdx'
|
|
29
|
+
- 'DavideCarvalho/adonis-durable:docs/authoring/scheduling.mdx'
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
# Authoring workflows & steps
|
|
33
|
+
|
|
34
|
+
A workflow is a class under `app/workflows/` extending `BaseWorkflow` with a
|
|
35
|
+
`static workflow = { name, version }`. The provider scans the directory at boot
|
|
36
|
+
and registers every exported class — you never call `engine.register` by hand
|
|
37
|
+
(it remains the low-level escape hatch). The convention mirrors `@adonisjs/queue`
|
|
38
|
+
jobs under `app/jobs`; scaffold with `node ace make:workflow order`.
|
|
39
|
+
|
|
40
|
+
## Setup
|
|
41
|
+
|
|
42
|
+
```ts title="app/workflows/checkout_workflow.ts"
|
|
43
|
+
import { inject } from '@adonisjs/core'
|
|
44
|
+
import { BaseWorkflow } from '@adonis-agora/durable'
|
|
45
|
+
import type { WorkflowCtx } from '@adonis-agora/durable'
|
|
46
|
+
|
|
47
|
+
export default class CheckoutWorkflow extends BaseWorkflow {
|
|
48
|
+
static workflow = { name: 'checkout', version: '1' }
|
|
49
|
+
|
|
50
|
+
async run(ctx: WorkflowCtx, order: { id: number; total: number }) {
|
|
51
|
+
await ctx.localStep('reserveStock', async () => ({ reserved: true }))
|
|
52
|
+
const charge = await ctx.step('payments:charge-card', {
|
|
53
|
+
orderId: order.id,
|
|
54
|
+
amountCents: order.total,
|
|
55
|
+
})
|
|
56
|
+
const approval = await ctx.waitForSignal<{ approved: boolean }>(`approve:${order.id}`)
|
|
57
|
+
if (!approval.approved) return { status: 'rejected', chargeId: charge.chargeId }
|
|
58
|
+
await ctx.localStep('ship', async () => ({ shipped: true }))
|
|
59
|
+
return { status: 'shipped', chargeId: charge.chargeId }
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Run it from anywhere: `CheckoutWorkflow.dispatch(input, { runId })` enqueues;
|
|
65
|
+
`CheckoutWorkflow.start(input)` awaits the settled result. Both statics are
|
|
66
|
+
context-aware — inside a running body they become a linked child /
|
|
67
|
+
fire-and-forget child instead of a top-level run.
|
|
68
|
+
|
|
69
|
+
## Core patterns
|
|
70
|
+
|
|
71
|
+
### Pattern 1 — typed steps with `@Step`, `defineStep`, and DI
|
|
72
|
+
|
|
73
|
+
Steps are discovered from `app/steps` and served by name automatically. A
|
|
74
|
+
`@Step` method ref passed to `ctx.step` gives full input/output typing:
|
|
75
|
+
|
|
76
|
+
```ts title="app/steps/payment_steps.ts"
|
|
77
|
+
import { Step } from '@adonis-agora/durable'
|
|
78
|
+
import { z } from 'zod'
|
|
79
|
+
|
|
80
|
+
export default class PaymentSteps {
|
|
81
|
+
@Step({
|
|
82
|
+
name: 'payments:charge-card',
|
|
83
|
+
input: z.object({ orderId: z.number().int(), amountCents: z.number().int() }),
|
|
84
|
+
output: z.object({ chargeId: z.string() }),
|
|
85
|
+
retries: 3,
|
|
86
|
+
})
|
|
87
|
+
async chargeCard(input: { orderId: number; amountCents: number }) {
|
|
88
|
+
return { chargeId: await stripe.charge(input) }
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
```ts title="app/workflows/order_workflow.ts"
|
|
94
|
+
import { inject } from '@adonisjs/core'
|
|
95
|
+
import { BaseWorkflow } from '@adonis-agora/durable'
|
|
96
|
+
import type { WorkflowCtx } from '@adonis-agora/durable'
|
|
97
|
+
import PaymentSteps from '#steps/payment_steps'
|
|
98
|
+
|
|
99
|
+
@inject()
|
|
100
|
+
export default class OrderWorkflow extends BaseWorkflow {
|
|
101
|
+
static workflow = { name: 'order', version: '1' }
|
|
102
|
+
|
|
103
|
+
constructor(private payments: PaymentSteps) {
|
|
104
|
+
super()
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async run(ctx: WorkflowCtx, order: Order) {
|
|
108
|
+
// Typed both ways — renaming chargeCard is a compile error here:
|
|
109
|
+
const charge = await ctx.step(this.payments.chargeCard, {
|
|
110
|
+
orderId: order.id,
|
|
111
|
+
amountCents: order.total,
|
|
112
|
+
})
|
|
113
|
+
return { chargeId: charge.chargeId }
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The instance is built once at registration and reused for every run — treat the
|
|
119
|
+
constructor as wiring; keep per-run state in input and step outputs, never on
|
|
120
|
+
`this`. Injected services are for **composing**, not doing work: reach them
|
|
121
|
+
through step refs so the work is checkpointed.
|
|
122
|
+
|
|
123
|
+
### Pattern 2 — pausing durably: sleeps, signals, events
|
|
124
|
+
|
|
125
|
+
All three suspend the run with zero compute and survive restarts.
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
// Time-based wait — duration string or ms:
|
|
129
|
+
await ctx.sleep('7 days')
|
|
130
|
+
await ctx.sleepUntil(new Date('2026-12-31T00:00:00Z'))
|
|
131
|
+
|
|
132
|
+
// Human-in-the-loop / webhook callback — point-to-point by token:
|
|
133
|
+
const decision = await ctx.waitForSignal<{ approved: boolean }>(`approve:${order.id}`, {
|
|
134
|
+
timeoutMs: 24 * 60 * 60 * 1000, // throws SignalTimeoutError when the deadline passes
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
// Named pub/sub — one publish fans out to every matching waiter:
|
|
138
|
+
const settled = await ctx.waitForEvent<{ orderId: string }>('payment.settled', {
|
|
139
|
+
match: { orderId: order.id },
|
|
140
|
+
})
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Deliver from controllers: `engine.signal(token, payload)` resumes one waiter;
|
|
144
|
+
signals sent before the waiter registers are buffered, not lost;
|
|
145
|
+
`engine.signalWithStart(workflow, input, runId, { token, payload })` starts the
|
|
146
|
+
run if missing and delivers in one race-free call. Publish events with
|
|
147
|
+
`engine.publishEvent(name, payload, { id: event.id })` — the upstream event id
|
|
148
|
+
makes redelivery a no-op for `onEvent` starts. Register a workflow to start on
|
|
149
|
+
events with `{ onEvent: ['payment.settled'] }`; coalesce chatty sources with
|
|
150
|
+
`eventBatch: { mode: 'debounce', windowMs: 5_000 }` (last payload wins) or
|
|
151
|
+
`{ mode: 'batch', maxSize: 50, windowMs: 60_000 }` (receives `{ events: [...] }`).
|
|
152
|
+
|
|
153
|
+
```ts title="app/controllers/approvals_controller.ts"
|
|
154
|
+
import { inject } from '@adonisjs/core'
|
|
155
|
+
import { WorkflowEngine } from '@adonis-agora/durable'
|
|
156
|
+
|
|
157
|
+
@inject()
|
|
158
|
+
export default class ApprovalsController {
|
|
159
|
+
constructor(private engine: WorkflowEngine) {}
|
|
160
|
+
|
|
161
|
+
async approve({ params, request, response }: HttpContext) {
|
|
162
|
+
await this.engine.signal(`approve:${params.id}`, request.body())
|
|
163
|
+
return response.noContent()
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Pattern 3 — children, fan-out, and singletons
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
const shipment = await ctx.child(ShippingWorkflow, { orderId: order.id }) // parent suspends
|
|
172
|
+
await ctx.startChild('reindex-search', { postId: post.id }) // fire-and-forget
|
|
173
|
+
const results = await ctx.all(ProcessItemWorkflow, batch.items) // outputs in input order
|
|
174
|
+
if (input.n < 3) await ctx.continueAsNew({ n: input.n + 1 }) // clean history per generation
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
`ctx.all` default mode is `waitAll`: every sibling finishes, then the call throws
|
|
178
|
+
a `GatherError` carrying `.failures`; `{ mode: 'failFast' }` cancels remaining
|
|
179
|
+
siblings (plain cancel — no saga). Child ids derive from the call position and
|
|
180
|
+
are replay-stable; never pass a random one.
|
|
181
|
+
|
|
182
|
+
Serialize runs per subject with a singleton — runs sharing a key queue FIFO and
|
|
183
|
+
are race-free across instances:
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
export default class SyncShopWorkflow extends BaseWorkflow {
|
|
187
|
+
static workflow = {
|
|
188
|
+
name: 'sync-shop',
|
|
189
|
+
version: '1',
|
|
190
|
+
singleton: { key: (input) => (input as { shopId: string }).shopId, limit: 1, maxQueueDepth: 20 },
|
|
191
|
+
}
|
|
192
|
+
// …
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Overflow beyond `limit + maxQueueDepth` rejects `dispatch` with
|
|
197
|
+
`SingletonQueueFullError` before anything is created.
|
|
198
|
+
|
|
199
|
+
### Pattern 4 — long-lived state, callbacks, cadences
|
|
200
|
+
|
|
201
|
+
Entities serialize operations per key without DB locks (register from a
|
|
202
|
+
preload):
|
|
203
|
+
|
|
204
|
+
```ts title="start/entities.ts"
|
|
205
|
+
import engine from '@adonis-agora/durable/services/main'
|
|
206
|
+
|
|
207
|
+
engine.registerEntity<{ balanceCents: number }>('account', {
|
|
208
|
+
initialState: () => ({ balanceCents: 0 }),
|
|
209
|
+
handlers: {
|
|
210
|
+
deposit: (state, amountCents: number) => {
|
|
211
|
+
state.balanceCents += amountCents
|
|
212
|
+
return state.balanceCents
|
|
213
|
+
},
|
|
214
|
+
balance: (state) => state.balanceCents,
|
|
215
|
+
},
|
|
216
|
+
})
|
|
217
|
+
// drive: engine.signalEntity('account', key, 'deposit', 500)
|
|
218
|
+
// read: engine.getEntityState('account', key)
|
|
219
|
+
// from a workflow: await ctx.callEntity('account', key, 'deposit', 500)
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Wait on a foreign system's own callback by id (`engine.completeTask(runId, name,
|
|
223
|
+
result)` / `failTask` resume the run):
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
const result = await ctx.task<TranscodeResult>(job.id, async () => {
|
|
227
|
+
await sqs.send({ queueUrl, body: JSON.stringify({ jobId: job.id, src: job.src }) })
|
|
228
|
+
})
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Recurring cadences are colocated on the class (or set in `config/durable.ts`
|
|
232
|
+
`schedules`, which overrides by `key`); cron needs `cron-parser` installed where
|
|
233
|
+
the worker runs, and only the `durable:work` loop fires schedules:
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
export default class DailyReportWorkflow extends BaseWorkflow {
|
|
237
|
+
static workflow = { name: 'daily-report', version: '1' }
|
|
238
|
+
static schedule = { cron: '0 2 * * *', timezone: 'America/Sao_Paulo' }
|
|
239
|
+
// or: @Scheduled({ everyMs: 60_000 }) above the class
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Each schedule window starts exactly once across a fleet via an idempotent
|
|
244
|
+
time-bucket run id.
|
|
245
|
+
|
|
246
|
+
Source: `docs/authoring/entities.mdx`, `docs/authoring/external-tasks.mdx`,
|
|
247
|
+
`docs/authoring/scheduling.mdx`.
|
|
248
|
+
|
|
249
|
+
## Common mistakes
|
|
250
|
+
|
|
251
|
+
### HIGH calling an injected service directly inside `run`
|
|
252
|
+
|
|
253
|
+
Wrong:
|
|
254
|
+
|
|
255
|
+
```ts
|
|
256
|
+
async run(ctx, input) {
|
|
257
|
+
const receipt = await this.billing.charge(input) // I/O outside a step
|
|
258
|
+
return { receipt }
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Correct:
|
|
263
|
+
|
|
264
|
+
```ts
|
|
265
|
+
async run(ctx, input) {
|
|
266
|
+
const receipt = await ctx.step(this.billing.charge, input)
|
|
267
|
+
return { receipt }
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Mechanism: work done outside `ctx.step`/`ctx.localStep` is never checkpointed,
|
|
272
|
+
so it re-executes on every replay and its result is not durable. The docs warn
|
|
273
|
+
explicitly that injected services exist "for composing the workflow, not for
|
|
274
|
+
doing its work". Source: `docs/authoring/app-workflows.mdx`.
|
|
275
|
+
|
|
276
|
+
### HIGH swallowing control-flow signals in a hand-rolled try/catch
|
|
277
|
+
|
|
278
|
+
Wrong:
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
try {
|
|
282
|
+
await ctx.step('chargeCard', input)
|
|
283
|
+
} catch (error) {
|
|
284
|
+
await ctx.step('refund', input) // also catches suspend/continue-as-new signals!
|
|
285
|
+
throw error
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
Correct:
|
|
290
|
+
|
|
291
|
+
```ts
|
|
292
|
+
import { isWorkflowControlFlowSignal } from '@adonis-agora/durable'
|
|
293
|
+
|
|
294
|
+
try {
|
|
295
|
+
await ctx.step('chargeCard', input)
|
|
296
|
+
} catch (error) {
|
|
297
|
+
if (isWorkflowControlFlowSignal(error)) throw error
|
|
298
|
+
await ctx.step('refund', input)
|
|
299
|
+
throw error
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
Mechanism: `ctx.sleep`, `ctx.waitForSignal` and `ctx.continueAsNew` unwind the
|
|
304
|
+
turn by throwing; running your failure path on one records extra history a later
|
|
305
|
+
replay never produces → `NonDeterminismError` on resume. The predicate checks a
|
|
306
|
+
stamped marker, deliberately `false` for cancellations and real failures.
|
|
307
|
+
Source: `docs/concepts/workflows-and-steps.mdx` ("Catching errors").
|
|
308
|
+
|
|
309
|
+
### HIGH passing a random child id inside a workflow
|
|
310
|
+
|
|
311
|
+
Wrong:
|
|
312
|
+
|
|
313
|
+
```ts
|
|
314
|
+
await ctx.startChild('reindex-search', item, crypto.randomUUID())
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Correct:
|
|
318
|
+
|
|
319
|
+
```ts
|
|
320
|
+
await ctx.startChild('reindex-search', item) // deterministic positional id
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Mechanism: inside a body, omitted child ids are derived deterministically from
|
|
324
|
+
the call position so replay re-attaches to the same child; a fresh random id on
|
|
325
|
+
each replay breaks that dedup and re-fires the child. Source:
|
|
326
|
+
`docs/authoring/child-workflows.mdx` ("opts.runId — outside vs inside").
|
|
327
|
+
|
|
328
|
+
### MEDIUM blocking a hot HTTP path on `.start`
|
|
329
|
+
|
|
330
|
+
Wrong:
|
|
331
|
+
|
|
332
|
+
```ts
|
|
333
|
+
const result = await CheckoutWorkflow.start(order) // request held open until settle
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
Correct:
|
|
337
|
+
|
|
338
|
+
```ts
|
|
339
|
+
const { runId } = await CheckoutWorkflow.dispatch(order, { runId: `checkout:${order.id}` })
|
|
340
|
+
return response.accepted({ runId })
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Mechanism: `.start` resolves only when the run reaches a terminal state or
|
|
344
|
+
`suspends` — hours later for a long workflow. Source: `docs/getting-started.mdx`
|
|
345
|
+
(warning callout).
|
|
346
|
+
|
|
347
|
+
### MEDIUM awaiting a webhook with no timeout
|
|
348
|
+
|
|
349
|
+
Wrong:
|
|
350
|
+
|
|
351
|
+
```ts
|
|
352
|
+
const result = await hook.wait() // suspends indefinitely if the provider never calls back
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
Correct:
|
|
356
|
+
|
|
357
|
+
```ts
|
|
358
|
+
import { SignalTimeoutError } from '@adonis-agora/durable'
|
|
359
|
+
|
|
360
|
+
try {
|
|
361
|
+
const result = await hook.wait({ timeoutMs: 30 * 60 * 1000 })
|
|
362
|
+
} catch (error) {
|
|
363
|
+
if (!(error instanceof SignalTimeoutError)) throw error
|
|
364
|
+
// reconcile: poll the provider instead of hanging forever
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
Mechanism: without `timeoutMs` there is no wake timer — a dropped callback
|
|
369
|
+
leaves the run parked invisibly to the timer poller and crash recovery.
|
|
370
|
+
Source: `docs/authoring/webhooks.mdx` ("Not waiting forever").
|
|
371
|
+
|
|
372
|
+
### MEDIUM throwing business rejections out of entity handlers
|
|
373
|
+
|
|
374
|
+
Wrong:
|
|
375
|
+
|
|
376
|
+
```ts
|
|
377
|
+
withdraw: (state, amountCents) => {
|
|
378
|
+
if (amountCents > state.balanceCents) throw new Error('insufficient funds')
|
|
379
|
+
state.balanceCents -= amountCents
|
|
380
|
+
return state.balanceCents
|
|
381
|
+
},
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
Correct:
|
|
385
|
+
|
|
386
|
+
```ts
|
|
387
|
+
withdraw: (state, amountCents) =>
|
|
388
|
+
amountCents > state.balanceCents
|
|
389
|
+
? { ok: false as const, reason: 'insufficient_funds' as const }
|
|
390
|
+
: ((state.balanceCents -= amountCents), { ok: true as const }),
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
Mechanism: a throwing handler fails the entity's immortal run, stranding every
|
|
394
|
+
caller suspended on `ctx.callEntity`; model expected rejections as returned
|
|
395
|
+
discriminated results and reserve throws for genuine programmer errors.
|
|
396
|
+
Source: `docs/authoring/entities.mdx` (warning callout).
|
|
397
|
+
|
|
398
|
+
See also: `durable-determinism` — why the body must stay deterministic and how
|
|
399
|
+
to change it safely once live.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.react-flow{direction:ltr;--xy-edge-stroke-default: #b1b1b7;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #555;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(255, 255, 255, .5);--xy-minimap-background-color-default: #fff;--xy-minimap-mask-background-color-default: rgba(240, 240, 240, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #e2e2e2;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: transparent;--xy-background-pattern-dots-color-default: #91919a;--xy-background-pattern-lines-color-default: #eee;--xy-background-pattern-cross-color-default: #e2e2e2;background-color:var(--xy-background-color, var(--xy-background-color-default));--xy-node-color-default: inherit;--xy-node-border-default: 1px solid #1a192b;--xy-node-background-color-default: #fff;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #1a192b;--xy-node-border-radius-default: 3px;--xy-handle-background-color-default: #1a192b;--xy-handle-border-color-default: #fff;--xy-selection-background-color-default: rgba(0, 89, 220, .08);--xy-selection-border-default: 1px dotted rgba(0, 89, 220, .8);--xy-controls-button-background-color-default: #fefefe;--xy-controls-button-background-color-hover-default: #f4f4f4;--xy-controls-button-color-default: inherit;--xy-controls-button-color-hover-default: inherit;--xy-controls-button-border-color-default: #eee;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #ffffff;--xy-edge-label-color-default: inherit;--xy-resize-background-color-default: #3367d9}.react-flow.dark{--xy-edge-stroke-default: #3e3e3e;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #727272;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(150, 150, 150, .25);--xy-minimap-background-color-default: #141414;--xy-minimap-mask-background-color-default: rgba(60, 60, 60, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #2b2b2b;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: #141414;--xy-background-pattern-dots-color-default: #555;--xy-background-pattern-lines-color-default: #333;--xy-background-pattern-cross-color-default: #333;--xy-node-color-default: #f8f8f8;--xy-node-border-default: 1px solid #3c3c3c;--xy-node-background-color-default: #1e1e1e;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #999;--xy-handle-background-color-default: #bebebe;--xy-handle-border-color-default: #1e1e1e;--xy-selection-background-color-default: rgba(200, 200, 220, .08);--xy-selection-border-default: 1px dotted rgba(200, 200, 220, .8);--xy-controls-button-background-color-default: #2b2b2b;--xy-controls-button-background-color-hover-default: #3e3e3e;--xy-controls-button-color-default: #f8f8f8;--xy-controls-button-color-hover-default: #fff;--xy-controls-button-border-color-default: #5b5b5b;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #141414;--xy-edge-label-color-default: #f8f8f8}.react-flow__background{background-color:var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));pointer-events:none;z-index:-1}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1;touch-action:none}.react-flow__pane.draggable{cursor:grab}.react-flow__pane.dragging{cursor:grabbing}.react-flow__pane.selection{cursor:pointer}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow__edge-path{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default));stroke-width:var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));fill:none}.react-flow__connection-path{stroke:var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));stroke-width:var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));fill:none}.react-flow .react-flow__edges{position:absolute}.react-flow .react-flow__edges svg{overflow:visible;position:absolute;pointer-events:none}.react-flow__edge{pointer-events:visibleStroke}.react-flow__edge.selectable{cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge.selectable:focus .react-flow__edge-path,.react-flow__edge.selectable:focus-visible .react-flow__edge-path{stroke:var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default))}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__arrowhead polyline{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__arrowhead polyline.arrowclosed{fill:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}svg.react-flow__connectionline{z-index:1001;overflow:visible;position:absolute}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default}.react-flow__node.selectable{cursor:pointer}.react-flow__node.draggable{cursor:grab;pointer-events:all}.react-flow__node.draggable.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background-color:var(--xy-handle-background-color, var(--xy-handle-background-color-default));border:1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));border-radius:100%}.react-flow__handle.connectingfrom{pointer-events:all}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:0;transform:translate(-50%,50%)}.react-flow__handle-top{top:0;left:50%;transform:translate(-50%,-50%)}.react-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.react-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__pane.selection .react-flow__panel{pointer-events:none}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.top.center,.react-flow__panel.bottom.center{left:50%;transform:translate(-15px) translate(-50%)}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.left.center,.react-flow__panel.right.center{top:50%;transform:translateY(-15px) translateY(-50%)}.react-flow__attribution{font-size:10px;background:var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;left:0;top:0}.react-flow__viewport-portal{position:absolute;width:100%;height:100%;left:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__minimap{background:var( --xy-minimap-background-color-props, var(--xy-minimap-background-color, var(--xy-minimap-background-color-default)) )}.react-flow__minimap-svg{display:block}.react-flow__minimap-mask{fill:var( --xy-minimap-mask-background-color-props, var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default)) );stroke:var( --xy-minimap-mask-stroke-color-props, var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default)) );stroke-width:var( --xy-minimap-mask-stroke-width-props, var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default)) )}.react-flow__minimap-node{fill:var( --xy-minimap-node-background-color-props, var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default)) );stroke:var( --xy-minimap-node-stroke-color-props, var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default)) );stroke-width:var( --xy-minimap-node-stroke-width-props, var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default)) )}.react-flow__background-pattern.dots{fill:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default)) )}.react-flow__background-pattern.lines{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default)) )}.react-flow__background-pattern.cross{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default)) )}.react-flow__controls{display:flex;flex-direction:column;box-shadow:var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default))}.react-flow__controls.horizontal{flex-direction:row}.react-flow__controls-button{display:flex;justify-content:center;align-items:center;height:26px;width:26px;padding:4px;border:none;background:var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));border-bottom:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) );color:var( --xy-controls-button-color-props, var(--xy-controls-button-color, var(--xy-controls-button-color-default)) );cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px;fill:currentColor}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-input,.react-flow__node-default,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:var(--xy-node-border-radius, var(--xy-node-border-radius-default));width:150px;font-size:12px;color:var(--xy-node-color, var(--xy-node-color-default));text-align:center;border:var(--xy-node-border, var(--xy-node-border-default));background-color:var(--xy-node-background-color, var(--xy-node-background-color-default))}.react-flow__node-input.selectable:hover,.react-flow__node-default.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default))}.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default))}.react-flow__node-group{background-color:var(--xy-node-group-background-color, var(--xy-node-group-background-color-default))}.react-flow__nodesselection-rect,.react-flow__selection{background:var(--xy-selection-background-color, var(--xy-selection-background-color-default));border:var(--xy-selection-border, var(--xy-selection-border-default))}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls-button:hover{background:var( --xy-controls-button-background-color-hover-props, var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default)) );color:var( --xy-controls-button-color-hover-props, var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default)) )}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__controls-button:last-child{border-bottom:none}.react-flow__controls.horizontal .react-flow__controls-button{border-bottom:none;border-right:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) )}.react-flow__controls.horizontal .react-flow__controls-button:last-child{border-right:none}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:5px;height:5px;border:1px solid #fff;border-radius:1px;background-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));translate:-50% -50%}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}.react-flow__edge-textbg{fill:var(--xy-edge-label-background-color, var(--xy-edge-label-background-color-default))}.react-flow__edge-text{fill:var(--xy-edge-label-color, var(--xy-edge-label-color-default))}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:JetBrains Mono,ui-monospace,SFMono-Regular,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1536px){.container{max-width:1536px}}.visible{visibility:visible}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{top:0;right:0;bottom:0;left:0}.inset-x-0{left:0;right:0}.inset-x-6{left:1.5rem;right:1.5rem}.inset-y-0{top:0;bottom:0}.bottom-6{bottom:1.5rem}.left-0{left:0}.left-1\/2{left:50%}.right-0{right:0}.top-0{top:0}.top-1\/2{top:50%}.top-full{top:100%}.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}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-top:.25rem;margin-bottom:.25rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-\[10px\]{margin-left:10px}.ml-\[18px\]{margin-left:18px}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-7{height:1.75rem}.h-full{height:100%}.h-px{height:1px}.max-h-48{max-height:12rem}.max-h-64{max-height:16rem}.max-h-80{max-height:20rem}.min-h-0{min-height:0px}.w-1\.5{width:.375rem}.w-10{width:2.5rem}.w-16{width:4rem}.w-32{width:8rem}.w-4{width:1rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-7{width:1.75rem}.w-72{width:18rem}.w-\[208px\]{width:208px}.w-\[300px\]{width:300px}.w-\[380px\]{width:380px}.w-\[3px\]{width:3px}.w-\[min\(560px\,92vw\)\]{width:min(560px,92vw)}.w-full{width:100%}.min-w-0{min-width:0px}.max-w-3xl{max-width:48rem}.max-w-\[120px\]{max-width:120px}.max-w-\[180px\]{max-width:180px}.max-w-\[280px\]{max-width:280px}.max-w-\[90\%\]{max-width:90%}.max-w-full{max-width:100%}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.-translate-x-1\/2{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-rotate-90{--tw-rotate: -90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.cursor-row-resize{cursor:row-resize}.resize-y{resize:vertical}.resize{resize:both}.grid-cols-\[130px_1fr\]{grid-template-columns:130px 1fr}.grid-cols-\[150px_1fr\]{grid-template-columns:150px 1fr}.grid-cols-\[minmax\(300px\,360px\)_1fr\]{grid-template-columns:minmax(300px,360px) 1fr}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.flex-nowrap{flex-wrap:nowrap}.place-items-center{place-items:center}.items-start{align-items:flex-start}.items-center{align-items:center}.items-baseline{align-items:baseline}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.gap-y-0\.5{row-gap:.125rem}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-line-soft>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:color-mix(in srgb,var(--line-soft) calc(var(--tw-divide-opacity, 1) * 100%),transparent)}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.break-words{overflow-wrap:break-word}.rounded{border-radius:.25rem}.rounded-\[2px\]{border-radius:2px}.rounded-\[3px\]{border-radius:3px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-xl{border-radius:.75rem}.\!border-0{border-width:0px!important}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-amber-500\/20{border-color:#f59e0b33}.border-amber-500\/25{border-color:#f59e0b40}.border-amber-500\/30{border-color:#f59e0b4d}.border-amber-500\/40{border-color:#f59e0b66}.border-amber-500\/50{border-color:#f59e0b80}.border-bad\/25{border-color:color-mix(in srgb,var(--bad) 25%,transparent)}.border-brand\/30{border-color:color-mix(in srgb,var(--accent) 30%,transparent)}.border-brand\/60{border-color:color-mix(in srgb,var(--accent) 60%,transparent)}.border-emerald-500\/25{border-color:#10b98140}.border-indigo-500\/30{border-color:#6366f14d}.border-indigo-500\/40{border-color:#6366f166}.border-line{--tw-border-opacity: 1;border-color:color-mix(in srgb,var(--line) calc(var(--tw-border-opacity, 1) * 100%),transparent)}.border-line-soft{--tw-border-opacity: 1;border-color:color-mix(in srgb,var(--line-soft) calc(var(--tw-border-opacity, 1) * 100%),transparent)}.border-line\/60{border-color:color-mix(in srgb,var(--line) 60%,transparent)}.border-red-500\/20{border-color:#ef444433}.border-red-500\/25{border-color:#ef444440}.border-red-500\/40{border-color:#ef444466}.border-rose-500\/30{border-color:#f43f5e4d}.border-rose-500\/40{border-color:#f43f5e66}.border-rose-500\/50{border-color:#f43f5e80}.border-sky-500\/30{border-color:#0ea5e94d}.border-sky-500\/40{border-color:#0ea5e966}.border-teal-500\/30{border-color:#14b8a64d}.border-transparent{border-color:transparent}.border-warn\/40{border-color:color-mix(in srgb,var(--warn) 40%,transparent)}.border-zinc-500{--tw-border-opacity: 1;border-color:rgb(113 113 122 / var(--tw-border-opacity, 1))}.border-zinc-600{--tw-border-opacity: 1;border-color:rgb(82 82 91 / var(--tw-border-opacity, 1))}.border-zinc-600\/50{border-color:#52525b80}.border-zinc-700{--tw-border-opacity: 1;border-color:rgb(63 63 70 / var(--tw-border-opacity, 1))}.\!bg-zinc-600{--tw-bg-opacity: 1 !important;background-color:rgb(82 82 91 / var(--tw-bg-opacity, 1))!important}.bg-amber-400{--tw-bg-opacity: 1;background-color:rgb(251 191 36 / var(--tw-bg-opacity, 1))}.bg-amber-500\/10{background-color:#f59e0b1a}.bg-amber-500\/15{background-color:#f59e0b26}.bg-amber-500\/35{background-color:#f59e0b59}.bg-amber-500\/5{background-color:#f59e0b0d}.bg-bad\/10{background-color:color-mix(in srgb,var(--bad) 10%,transparent)}.bg-black\/15{background-color:#00000026}.bg-black\/20{background-color:#0003}.bg-black\/40{background-color:#0006}.bg-black\/60{background-color:#0009}.bg-brand\/10{background-color:color-mix(in srgb,var(--accent) 10%,transparent)}.bg-current{background-color:currentColor}.bg-emerald-400{--tw-bg-opacity: 1;background-color:rgb(52 211 153 / var(--tw-bg-opacity, 1))}.bg-emerald-400\/45{background-color:#34d39973}.bg-emerald-500\/10{background-color:#10b9811a}.bg-emerald-500\/15{background-color:#10b98126}.bg-emerald-500\/20{background-color:#10b98133}.bg-emerald-500\/30{background-color:#10b9814d}.bg-emerald-500\/40{background-color:#10b98166}.bg-indigo-500\/10{background-color:#6366f11a}.bg-line-soft{--tw-bg-opacity: 1;background-color:color-mix(in srgb,var(--line-soft) calc(var(--tw-bg-opacity, 1) * 100%),transparent)}.bg-live{--tw-bg-opacity: 1;background-color:color-mix(in srgb,var(--live) calc(var(--tw-bg-opacity, 1) * 100%),transparent)}.bg-live\/15{background-color:color-mix(in srgb,var(--live) 15%,transparent)}.bg-live\/20{background-color:color-mix(in srgb,var(--live) 20%,transparent)}.bg-panel{--tw-bg-opacity: 1;background-color:color-mix(in srgb,var(--panel) calc(var(--tw-bg-opacity, 1) * 100%),transparent)}.bg-panel-2{--tw-bg-opacity: 1;background-color:color-mix(in srgb,var(--panel-2) calc(var(--tw-bg-opacity, 1) * 100%),transparent)}.bg-panel\/95{background-color:color-mix(in srgb,var(--panel) 95%,transparent)}.bg-popover\/95{background-color:color-mix(in srgb,var(--panel-2) 95%,transparent)}.bg-red-400{--tw-bg-opacity: 1;background-color:rgb(248 113 113 / var(--tw-bg-opacity, 1))}.bg-red-500\/10{background-color:#ef44441a}.bg-red-500\/15{background-color:#ef444426}.bg-red-500\/20{background-color:#ef444433}.bg-red-500\/35{background-color:#ef444459}.bg-red-500\/40{background-color:#ef444466}.bg-rose-500\/10{background-color:#f43f5e1a}.bg-rose-500\/15{background-color:#f43f5e26}.bg-rose-500\/80{background-color:#f43f5ecc}.bg-sky-500\/10{background-color:#0ea5e91a}.bg-teal-500\/10{background-color:#14b8a61a}.bg-transparent{background-color:transparent}.bg-warn\/10{background-color:color-mix(in srgb,var(--warn) 10%,transparent)}.bg-zinc-800{--tw-bg-opacity: 1;background-color:rgb(39 39 42 / var(--tw-bg-opacity, 1))}.bg-zinc-800\/40{background-color:#27272a66}.bg-zinc-800\/50{background-color:#27272a80}.bg-zinc-800\/60{background-color:#27272a99}.bg-zinc-800\/70{background-color:#27272ab3}.bg-zinc-900{--tw-bg-opacity: 1;background-color:rgb(24 24 27 / var(--tw-bg-opacity, 1))}.bg-zinc-900\/30{background-color:#18181b4d}.bg-zinc-900\/40{background-color:#18181b66}.bg-zinc-900\/60{background-color:#18181b99}.p-0{padding:0}.p-0\.5{padding:.125rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-0{padding-left:0;padding-right:0}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-3\.5{padding-left:.875rem;padding-right:.875rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-7{padding-left:1.75rem;padding-right:1.75rem}.py-0{padding-top:0;padding-bottom:0}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pl-1{padding-left:.25rem}.pl-2{padding-left:.5rem}.pl-3\.5{padding-left:.875rem}.pr-3{padding-right:.75rem}.pt-1\.5{padding-top:.375rem}.pt-3{padding-top:.75rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.text-\[10\.5px\]{font-size:10.5px}.text-\[10px\]{font-size:10px}.text-\[11\.5px\]{font-size:11.5px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-\[15px\]{font-size:15px}.text-\[9px\]{font-size:9px}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.normal-case{text-transform:none}.italic{font-style:italic}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.tracking-\[0\.15em\]{letter-spacing:.15em}.tracking-\[0\.16em\]{letter-spacing:.16em}.tracking-\[0\.18em\]{letter-spacing:.18em}.tracking-\[0\.2em\]{letter-spacing:.2em}.tracking-normal{letter-spacing:0em}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.text-amber-100{--tw-text-opacity: 1;color:rgb(254 243 199 / var(--tw-text-opacity, 1))}.text-amber-200{--tw-text-opacity: 1;color:rgb(253 230 138 / var(--tw-text-opacity, 1))}.text-amber-300{--tw-text-opacity: 1;color:rgb(252 211 77 / var(--tw-text-opacity, 1))}.text-amber-300\/70{color:#fcd34db3}.text-amber-400\/70{color:#fbbf24b3}.text-amber-400\/80{color:#fbbf24cc}.text-bad{--tw-text-opacity: 1;color:color-mix(in srgb,var(--bad) calc(var(--tw-text-opacity, 1) * 100%),transparent)}.text-brand{--tw-text-opacity: 1;color:color-mix(in srgb,var(--accent) calc(var(--tw-text-opacity, 1) * 100%),transparent)}.text-emerald-300{--tw-text-opacity: 1;color:rgb(110 231 183 / var(--tw-text-opacity, 1))}.text-emerald-400{--tw-text-opacity: 1;color:rgb(52 211 153 / var(--tw-text-opacity, 1))}.text-emerald-500\/80{color:#10b981cc}.text-foreground{--tw-text-opacity: 1;color:color-mix(in srgb,var(--text) calc(var(--tw-text-opacity, 1) * 100%),transparent)}.text-good{--tw-text-opacity: 1;color:color-mix(in srgb,var(--good) calc(var(--tw-text-opacity, 1) * 100%),transparent)}.text-indigo-300{--tw-text-opacity: 1;color:rgb(165 180 252 / var(--tw-text-opacity, 1))}.text-indigo-300\/80{color:#a5b4fccc}.text-indigo-400{--tw-text-opacity: 1;color:rgb(129 140 248 / var(--tw-text-opacity, 1))}.text-live{--tw-text-opacity: 1;color:color-mix(in srgb,var(--live) calc(var(--tw-text-opacity, 1) * 100%),transparent)}.text-red-200{--tw-text-opacity: 1;color:rgb(254 202 202 / var(--tw-text-opacity, 1))}.text-red-300{--tw-text-opacity: 1;color:rgb(252 165 165 / var(--tw-text-opacity, 1))}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.text-red-400\/80{color:#f87171cc}.text-rose-200{--tw-text-opacity: 1;color:rgb(254 205 211 / var(--tw-text-opacity, 1))}.text-rose-300{--tw-text-opacity: 1;color:rgb(253 164 175 / var(--tw-text-opacity, 1))}.text-rose-300\/70{color:#fda4afb3}.text-sky-300{--tw-text-opacity: 1;color:rgb(125 211 252 / var(--tw-text-opacity, 1))}.text-teal-300{--tw-text-opacity: 1;color:rgb(94 234 212 / var(--tw-text-opacity, 1))}.text-warn{--tw-text-opacity: 1;color:color-mix(in srgb,var(--warn) calc(var(--tw-text-opacity, 1) * 100%),transparent)}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-zinc-100{--tw-text-opacity: 1;color:rgb(244 244 245 / var(--tw-text-opacity, 1))}.text-zinc-200{--tw-text-opacity: 1;color:rgb(228 228 231 / var(--tw-text-opacity, 1))}.text-zinc-300{--tw-text-opacity: 1;color:rgb(212 212 216 / var(--tw-text-opacity, 1))}.text-zinc-400{--tw-text-opacity: 1;color:rgb(161 161 170 / var(--tw-text-opacity, 1))}.text-zinc-50{--tw-text-opacity: 1;color:rgb(250 250 250 / var(--tw-text-opacity, 1))}.text-zinc-500{--tw-text-opacity: 1;color:rgb(113 113 122 / var(--tw-text-opacity, 1))}.text-zinc-600{--tw-text-opacity: 1;color:rgb(82 82 91 / var(--tw-text-opacity, 1))}.text-zinc-800{--tw-text-opacity: 1;color:rgb(39 39 42 / var(--tw-text-opacity, 1))}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline{outline-style:solid}.ring{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-2{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-amber-500\/45{--tw-ring-color: rgb(245 158 11 / .45)}.ring-brand\/30{--tw-ring-color: color-mix(in srgb, var(--accent) 30% , transparent)}.ring-emerald-400\/60{--tw-ring-color: rgb(52 211 153 / .6)}.ring-emerald-500\/40{--tw-ring-color: rgb(16 185 129 / .4)}.ring-emerald-500\/50{--tw-ring-color: rgb(16 185 129 / .5)}.ring-line-soft{--tw-ring-opacity: 1;--tw-ring-color: color-mix(in srgb, var(--line-soft) calc(var(--tw-ring-opacity, 1) * 100%), transparent)}.ring-red-500\/50{--tw-ring-color: rgb(239 68 68 / .5)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur{--tw-backdrop-blur: blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-md{--tw-backdrop-blur: blur(12px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-sm{--tw-backdrop-blur: blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-150{transition-duration:.15s}.duration-500{transition-duration:.5s}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}:root{--bg: #09090b;--panel: #0c0c0f;--panel-2: #101017;--line: #1c1c22;--line-soft: #16161a;--text: #e7e7ea;--muted: #76767f;--good: #34d399;--warn: #fbbf24;--bad: #f87171;--live: #60a5fa;--accent: #a3e635}*{box-sizing:border-box}html,body,#root{height:100%}body{margin:0;background:var(--bg);color:var(--text);font-family:Space Grotesk,ui-sans-serif,system-ui,sans-serif;-webkit-font-smoothing:antialiased}.app-bg{position:fixed;top:0;right:0;bottom:0;left:0;z-index:0;pointer-events:none;background-image:radial-gradient(900px 400px at 78% -8%,color-mix(in srgb,var(--accent) 8%,transparent),transparent 70%),linear-gradient(to right,var(--line-soft) 1px,transparent 1px),linear-gradient(to bottom,var(--line-soft) 1px,transparent 1px);background-size:100% 100%,44px 44px,44px 44px;-webkit-mask-image:linear-gradient(to bottom,black,black 60%,transparent);mask-image:linear-gradient(to bottom,black,black 60%,transparent);opacity:.5}.mono{font-family:JetBrains Mono,ui-monospace,monospace}.tnum{font-variant-numeric:tabular-nums}.s-running{color:var(--live)}.s-suspended{color:var(--warn)}.s-sleeping{color:#818cf8}.s-awaiting{color:var(--warn)}.s-completed{color:var(--good)}.s-failed{color:var(--bad)}.s-cancelling{color:#f59e0b}.s-cancelled{color:#71717a}.s-dead{color:#e11d48}.s-pending{color:#94a3b8}.s-no-worker{color:#fb923c}.s-queued{color:#a78bfa}.s-stale{color:#fb923c}.dot{width:7px;height:7px;border-radius:999px;background:currentColor;box-shadow:0 0 0 3px color-mix(in srgb,currentColor 18%,transparent)}.pulse{animation:pulse 1.6s ease-in-out infinite}@keyframes pulse{0%,to{opacity:1}50%{opacity:.35}}@keyframes rise{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}.rise{animation:rise .32s cubic-bezier(.2,.7,.2,1) both}.react-flow{--xy-background-color: transparent;--xy-edge-stroke-default: var(--line);--xy-attribution-background-color: transparent}.react-flow__edge-path{stroke-width:1.5}.react-flow__controls{border:1px solid var(--line);border-radius:8px;overflow:hidden;box-shadow:none}.react-flow__controls-button{background:var(--panel);border-bottom:1px solid var(--line);color:var(--muted);fill:var(--muted)}.react-flow__controls-button:hover{background:#18181b}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-thumb{background:#26262c;border:3px solid var(--bg);border-radius:999px}.placeholder\:text-zinc-600::-moz-placeholder{--tw-text-opacity: 1;color:rgb(82 82 91 / var(--tw-text-opacity, 1))}.placeholder\:text-zinc-600::placeholder{--tw-text-opacity: 1;color:rgb(82 82 91 / var(--tw-text-opacity, 1))}.focus-within\:border-zinc-600:focus-within{--tw-border-opacity: 1;border-color:rgb(82 82 91 / var(--tw-border-opacity, 1))}.hover\:-translate-y-0\.5:hover{--tw-translate-y: -.125rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:border-amber-500\/40:hover{border-color:#f59e0b66}.hover\:border-indigo-400\/60:hover{border-color:#818cf899}.hover\:border-red-400\/60:hover{border-color:#f8717199}.hover\:border-sky-400\/60:hover{border-color:#38bdf899}.hover\:border-teal-400\/60:hover{border-color:#2dd4bf99}.hover\:border-zinc-500:hover{--tw-border-opacity: 1;border-color:rgb(113 113 122 / var(--tw-border-opacity, 1))}.hover\:border-zinc-600:hover{--tw-border-opacity: 1;border-color:rgb(82 82 91 / var(--tw-border-opacity, 1))}.hover\:bg-brand\/20:hover{background-color:color-mix(in srgb,var(--accent) 20%,transparent)}.hover\:bg-brand\/40:hover{background-color:color-mix(in srgb,var(--accent) 40%,transparent)}.hover\:bg-indigo-500\/20:hover{background-color:#6366f133}.hover\:bg-rose-500\/20:hover{background-color:#f43f5e33}.hover\:bg-sky-500\/20:hover{background-color:#0ea5e933}.hover\:bg-warn\/20:hover{background-color:color-mix(in srgb,var(--warn) 20%,transparent)}.hover\:bg-zinc-800:hover{--tw-bg-opacity: 1;background-color:rgb(39 39 42 / var(--tw-bg-opacity, 1))}.hover\:bg-zinc-800\/50:hover{background-color:#27272a80}.hover\:bg-zinc-900\/50:hover{background-color:#18181b80}.hover\:bg-zinc-900\/60:hover{background-color:#18181b99}.hover\:text-indigo-100:hover{--tw-text-opacity: 1;color:rgb(224 231 255 / var(--tw-text-opacity, 1))}.hover\:text-indigo-200:hover{--tw-text-opacity: 1;color:rgb(199 210 254 / var(--tw-text-opacity, 1))}.hover\:text-sky-200:hover{--tw-text-opacity: 1;color:rgb(186 230 253 / var(--tw-text-opacity, 1))}.hover\:text-teal-200:hover{--tw-text-opacity: 1;color:rgb(153 246 228 / var(--tw-text-opacity, 1))}.hover\:text-zinc-100:hover{--tw-text-opacity: 1;color:rgb(244 244 245 / var(--tw-text-opacity, 1))}.hover\:text-zinc-200:hover{--tw-text-opacity: 1;color:rgb(228 228 231 / var(--tw-text-opacity, 1))}.hover\:text-zinc-300:hover{--tw-text-opacity: 1;color:rgb(212 212 216 / var(--tw-text-opacity, 1))}.focus\:border-zinc-600:focus{--tw-border-opacity: 1;border-color:rgb(82 82 91 / var(--tw-border-opacity, 1))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-1:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-ring:focus-visible{--tw-ring-opacity: 1;--tw-ring-color: color-mix(in srgb, var(--accent) calc(var(--tw-ring-opacity, 1) * 100%), transparent)}.enabled\:hover\:bg-rose-500\/25:hover:enabled{background-color:#f43f5e40}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-default:disabled{cursor:default}.disabled\:opacity-30:disabled{opacity:.3}.disabled\:opacity-50:disabled{opacity:.5}.data-\[active\]\:bg-zinc-700[data-active]{--tw-bg-opacity: 1;background-color:rgb(63 63 70 / var(--tw-bg-opacity, 1))}.data-\[active\]\:text-zinc-100[data-active]{--tw-text-opacity: 1;color:rgb(244 244 245 / var(--tw-text-opacity, 1))}
|