@fabrika/builder 0.2.0

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.
Files changed (112) hide show
  1. package/BUILD-CONTRACT.md +41 -0
  2. package/LICENSE +21 -0
  3. package/README.md +100 -0
  4. package/cli/src/bin.ts +66 -0
  5. package/cli/src/build-status.ts +109 -0
  6. package/cli/src/catalog.ts +42 -0
  7. package/cli/src/commands/advance.ts +73 -0
  8. package/cli/src/commands/build.ts +215 -0
  9. package/cli/src/commands/ensure-daemon.ts +25 -0
  10. package/cli/src/commands/gate.ts +165 -0
  11. package/cli/src/commands/induce.ts +61 -0
  12. package/cli/src/commands/init.ts +91 -0
  13. package/cli/src/commands/next.ts +31 -0
  14. package/cli/src/config.ts +47 -0
  15. package/cli/src/context.ts +28 -0
  16. package/cli/src/daemon-client.ts +280 -0
  17. package/cli/src/daemon-lifecycle.ts +171 -0
  18. package/cli/src/derive.ts +109 -0
  19. package/cli/src/index.ts +38 -0
  20. package/cli/src/induce.ts +151 -0
  21. package/cli/src/inject-skills.ts +313 -0
  22. package/cli/src/issues.ts +75 -0
  23. package/cli/src/layout.ts +124 -0
  24. package/cli/src/packet.ts +108 -0
  25. package/cli/src/phase-state.ts +19 -0
  26. package/cli/src/phases.ts +131 -0
  27. package/cli/src/skeletons.ts +104 -0
  28. package/daemon/src/bin.ts +70 -0
  29. package/daemon/src/build-stream.ts +38 -0
  30. package/daemon/src/handlers.ts +472 -0
  31. package/daemon/src/index.ts +123 -0
  32. package/daemon/src/paths.ts +30 -0
  33. package/daemon/src/phases.ts +221 -0
  34. package/daemon/src/static.ts +72 -0
  35. package/decisions/README.md +133 -0
  36. package/decisions/patterns/app-deploy.md +55 -0
  37. package/decisions/patterns/auth-password-kv.md +45 -0
  38. package/decisions/patterns/count-store.md +44 -0
  39. package/decisions/patterns/di-container.md +47 -0
  40. package/decisions/patterns/feature-architecture.md +48 -0
  41. package/decisions/patterns/lib-publish.md +46 -0
  42. package/decisions/patterns/monorepo.md +47 -0
  43. package/decisions/patterns/named-seeds.md +45 -0
  44. package/decisions/patterns/observability.md +45 -0
  45. package/decisions/patterns/single-worker-spa.md +74 -0
  46. package/decisions/patterns/structured-logging.md +49 -0
  47. package/decisions/patterns/typed-worker-rpc.md +87 -0
  48. package/decisions/patterns/vozka-app-deploy.md +74 -0
  49. package/decisions/patterns/write-split.md +47 -0
  50. package/decisions/technologies/analytics-engine.md +44 -0
  51. package/decisions/technologies/bindx.md +55 -0
  52. package/decisions/technologies/bun.md +51 -0
  53. package/decisions/technologies/buzola.md +80 -0
  54. package/decisions/technologies/cloudflare-access.md +50 -0
  55. package/decisions/technologies/cloudflare-vite-plugin.md +43 -0
  56. package/decisions/technologies/cloudflare.md +50 -0
  57. package/decisions/technologies/contember.md +65 -0
  58. package/decisions/technologies/cron-triggers.md +46 -0
  59. package/decisions/technologies/d1.md +51 -0
  60. package/decisions/technologies/durable-objects.md +44 -0
  61. package/decisions/technologies/kv.md +42 -0
  62. package/decisions/technologies/lopata.md +55 -0
  63. package/decisions/technologies/nuasite.md +50 -0
  64. package/decisions/technologies/oblaka.md +48 -0
  65. package/decisions/technologies/opice.md +40 -0
  66. package/decisions/technologies/pletivo.md +53 -0
  67. package/decisions/technologies/postgres.md +47 -0
  68. package/decisions/technologies/preact.md +44 -0
  69. package/decisions/technologies/propustka.md +137 -0
  70. package/decisions/technologies/queue.md +55 -0
  71. package/decisions/technologies/r2.md +41 -0
  72. package/decisions/technologies/react-router.md +47 -0
  73. package/decisions/technologies/react.md +37 -0
  74. package/decisions/technologies/roj.md +51 -0
  75. package/decisions/technologies/sentry.md +49 -0
  76. package/decisions/technologies/tailwind.md +45 -0
  77. package/decisions/technologies/vite.md +47 -0
  78. package/decisions/technologies/vozka.md +122 -0
  79. package/decisions/technologies/workers-ai.md +59 -0
  80. package/decisions/technologies/wrangler.md +41 -0
  81. package/decisions/tooling/deptective.md +45 -0
  82. package/decisions/tooling/edvabe.md +45 -0
  83. package/index.ts +2 -0
  84. package/package.json +51 -0
  85. package/skill/SKILL.md +76 -0
  86. package/skill/agents/build-orchestrator.md +170 -0
  87. package/skill/agents/flows-author.md +65 -0
  88. package/skill/agents/implementer.md +37 -0
  89. package/skill/agents/openai.yaml +4 -0
  90. package/skill/agents/opice-skeleton-author.md +68 -0
  91. package/skill/gates/brief.jsx +20 -0
  92. package/skill/gates/build.jsx +20 -0
  93. package/skill/gates/design.jsx +22 -0
  94. package/skill/gates/flows.jsx +14 -0
  95. package/skill/gates/review-grid.jsx +32 -0
  96. package/skill/gates/tech.jsx +17 -0
  97. package/skill/gates/vision.jsx +27 -0
  98. package/stacks/README.md +44 -0
  99. package/stacks/cf-fat.md +64 -0
  100. package/stacks/cf-internal-app.md +125 -0
  101. package/stacks/cf-lightweight.md +54 -0
  102. package/stacks/contember-app.md +53 -0
  103. package/stacks/content-site.md +45 -0
  104. package/ui/dist/assets/annotations-runtime.js +1 -0
  105. package/ui/dist/assets/client.css +2 -0
  106. package/ui/dist/assets/client.fhjppkvr.js +214 -0
  107. package/ui/dist/assets/components.js +63 -0
  108. package/ui/dist/assets/preact-compat.js +1 -0
  109. package/ui/dist/assets/react-jsx-dev-runtime.js +3 -0
  110. package/ui/dist/assets/react-jsx-runtime.js +3 -0
  111. package/ui/dist/assets/runtime.js +1 -0
  112. package/ui/dist/index.html +36 -0
@@ -0,0 +1,125 @@
1
+ ---
2
+ id: cf-internal-app
3
+ title: "Full internal Cloudflare app — Buzola SPA + Propustka + Vozka"
4
+ goal: "From empty to a full internal app: Buzola SPA + Worker API, D1/R2/Queue/Cron/Workers AI, local Vite+lopata, native Propustka login, Vozka-managed production deploy, and green opice tests."
5
+ decisions:
6
+ - cloudflare
7
+ - lopata
8
+ - oblaka
9
+ - vozka
10
+ - wrangler
11
+ - vite
12
+ - react
13
+ - buzola
14
+ - tailwind
15
+ - d1
16
+ - r2
17
+ - queue
18
+ - cron-triggers
19
+ - workers-ai
20
+ - propustka
21
+ - bun
22
+ - named-seeds
23
+ - single-worker-spa
24
+ - typed-worker-rpc
25
+ - vozka-app-deploy
26
+ - opice
27
+ build: "see §build recipe below"
28
+ ---
29
+
30
+ # Stack: cf-internal-app
31
+
32
+ The production-grade **internal-app shape**: an internal, client-rendered Buzola/React
33
+ SPA backed by a Cloudflare Worker. It runs as a Vite SPA plus a lopata Worker
34
+ locally, ships as one Worker with static assets in production, logs people in
35
+ through native Propustka, and delegates the whole production lifecycle to Vozka.
36
+
37
+ Use `cf-lightweight` when an app only needs SPA + D1 and does not belong to the
38
+ Vozka/Propustka ecosystem. This preset deliberately includes the operational
39
+ primitives available to the stack: R2, Queue, Cron and Workers AI. Drop any of those at the
40
+ tech gate when the product has no corresponding workload.
41
+
42
+ ## Composition
43
+
44
+ Frontend: `react` + `buzola` + `vite` + `tailwind`. Runtime/data: `cloudflare` +
45
+ `d1` + `r2` + `queue` + `cron-triggers` + `workers-ai`. Local development:
46
+ `lopata` + `oblaka` + `bun`. Authentication/authorization: native `propustka`.
47
+ Deployment: `vozka` + `wrangler` through the `vozka-app-deploy` pattern. Delivery:
48
+ `single-worker-spa` + `typed-worker-rpc`. Acceptance: `named-seeds` + `opice`.
49
+
50
+ requires-closure holds:
51
+
52
+ - `vozka` → {`cloudflare`, `oblaka`, `wrangler`, `propustka`};
53
+ - `propustka` → {`cloudflare`, `d1`};
54
+ - `single-worker-spa` → {`cloudflare`, `vite`, `buzola`};
55
+ - `typed-worker-rpc` → {`cloudflare`, `buzola`};
56
+ - `vozka-app-deploy` → {`vozka`, `propustka`, `oblaka`, `wrangler`};
57
+ - `buzola` → `react`; all CF resources → `cloudflare`; `named-seeds` → `d1`.
58
+
59
+ One per exclusive slot: platform, deploy-control-plane, app-delivery-shape,
60
+ client-worker-api, cf-dev-runtime, bundler, ui-framework, router, styling,
61
+ relational-db, ai-runtime, authz, js-runtime, seed-strategy and e2e-tests. There
62
+ is **no Cloudflare Access**
63
+ and no app-owned password auth; native Propustka owns both login and permission
64
+ resolution.
65
+
66
+ **Maturity:** Vozka, Propustka, Buzola, lopata and opice are 0.x/WIP. This is a
67
+ curated internal production stack, not the generic default. Pin the working
68
+ versions, read installed sources/types before scaffolding, and typecheck the
69
+ actual resource/auth config.
70
+
71
+ ## Required application shape
72
+
73
+ ### Local vs production delivery
74
+
75
+ - `bun run dev` starts the Vite/Buzola SPA (normally `:5173`).
76
+ - `bunx lopata dev` starts the Worker and local bindings (normally `:8787`).
77
+ - Vite proxies `/rpc`, `/api` and `/internal` to the Worker.
78
+ - Production builds the SPA to `dist/`; a Worker `ASSETS` binding with SPA
79
+ fallback serves non-API paths. Selective `run_worker_first` patterns send only
80
+ API namespaces through Worker code; those paths return their own 404s and
81
+ never fall through to `index.html`.
82
+
83
+ ### Native Propustka login
84
+
85
+ - Define one app id and one action/scope vocabulary shared by runtime auth and
86
+ the schema in `vozka.config.ts`.
87
+ - Off-local, bind `IAM` to `propustka-worker` and inject `PROPUSTKA_URL` as the
88
+ token issuer/login origin.
89
+ - Pass ordered `AppGates` to `PropustkaAuth`: normally a `service` rule followed
90
+ by a `human` rule for each protected API path. Unmatched paths fail closed.
91
+ - Return `loginUrl` to the SPA on a human auth miss, redirect the browser to it,
92
+ and attach every returned `setCookie` to the response.
93
+ - Local/opice runs synthesize a deterministic operator `AuthContext`; current
94
+ `FakeIamClient` is for management methods, not request authentication.
95
+
96
+ ### Typed Worker API
97
+
98
+ - Compose a validated method map behind one `/rpc` endpoint and export its
99
+ inferred contract to the SPA through a type-only import.
100
+ - Authenticate once at the dispatcher, then require each feature handler to
101
+ enforce its concrete `auth.can(...)` capability.
102
+ - Preserve Propustka's `loginUrl`/`setCookie` across the RPC response seam.
103
+
104
+ ### Vozka deploy
105
+
106
+ - `vozka.config.ts` is the production source of truth: stable `id`, exported
107
+ resource builder, schema and pipeline.
108
+ - `ctx.domain` owns the custom domain; `pipeline.secrets` lists required runtime
109
+ secrets. Do not recreate deployment in `.github/workflows/deploy.yml`.
110
+ - A thin `oblaka.ts` reuses the resource builder only for the local lopata loop.
111
+ - The account operator registers repo/env/domain/trigger/secrets in Vozka. That
112
+ is a deployment prerequisite, not a scaffold-time Cloudflare mutation.
113
+
114
+ ## Build recipe (per-issue verify stage)
115
+
116
+ 1. install with Bun; generate local `wrangler.jsonc` from the shared resource
117
+ graph and apply D1 migrations + the issue's named seeds through lopata.
118
+ 2. keep the lopata Worker and Vite SPA running as two background processes.
119
+ 3. run the targeted opice scenario against the Vite URL; auth is the deterministic
120
+ dev operator and external AI/providers use deterministic fakes.
121
+ 4. run unit tests + `bun run typecheck` + the SPA production build. Validate
122
+ `vozka.config.ts`/`oblaka.ts` through their real config-generation command when
123
+ their raw-source type graph is intentionally excluded from `tsc`.
124
+ 5. collapse the result. Production deployment remains Vozka's responsibility;
125
+ do not deploy from an issue implementation loop.
@@ -0,0 +1,54 @@
1
+ ---
2
+ id: cf-lightweight
3
+ title: "buzola SPA + lopata + D1 on Cloudflare — lightweight, no SSR (preferred default)"
4
+ goal: "From empty to a buzola SPA on a local lopata CF dev server with a D1 binding and a green opice test — no SSR, local-first."
5
+ decisions:
6
+ - cloudflare
7
+ - lopata
8
+ - oblaka
9
+ - vite
10
+ - react
11
+ - buzola
12
+ - d1
13
+ - bun
14
+ - tailwind
15
+ - named-seeds
16
+ - opice
17
+ build: "see §build recipe below"
18
+ ---
19
+
20
+ # Stack: cf-lightweight
21
+
22
+ The **preferred default**: a client-rendered **buzola SPA** (no SSR) on **lopata**
23
+ (local-first CF runtime, Bun) with a single **D1** database, styled with Tailwind,
24
+ tested by opice. Lighter than `cf-fat` — no SSR machinery, no workerd, the bun/lopata
25
+ path. Replaces the old `cf-local` (which was RRv7 SSR); the SPA-no-SSR shape is the
26
+ lightweight one.
27
+
28
+ ## Composition
29
+
30
+ `cloudflare` (platform) · `lopata` (cf-dev-runtime, local-first) · `oblaka` (iac) ·
31
+ `buzola` (SPA router — **no SSR**) + `react` · `d1` (relational-db) · `tailwind`
32
+ (styling) · `bun` (toolchain) · `named-seeds` · `opice`.
33
+
34
+ requires-closure holds: `lopata`→{cloudflare,vite}, `buzola`→react, `d1`/`oblaka`→cloudflare,
35
+ `named-seeds`→d1 — all present. One per slot (cf-dev-runtime=lopata, router=buzola,
36
+ ui-framework=react, relational-db=d1, …). **No `react-router`** — buzola is the SPA router.
37
+
38
+ **Note on vite vs the non-vite preference:** `lopata` is a vite plugin, so this stack
39
+ _does_ run vite for the local CF dev server, and buzola integrates via `@buzola/vite-plugin`.
40
+ The Bun-native `@buzola/bun-plugin` (true non-vite) path is for setups that don't use
41
+ lopata's vite dev server — see `buzola` / `bun`.
42
+
43
+ Read first: **`buzola`** (`.route()` is the URL, Navigation-API-only, codegen), **`lopata`**
44
+ (local D1 + the dev server), **`d1`** (idempotent migrations).
45
+
46
+ ## Build recipe (per-issue verify stage)
47
+
48
+ 1. start the lopata dev server (Bun) → the buzola SPA at the local URL.
49
+ 2. `bunx lopata d1 migrations apply` + apply the relevant `named-seeds` (idempotent).
50
+ 3. `bun test` the targeted opice scenarios against the running SPA.
51
+ 4. collapse the result (steps + invariants); between iterations the app stays up, reseed idempotently.
52
+
53
+ Scaffold: write artifacts from sources → `bun install` → `bunx oblaka oblaka.ts` (→ wrangler.jsonc
54
+ with the D1 binding) → migrate → seed → lopata dev → buzola SPA renders D1 data → `bun test` green.
@@ -0,0 +1,53 @@
1
+ ---
2
+ id: contember-app
3
+ title: "Contember (Postgres GraphQL CMS) + buzola/React admin SPA + bindx + Tailwind"
4
+ goal: "From empty to a Contember backend (Postgres) with a typed schema + ACL, and a buzola/React admin SPA bound to it via bindx, green opice tests against the running SPA."
5
+ decisions:
6
+ - contember
7
+ - postgres
8
+ - bindx
9
+ - react
10
+ - buzola
11
+ - tailwind
12
+ - bun
13
+ - opice
14
+ build: "see §build recipe below"
15
+ ---
16
+
17
+ # Stack: contember-app
18
+
19
+ A **data-driven admin app**: a Contember backend (GraphQL CMS + ACL + tenancy on
20
+ **Postgres**) with a **buzola/React SPA** front end bound to it through **bindx**
21
+ (typed data binding + form state). The opposite deployment shape to the cf-* stacks
22
+ — a **Node backend + Postgres** plus a **static SPA**, not Workers + D1.
23
+
24
+ ## Composition
25
+
26
+ Backend: `contember` (backend slot) → `postgres` (relational-db). Frontend:
27
+ `react` + `buzola` (SPA router, bundled via `@buzola/bun-plugin` — the non-vite path)
28
+
29
+ - `bindx` (data-binding over Contember's GraphQL) + `tailwind` (styling). Toolchain:
30
+ `bun`. Tests: `opice`.
31
+
32
+ requires-closure holds: `contember`→postgres, `bindx`→{contember,react},
33
+ `buzola`→react — all present. One per slot (backend, relational-db, router,
34
+ ui-framework, data-binding, styling). **No `cloudflare`/`d1`** — Contember is a Node
35
+ service on Postgres; `d1` would collide with `postgres` on `relational-db`.
36
+
37
+ Read first: **`contember`** (schema-as-code DSL, predicate ACL, Postgres + migrations),
38
+ **`bindx`** (the codegen step + implicit selection over-fetch gotcha), **`buzola`**
39
+ (`.route()` is the URL, Navigation-API-only, bun-plugin).
40
+
41
+ **Maturity:** `bindx` and `buzola` are `wip` (0.x) — the binding/router pieces still
42
+ churn; pin versions. The Contember backend itself is stable.
43
+
44
+ ## Build recipe (per-issue verify stage)
45
+
46
+ 1. start Postgres + the Contember engine (`docker-compose`); apply Contember migrations.
47
+ 2. `generate:schema` (bindx generator: Contember model → typed entities) — commit the output.
48
+ 3. start the buzola SPA dev server (`@buzola/bun-plugin`) → it queries the Contember GraphQL API.
49
+ 4. `bun test` the targeted opice scenarios against the running SPA.
50
+ 5. between iterations: backend + SPA stay up; reseed Contember data idempotently.
51
+
52
+ Scaffold: declare the Contember schema + ACL → bring up Postgres/engine → migrate →
53
+ `generate:schema` → wire `ContemberBindxProvider` + buzola routes → opice green.
@@ -0,0 +1,45 @@
1
+ ---
2
+ id: content-site
3
+ title: "pletivo (Bun-native SSG) + Preact islands + Tailwind — static content site"
4
+ goal: "From empty to a statically-generated content site (file-based pages + content collections) with Preact islands and Tailwind, served locally, green opice smoke test."
5
+ decisions:
6
+ - pletivo
7
+ - preact
8
+ - tailwind
9
+ - bun
10
+ - opice
11
+ build: "see §build recipe below"
12
+ ---
13
+
14
+ # Stack: content-site
15
+
16
+ A **static content site** (marketing / docs / blog) built the Bun-native way —
17
+ `pletivo` (Astro-compatible SSG on Bun) with **Preact islands** for the bits that
18
+ need interactivity, **Tailwind** styling, tested by `opice`. Squarely on the team's
19
+ **bun / non-vite** preference: no app server, no vite pipeline, just a Bun build.
20
+
21
+ ## Composition
22
+
23
+ `pletivo` (site-framework) · `preact` (islands — `ui-framework`) · `tailwind`
24
+ (styling) · `bun` (runtime/build) · `opice` (tests).
25
+
26
+ requires-closure holds: `pletivo`→bun; `pletivo` recommends `preact`+`tailwind`
27
+ (both present). One per slot (site-framework, ui-framework, styling, js-runtime,
28
+ e2e-tests). **No `react`** — pletivo's islands are Preact (and `preact` conflicts
29
+ `react`). **No SSR** — it's static; pre-declare dynamic routes via `getStaticPaths`.
30
+
31
+ Read first: **`pletivo`** (island registry reset, JSON-serializable island props,
32
+ `getStaticPaths` for dynamic routes), **`preact`** (DOM-standard event names).
33
+
34
+ **Maturity:** `pletivo` is `experimental` (0.1.x) — fine for a static site you control,
35
+ but pin the version; it's the bun-native bet, not a settled default.
36
+
37
+ ## Build recipe (per-issue verify stage)
38
+
39
+ 1. `bun install`; author `.astro`/`.tsx` pages under `src/pages/` + islands under `src/islands/`.
40
+ 2. run the pletivo dev server (Bun) and/or `pletivo build` → static HTML.
41
+ 3. serve the output locally; `bun test` the targeted opice scenarios against it.
42
+ 4. between iterations: keep the dev server up; content is file-based (no DB to seed).
43
+
44
+ Hosting is flexible (any static host / Cloudflare Pages); add `cloudflare` only if the
45
+ site grows into needing Workers/bindings — at which point reconsider a Workers SSR stack.
@@ -0,0 +1 @@
1
+ import{createContext as t,useContext as o}from"react";var i=t(null),r=t(""),e=t({sessionId:"",isShared:!1,fsAvailable:!1,uploadUrl:null});function s(){let n=o(i);if(!n)throw Error("useAnnotations requires an AnnotationProvider");return n}function l(){return o(e)}export{s as useAnnotations,l as useAnnotationHost,r as SessionContext,e as AnnotationHostContext,i as AnnotationCtx};
@@ -0,0 +1,2 @@
1
+ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
2
+ @import "https://fonts.googleapis.com/css2?family=Instrument+Serif&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap";@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:-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-mono:"JetBrains Mono", "Fira Code", Consolas, monospace;--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-2xl:42rem;--container-3xl:48rem;--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-medium:500;--font-weight-semibold:600;--tracking-wide:.025em;--tracking-wider:.05em;--tracking-widest:.1em;--leading-snug:1.375;--leading-relaxed:1.625;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--ease-out:cubic-bezier(0, 0, .2, 1);--animate-ping:ping 1s cubic-bezier(0, 0, .2, 1) infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--blur-sm:8px;--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);--color-bg-base:#161510;--color-bg-surface:#1c1b15;--color-bg-elevated:#25241d;--color-bg-code:#1c1b16;--color-bg-input:#fff8dc08;--color-bg-elevated-half:#25241d80;--color-text-primary:#e8e4df;--color-text-secondary:#a09a92;--color-text-tertiary:#847d75;--color-text-code:#c4beb7;--color-text-disabled:#4a463f;--color-text-inverse:#1a1a1a;--color-border-subtle:#fff8f00f;--color-border-medium:#fff8f017;--color-border-hover:#fff8f024;--color-border-strong:#fff8f02e;--color-accent-green:#4a9e6d;--color-accent-green-muted:#4a9e6d24;--color-accent-amber:#c49a3a;--color-accent-amber-muted:#c49a3a24;--color-accent-red:#c45a5a;--color-accent-red-muted:#c45a5a24;--color-accent-blue:#5a8ec4;--color-accent-blue-muted:#5a8ec41f;--color-highlight-bg:#ffdc6426;--color-highlight-border:#ffdc6459;--color-highlight-annotation:#ffdc642e;--color-highlight-active:#ffdc6459;--color-highlight-selected:#ffdc641a;--color-badge-bg:#c49a3a33;--color-btn-primary:#e8e4df;--color-btn-primary-text:#1a1a1a;--font-heading:"Instrument Serif", Georgia, "Times New Roman", serif;--font-body:"Inter", -apple-system, BlinkMacSystemFont, sans-serif;--text-section:1.5rem;--text-section--line-height:1.25;--text-section--letter-spacing:-.01em;--text-task-label:.9375rem;--text-task-label--line-height:1.4;--text-body:.875rem;--text-body--line-height:1.6;--text-code:.8125rem;--text-code--line-height:1.55;--text-meta:.75rem;--text-meta--line-height:1.4;--text-meta--letter-spacing:.02em;--text-tiny:.6875rem;--text-tiny--line-height:1.4}}@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;-webkit-text-decoration: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}body{background-color:var(--color-bg-base);color:var(--color-text-primary);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:0}.top-1{top:var(--spacing)}.top-1\.5{top:calc(var(--spacing) * 1.5)}.top-1\/2{top:50%}.top-2{top:calc(var(--spacing) * 2)}.right-0{right:0}.right-1{right:var(--spacing)}.right-1\.5{right:calc(var(--spacing) * 1.5)}.right-3{right:calc(var(--spacing) * 3)}.-left-8{left:calc(var(--spacing) * -8)}.left-0{left:0}.z-10{z-index:10}.z-50{z-index:50}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.-mx-4{margin-inline:calc(var(--spacing) * -4)}.mx-0\.5{margin-inline:calc(var(--spacing) * .5)}.mx-4{margin-inline:calc(var(--spacing) * 4)}.mx-auto{margin-inline:auto}.my-1{margin-block:var(--spacing)}.my-2{margin-block:calc(var(--spacing) * 2)}.my-3{margin-block:calc(var(--spacing) * 3)}.-mt-0\.5{margin-top:calc(var(--spacing) * -.5)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.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-\[7px\]{margin-top:7px}.mt-px{margin-top:1px}.mb-1{margin-bottom:var(--spacing)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-8{margin-bottom:calc(var(--spacing) * 8)}.ml-2{margin-left:calc(var(--spacing) * 2)}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-2\.5{height:calc(var(--spacing) * 2.5)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-11{height:calc(var(--spacing) * 11)}.h-64{height:calc(var(--spacing) * 64)}.h-\[16px\]{height:16px}.h-\[18px\]{height:18px}.h-auto{height:auto}.h-full{height:100%}.h-screen{height:100vh}.min-h-0{min-height:0}.min-h-\[20px\]{min-height:20px}.min-h-\[40px\]{min-height:40px}.min-h-\[60px\]{min-height:60px}.min-h-screen{min-height:100vh}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-2{width:calc(var(--spacing) * 2)}.w-2\.5{width:calc(var(--spacing) * 2.5)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-7{width:calc(var(--spacing) * 7)}.w-8{width:calc(var(--spacing) * 8)}.w-9{width:calc(var(--spacing) * 9)}.w-72{width:calc(var(--spacing) * 72)}.w-80{width:calc(var(--spacing) * 80)}.w-full{width:100%}.w-px{width:1px}.w-screen{width:100vw}.max-w-2xl{max-width:var(--container-2xl)}.max-w-3xl{max-width:var(--container-3xl)}.max-w-full{max-width:100%}.min-w-0{min-width:0}.min-w-\[16px\]{min-width:16px}.min-w-\[18px\]{min-width:18px}.flex-1{flex:1}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.-rotate-90{rotate:-90deg}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-ping{animation:var(--animate-ping)}.animate-pulse{animation:var(--animate-pulse)}.cursor-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.resize{resize:both}.resize-none{resize:none}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-\[5rem_1fr\]{grid-template-columns:5rem 1fr}.grid-cols-\[14rem_minmax\(0\,1fr\)_22rem_auto\]{grid-template-columns:14rem minmax(0,1fr) 22rem auto}.grid-cols-\[14rem_minmax\(0\,1fr\)_auto\]{grid-template-columns:14rem minmax(0,1fr) auto}.grid-rows-\[minmax\(0\,1fr\)\]{grid-template-rows:minmax(0,1fr)}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-3{column-gap:calc(var(--spacing) * 3)}.gap-y-1{row-gap:var(--spacing)}.gap-y-1\.5{row-gap:calc(var(--spacing) * 1.5)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.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-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-none{--tw-border-style:none;border-style:none}.border-accent-amber{border-color:var(--color-accent-amber)}.border-border-hover{border-color:var(--color-border-hover)}.border-border-medium{border-color:var(--color-border-medium)}.border-border-strong{border-color:var(--color-border-strong)}.border-border-subtle{border-color:var(--color-border-subtle)}.border-highlight-border{border-color:var(--color-highlight-border)}.\!bg-transparent{background-color:#0000!important}.bg-accent-amber{background-color:var(--color-accent-amber)}.bg-accent-amber-muted{background-color:var(--color-accent-amber-muted)}.bg-accent-amber-muted\/60{background-color:#c49a3a16}@supports (color:color-mix(in lab, red, red)){.bg-accent-amber-muted\/60{background-color:color-mix(in oklab, var(--color-accent-amber-muted) 60%, transparent)}}.bg-accent-amber\/60{background-color:#c49a3a99}@supports (color:color-mix(in lab, red, red)){.bg-accent-amber\/60{background-color:color-mix(in oklab, var(--color-accent-amber) 60%, transparent)}}.bg-accent-blue{background-color:var(--color-accent-blue)}.bg-accent-blue-muted{background-color:var(--color-accent-blue-muted)}.bg-accent-green{background-color:var(--color-accent-green)}.bg-accent-green-muted{background-color:var(--color-accent-green-muted)}.bg-accent-green\/60{background-color:#4a9e6d99}@supports (color:color-mix(in lab, red, red)){.bg-accent-green\/60{background-color:color-mix(in oklab, var(--color-accent-green) 60%, transparent)}}.bg-accent-red{background-color:var(--color-accent-red)}.bg-accent-red-muted{background-color:var(--color-accent-red-muted)}.bg-accent-red\/60{background-color:#c45a5a99}@supports (color:color-mix(in lab, red, red)){.bg-accent-red\/60{background-color:color-mix(in oklab, var(--color-accent-red) 60%, transparent)}}.bg-badge-bg{background-color:var(--color-badge-bg)}.bg-bg-base{background-color:var(--color-bg-base)}.bg-bg-code{background-color:var(--color-bg-code)}.bg-bg-elevated{background-color:var(--color-bg-elevated)}.bg-bg-input{background-color:var(--color-bg-input)}.bg-bg-surface{background-color:var(--color-bg-surface)}.bg-bg-surface\/30{background-color:#1c1b154d}@supports (color:color-mix(in lab, red, red)){.bg-bg-surface\/30{background-color:color-mix(in oklab, var(--color-bg-surface) 30%, transparent)}}.bg-black\/40{background-color:#0006}@supports (color:color-mix(in lab, red, red)){.bg-black\/40{background-color:color-mix(in oklab, var(--color-black) 40%, transparent)}}.bg-black\/50{background-color:#00000080}@supports (color:color-mix(in lab, red, red)){.bg-black\/50{background-color:color-mix(in oklab, var(--color-black) 50%, transparent)}}.bg-border-hover{background-color:var(--color-border-hover)}.bg-border-medium{background-color:var(--color-border-medium)}.bg-border-subtle{background-color:var(--color-border-subtle)}.bg-btn-primary{background-color:var(--color-btn-primary)}.bg-highlight-bg{background-color:var(--color-highlight-bg)}.bg-highlight-selected{background-color:var(--color-highlight-selected)}.bg-text-inverse{background-color:var(--color-text-inverse)}.bg-text-tertiary{background-color:var(--color-text-tertiary)}.bg-transparent{background-color:#0000}.bg-white{background-color:var(--color-white)}.p-0{padding:0}.p-0\.5{padding:calc(var(--spacing) * .5)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-0{padding-inline:0}.px-0\.5{padding-inline:calc(var(--spacing) * .5)}.px-1{padding-inline:var(--spacing)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.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-4{padding-block:calc(var(--spacing) * 4)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-px{padding-block:1px}.pt-3{padding-top:calc(var(--spacing) * 3)}.pb-1{padding-bottom:var(--spacing)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pl-2{padding-left:calc(var(--spacing) * 2)}.pl-5{padding-left:calc(var(--spacing) * 5)}.text-center{text-align:center}.text-left{text-align:left}.font-body{font-family:var(--font-body)}.font-heading{font-family:var(--font-heading)}.font-mono{font-family:var(--font-mono)}.text-meta{font-size:var(--text-meta);line-height:var(--tw-leading,var(--text-meta--line-height));letter-spacing:var(--tw-tracking,var(--text-meta--letter-spacing))}.text-section{font-size:var(--text-section);line-height:var(--tw-leading,var(--text-section--line-height));letter-spacing:var(--tw-tracking,var(--text-section--letter-spacing))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-body{font-size:var(--text-body);line-height:var(--tw-leading,var(--text-body--line-height))}.text-code{font-size:var(--text-code);line-height:var(--tw-leading,var(--text-code--line-height))}.text-task-label{font-size:var(--text-task-label);line-height:var(--tw-leading,var(--text-task-label--line-height))}.text-tiny{font-size:var(--text-tiny);line-height:var(--tw-leading,var(--text-tiny--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.break-words{overflow-wrap:break-word}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-accent-amber{color:var(--color-accent-amber)}.text-accent-blue{color:var(--color-accent-blue)}.text-accent-green{color:var(--color-accent-green)}.text-accent-red{color:var(--color-accent-red)}.text-btn-primary-text{color:var(--color-btn-primary-text)}.text-text-code{color:var(--color-text-code)}.text-text-disabled{color:var(--color-text-disabled)}.text-text-primary{color:var(--color-text-primary)}.text-text-secondary{color:var(--color-text-secondary)}.text-text-tertiary{color:var(--color-text-tertiary)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.line-through{text-decoration-line:line-through}.underline{text-decoration-line:underline}.decoration-border-hover{-webkit-text-decoration-color:var(--color-border-hover);-webkit-text-decoration-color:var(--color-border-hover);text-decoration-color:var(--color-border-hover)}.opacity-0{opacity:0}.opacity-40{opacity:.4}.opacity-50{opacity:.5}.opacity-55{opacity:.55}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.shadow-lg{--tw-shadow:0 8px 24px var(--tw-shadow-color,var(--color-shadow));box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 12px var(--tw-shadow-color,var(--color-shadow));box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px var(--tw-shadow-color,var(--color-shadow));box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-0{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + 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)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur-sm{--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;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-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-100{--tw-duration:.1s;transition-duration:.1s}.duration-150{--tw-duration:.15s;transition-duration:.15s}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}.select-text{-webkit-user-select:text;user-select:text}.\[writing-mode\:vertical-rl\]{writing-mode:vertical-rl}@media (hover:hover){.group-hover\/ann\:opacity-100:is(:where(.group\/ann):hover *){opacity:1}.group-hover\/code\:opacity-60:is(:where(.group\/code):hover *),.group-hover\/diff\:opacity-60:is(:where(.group\/diff):hover *){opacity:.6}.group-hover\/section\:opacity-20:is(:where(.group\/section):hover *){opacity:.2}.group-hover\/section\:opacity-50:is(:where(.group\/section):hover *){opacity:.5}.group-hover\/task\:opacity-100:is(:where(.group\/task):hover *){opacity:1}}.placeholder\:text-text-disabled::placeholder{color:var(--color-text-disabled)}.placeholder\:text-text-tertiary::placeholder{color:var(--color-text-tertiary)}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.odd\:bg-bg-elevated-half:nth-child(odd){background-color:var(--color-bg-elevated-half)}@media (hover:hover){.hover\:-translate-y-px:hover{--tw-translate-y:-1px;translate:var(--tw-translate-x) var(--tw-translate-y)}.hover\:border-border-hover:hover{border-color:var(--color-border-hover)}.hover\:bg-accent-red-muted:hover{background-color:var(--color-accent-red-muted)}.hover\:bg-bg-elevated:hover{background-color:var(--color-bg-elevated)}.hover\:bg-bg-elevated-half:hover{background-color:var(--color-bg-elevated-half)}.hover\:bg-bg-input:hover{background-color:var(--color-bg-input)}.hover\:bg-bg-surface\/50:hover{background-color:#1c1b1580}@supports (color:color-mix(in lab, red, red)){.hover\:bg-bg-surface\/50:hover{background-color:color-mix(in oklab, var(--color-bg-surface) 50%, transparent)}}.hover\:bg-border-medium:hover{background-color:var(--color-border-medium)}.hover\:bg-border-subtle:hover{background-color:var(--color-border-subtle)}.hover\:text-accent-red:hover{color:var(--color-accent-red)}.hover\:text-text-primary:hover{color:var(--color-text-primary)}.hover\:text-text-secondary:hover{color:var(--color-text-secondary)}.hover\:text-text-tertiary:hover{color:var(--color-text-tertiary)}.hover\:underline:hover{text-decoration-line:underline}.hover\:\!opacity-80:hover{opacity:.8!important}.hover\:\!opacity-100:hover{opacity:1!important}.hover\:opacity-90:hover{opacity:.9}.hover\:opacity-100:hover{opacity:1}}.focus\:border-none:focus{--tw-border-style:none;border-style:none}.focus\:border-border-hover:focus{border-color:var(--color-border-hover)}.focus\:ring-0:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + 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)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}}mark[data-annotation-id]{background:var(--color-highlight-annotation);border-bottom:1.5px solid var(--color-highlight-bg);cursor:pointer;color:inherit;border-radius:2px;padding:1px 0;transition:background .15s,box-shadow .15s}mark[data-annotation-id].mark-active{background:var(--color-highlight-active);border-bottom:2px solid var(--color-highlight-border);box-shadow:0 0 0 1px var(--color-highlight-border)}@keyframes ann-flash{0%,to{background:var(--color-highlight-annotation)}25%,75%{background:var(--color-highlight-active)}}.ann-flash{animation:.6s 2 ann-flash}[data-annotation-image]{cursor:crosshair;touch-action:none;position:relative}.ann-region{background:var(--color-highlight-annotation);border:2px solid var(--color-highlight-bg);cursor:pointer;border-radius:2px;transition:background .15s,box-shadow .15s;position:absolute}.ann-region[data-annotation-region=ellipse]{border-radius:50%}.ann-region.mark-active{background:var(--color-highlight-active);border-color:var(--color-highlight-border);box-shadow:0 0 0 1px var(--color-highlight-border)}.ann-region-draft{pointer-events:none;border-style:dashed;border-color:var(--color-highlight-border)}.annotation-highlight{background:var(--color-highlight-bg);border-bottom:2px solid var(--color-highlight-border);cursor:pointer;border-radius:2px;transition:background .15s}.annotation-highlight:hover,.annotation-highlight.active{background:var(--color-highlight-active)}:root{--color-shadow:#00000040;--color-scrollbar:#fff8f00f;--color-scrollbar-hover:#fff8f01f;--color-folder-fill:#c49a3a26;--color-folder-fill-active:#c49a3a40;--color-folder-stroke:#c49a3a80;--color-folder-stroke-active:#c49a3a;--color-hljs-base:#c4beb7;--color-hljs-keyword:#d2a6ff;--color-hljs-string:#a8cc8c;--color-hljs-comment:#847d75;--color-hljs-number:#e8a87c;--color-hljs-variable:#7ec8e3;--color-hljs-function:#dbc074;--color-hljs-punctuation:#a09a92}[data-theme=light]{--color-bg-base:#faf5e6;--color-bg-surface:#f3edd8;--color-bg-elevated:#ebe4ce;--color-bg-code:#f0ebd5;--color-bg-input:#503c0a0d;--color-bg-elevated-half:#ebe4ce80;--color-text-primary:#2a2520;--color-text-secondary:#5a5550;--color-text-tertiary:#9a9390;--color-text-code:#4a4540;--color-text-disabled:#c5c0b8;--color-text-inverse:#faf6ef;--color-border-subtle:#503c1e14;--color-border-medium:#503c1e1a;--color-border-hover:#503c1e26;--color-border-strong:#503c1e33;--color-accent-green:#3a8a5a;--color-accent-green-muted:#3a8a5a1a;--color-accent-amber:#a07820;--color-accent-amber-muted:#a078201a;--color-accent-red:#b84a4a;--color-accent-red-muted:#b84a4a14;--color-accent-blue:#4a7eb4;--color-accent-blue-muted:#4a7eb414;--color-highlight-bg:#c8a01e26;--color-highlight-border:#c8a01e66;--color-highlight-annotation:#c8a01e2e;--color-highlight-active:#c8a01e59;--color-highlight-selected:#c8a01e1a;--color-badge-bg:#a0782026;--color-btn-primary:#2a2520;--color-btn-primary-text:#faf6ef;--color-shadow:#503c1e1a;--color-scrollbar:#503c1e14;--color-scrollbar-hover:#503c1e26;--color-folder-fill:#a078201f;--color-folder-fill-active:#a0782038;--color-folder-stroke:#a0782066;--color-folder-stroke-active:#a07820;--color-hljs-base:#4a4540;--color-hljs-keyword:#7c3aed;--color-hljs-string:#2e7d32;--color-hljs-comment:#9a9390;--color-hljs-number:#c45a20;--color-hljs-variable:#1976d2;--color-hljs-function:#8a6d00;--color-hljs-punctuation:#6b6560}code,pre,.font-mono{font-family:JetBrains Mono,Fira Code,Consolas,monospace}::selection{background-color:var(--color-highlight-active);color:var(--color-text-primary)}:focus-visible{outline:2px solid var(--color-accent-blue);outline-offset:2px;border-radius:4px}textarea:focus-visible{outline:none}button,a,[role=button]{transition:all .15s}.diff-added{background-color:#4a9e6d40}@supports (color:color-mix(in lab, red, red)){.diff-added{background-color:color-mix(in srgb, var(--color-accent-green) 25%, transparent)}}.diff-added{border-radius:2px;padding-block:1px;padding-inline:1px}.diff-removed{background-color:#c45a5a40}@supports (color:color-mix(in lab, red, red)){.diff-removed{background-color:color-mix(in srgb, var(--color-accent-red) 25%, transparent)}}.diff-removed{text-decoration:line-through;-webkit-text-decoration-color:var(--color-accent-red);-webkit-text-decoration-color:var(--color-accent-red);text-decoration-color:var(--color-accent-red);border-radius:2px;padding-block:1px;padding-inline:1px}.diff-block-removed{background:#c45a5a14}@supports (color:color-mix(in lab, red, red)){.diff-block-removed{background:color-mix(in srgb, var(--color-accent-red) 8%, transparent)}}.diff-block-removed{border-left:3px solid var(--color-accent-red);opacity:.7}.diff-block-added{background:#4a9e6d14}@supports (color:color-mix(in lab, red, red)){.diff-block-added{background:color-mix(in srgb, var(--color-accent-green) 8%, transparent)}}.diff-block-added{border-left:3px solid var(--color-accent-green)}.diff-row-removed td{background:#c45a5a1a}@supports (color:color-mix(in lab, red, red)){.diff-row-removed td{background:color-mix(in srgb, var(--color-accent-red) 10%, transparent)}}.diff-row-removed td{text-decoration:line-through;-webkit-text-decoration-color:var(--color-accent-red);-webkit-text-decoration-color:var(--color-accent-red);text-decoration-color:var(--color-accent-red);opacity:.6}.diff-row-added td{background:#4a9e6d1a}@supports (color:color-mix(in lab, red, red)){.diff-row-added td{background:color-mix(in srgb, var(--color-accent-green) 10%, transparent)}}.diff-item-removed{background:#c45a5a1a}@supports (color:color-mix(in lab, red, red)){.diff-item-removed{background:color-mix(in srgb, var(--color-accent-red) 10%, transparent)}}.diff-item-removed{text-decoration:line-through;-webkit-text-decoration-color:var(--color-accent-red);-webkit-text-decoration-color:var(--color-accent-red);text-decoration-color:var(--color-accent-red);opacity:.6}.diff-item-added{background:#4a9e6d1a}@supports (color:color-mix(in lab, red, red)){.diff-item-added{background:color-mix(in srgb, var(--color-accent-green) 10%, transparent)}}.diff-block-label{text-transform:uppercase;pointer-events:none;border-radius:3px;padding:1px 6px;font-size:10px;font-weight:500;position:absolute;top:4px;right:8px}@keyframes plan-refresh{0%{opacity:.6}to{opacity:1}}.plan-updated{animation:.3s plan-refresh}input[type=range]{appearance:none;background:0 0;height:20px}input[type=range]::-webkit-slider-thumb{appearance:none;background:var(--color-accent-amber);cursor:pointer;border:2px solid var(--color-bg-base);border-radius:50%;width:14px;height:14px;margin-top:-5px}input[type=range]::-moz-range-thumb{background:var(--color-accent-amber);cursor:pointer;border:2px solid var(--color-bg-base);border-radius:50%;width:14px;height:14px}input[type=range]::-webkit-slider-runnable-track{background:0 0;border-radius:2px;height:4px}input[type=range]::-moz-range-track{background:0 0;border-radius:2px;height:4px}.prose-canvas{color:var(--color-text-secondary);font-size:.875rem;line-height:1.7}.prose-canvas h1,.prose-canvas h2,.prose-canvas h3,.prose-canvas h4,.prose-canvas h5,.prose-canvas h6{color:var(--color-text-primary);margin-top:1.5em;margin-bottom:.5em;font-weight:600;line-height:1.3}.prose-canvas h1{font-size:1.5rem}.prose-canvas h2{font-size:1.25rem}.prose-canvas h3{font-size:1.1rem}.prose-canvas h1:first-child,.prose-canvas h2:first-child,.prose-canvas h3:first-child{margin-top:0}.prose-canvas p{margin-top:.75em;margin-bottom:.75em}.prose-canvas p:first-child{margin-top:0}.prose-canvas a{color:var(--color-accent-blue);-webkit-text-decoration:underline #5a8ec466;text-decoration:underline #5a8ec466}@supports (color:color-mix(in lab, red, red)){.prose-canvas a{-webkit-text-decoration-color:color-mix(in srgb, var(--color-accent-blue) 40%, transparent);-webkit-text-decoration-color:color-mix(in srgb, var(--color-accent-blue) 40%, transparent);text-decoration-color:color-mix(in srgb, var(--color-accent-blue) 40%, transparent)}}.prose-canvas a{text-underline-offset:2px}.prose-canvas a:hover{-webkit-text-decoration-color:var(--color-accent-blue);-webkit-text-decoration-color:var(--color-accent-blue);text-decoration-color:var(--color-accent-blue)}.prose-canvas strong{color:var(--color-text-primary);font-weight:600}.prose-canvas code{background:var(--color-bg-code);color:var(--color-text-code);border-radius:4px;padding:.15em .4em;font-size:.8em}.prose-canvas pre{background:var(--color-bg-code);border-radius:8px;margin-top:.75em;margin-bottom:.75em;padding:1em;overflow-x:auto}.prose-canvas pre code{background:0 0;padding:0;font-size:.8rem}.prose-canvas ul,.prose-canvas ol{margin-top:.5em;margin-bottom:.5em;padding-left:1.5em}.prose-canvas ul{list-style-type:disc}.prose-canvas ol{list-style-type:decimal}.prose-canvas li{margin-top:.25em}.prose-canvas li>ul,.prose-canvas li>ol{margin-top:.25em;margin-bottom:0}.prose-canvas blockquote{border-left:3px solid var(--color-border-strong);color:var(--color-text-tertiary);margin-top:.75em;margin-bottom:.75em;margin-left:0;padding-left:1em}.prose-canvas hr{border:none;border-top:1px solid var(--color-border-subtle);margin:1.5em 0}.prose-canvas table{border-collapse:collapse;width:100%;margin-top:.75em;margin-bottom:.75em;font-size:.8rem}.prose-canvas th,.prose-canvas td{border:1px solid var(--color-border-subtle);text-align:left;padding:.5em .75em}.prose-canvas th{background:var(--color-bg-elevated);color:var(--color-text-primary);font-weight:600}.prose-canvas img{border-radius:8px;max-width:100%;margin-top:.75em;margin-bottom:.75em}.hljs{color:var(--color-hljs-base)!important;background:0 0!important}pre code.hljs{padding:0!important}.hljs-keyword,.hljs-selector-tag,.hljs-built_in,.hljs-name,.hljs-tag{color:var(--color-hljs-keyword)!important}.hljs-string,.hljs-title,.hljs-section,.hljs-attribute,.hljs-literal,.hljs-template-tag,.hljs-template-variable,.hljs-type{color:var(--color-hljs-string)!important}.hljs-comment,.hljs-quote,.hljs-deletion,.hljs-meta{color:var(--color-hljs-comment)!important}.hljs-number,.hljs-regexp,.hljs-addition{color:var(--color-hljs-number)!important}.hljs-variable,.hljs-attr{color:var(--color-hljs-variable)!important}.hljs-function .hljs-title,.hljs-title.function_{color:var(--color-hljs-function)!important}.hljs-params{color:var(--color-hljs-base)!important}.hljs-property{color:var(--color-hljs-variable)!important}.hljs-punctuation{color:var(--color-hljs-punctuation)!important}html,body{font-family:var(--font-body);background:var(--color-bg-base);color:var(--color-text-primary);-webkit-font-smoothing:antialiased;margin:0}body{font-size:var(--text-body);line-height:var(--text-body--line-height)}::-webkit-scrollbar{width:9px;height:9px}::-webkit-scrollbar-thumb{background:var(--color-border-medium);border-radius:5px}::-webkit-scrollbar-thumb:hover{background:var(--color-border-hover)}::-webkit-scrollbar-track{background:0 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-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@keyframes ping{75%,to{opacity:0;transform:scale(2)}}@keyframes pulse{50%{opacity:.5}}