melony 0.2.5 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -3
- package/dist/{chunk-7DSKO2W5.js → chunk-7YBEEXMK.js} +17 -8
- package/dist/chunk-7YBEEXMK.js.map +1 -0
- package/dist/cli.js +2 -72
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +5 -2
- package/dist/client.js +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/package.json +5 -8
- package/dist/chunk-7DSKO2W5.js.map +0 -1
- package/studio/assets/index-C9cA2u9S.css +0 -1
- package/studio/assets/index-DbBQePth.js +0 -22
- package/studio/index.html +0 -14
- package/studio/vite.svg +0 -1
package/README.md
CHANGED
|
@@ -100,12 +100,18 @@ You can also run it without arguments (defaults to chat):
|
|
|
100
100
|
npx melony
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
-
### Studio (
|
|
103
|
+
### Studio (Recommended)
|
|
104
104
|
|
|
105
|
+
A local UI for interacting with and debugging your agents.
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
npx @melony/studio
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
For more options:
|
|
105
112
|
```bash
|
|
106
|
-
npx melony
|
|
113
|
+
npx @melony/studio --port 4000 --url http://localhost:4001
|
|
107
114
|
```
|
|
108
|
-
A local Vite-based UI for interacting with and debugging your agents.
|
|
109
115
|
|
|
110
116
|
## Core Concepts
|
|
111
117
|
|
|
@@ -8,11 +8,11 @@ var MelonyClient = class {
|
|
|
8
8
|
this.stateListeners = /* @__PURE__ */ new Set();
|
|
9
9
|
this.url = options.url;
|
|
10
10
|
this.headers = options.headers;
|
|
11
|
-
this.runId = generateId();
|
|
12
11
|
this.state = {
|
|
13
12
|
events: options.initialEvents ?? [],
|
|
14
13
|
streaming: false,
|
|
15
|
-
error: null
|
|
14
|
+
error: null,
|
|
15
|
+
context: options.initialContext ?? {}
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
18
|
subscribe(listener) {
|
|
@@ -38,7 +38,7 @@ var MelonyClient = class {
|
|
|
38
38
|
this.state = { ...this.state, ...updates };
|
|
39
39
|
this.stateListeners.forEach((l) => l(this.getState()));
|
|
40
40
|
}
|
|
41
|
-
async *send(event) {
|
|
41
|
+
async *send(event, additionalBody) {
|
|
42
42
|
if (this.abortController) this.abortController.abort();
|
|
43
43
|
this.abortController = new AbortController();
|
|
44
44
|
const optimisticEvent = {
|
|
@@ -57,7 +57,7 @@ var MelonyClient = class {
|
|
|
57
57
|
headers,
|
|
58
58
|
body: JSON.stringify({
|
|
59
59
|
event: optimisticEvent,
|
|
60
|
-
|
|
60
|
+
...additionalBody
|
|
61
61
|
}),
|
|
62
62
|
signal: this.abortController.signal
|
|
63
63
|
});
|
|
@@ -77,7 +77,8 @@ var MelonyClient = class {
|
|
|
77
77
|
if (!line.startsWith("data: ")) continue;
|
|
78
78
|
try {
|
|
79
79
|
const incomingEvent = JSON.parse(line.slice(6));
|
|
80
|
-
this.handleIncomingEvent(incomingEvent);
|
|
80
|
+
const handled = this.handleIncomingEvent(incomingEvent);
|
|
81
|
+
if (!handled) continue;
|
|
81
82
|
yield incomingEvent;
|
|
82
83
|
} catch (e) {
|
|
83
84
|
console.error("Failed to parse event", e);
|
|
@@ -104,17 +105,25 @@ var MelonyClient = class {
|
|
|
104
105
|
events.push(event);
|
|
105
106
|
}
|
|
106
107
|
this.setState({ events });
|
|
108
|
+
return true;
|
|
107
109
|
}
|
|
108
110
|
reset(events = []) {
|
|
109
|
-
|
|
111
|
+
this.stop();
|
|
110
112
|
this.setState({
|
|
111
113
|
events,
|
|
112
114
|
error: null,
|
|
113
115
|
streaming: false
|
|
114
116
|
});
|
|
115
117
|
}
|
|
118
|
+
stop() {
|
|
119
|
+
if (this.abortController) {
|
|
120
|
+
this.abortController.abort();
|
|
121
|
+
this.abortController = null;
|
|
122
|
+
this.setState({ streaming: false });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
116
125
|
};
|
|
117
126
|
|
|
118
127
|
export { MelonyClient };
|
|
119
|
-
//# sourceMappingURL=chunk-
|
|
120
|
-
//# sourceMappingURL=chunk-
|
|
128
|
+
//# sourceMappingURL=chunk-7YBEEXMK.js.map
|
|
129
|
+
//# sourceMappingURL=chunk-7YBEEXMK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"chunk-7YBEEXMK.js","sourcesContent":["import { Event } from \"./types\";\nimport { generateId } from \"./utils/generate-id\";\n\nexport type { Event };\nexport { generateId };\n\nexport interface ClientState<TEvent extends Event = Event> {\n events: TEvent[];\n streaming: boolean;\n error: Error | null;\n context: Record<string, any>;\n}\n\nexport interface MelonyClientOptions<TEvent extends Event = Event> {\n url: string;\n initialEvents?: TEvent[];\n initialContext?: Record<string, any>;\n headers?:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>);\n}\n\nexport class MelonyClient<TEvent extends Event = Event> {\n private state: ClientState<TEvent>;\n public readonly url: string;\n private headers?: MelonyClientOptions<TEvent>[\"headers\"];\n private lastServerState: any = null;\n private abortController: AbortController | null = null;\n private stateListeners: Set<(state: ClientState<TEvent>) => void> = new Set();\n\n constructor(options: MelonyClientOptions<TEvent>) {\n this.url = options.url;\n this.headers = options.headers;\n this.state = {\n events: options.initialEvents ?? [],\n streaming: false,\n error: null,\n context: options.initialContext ?? {},\n };\n }\n\n subscribe(listener: (state: ClientState<TEvent>) => void) {\n this.stateListeners.add(listener);\n return () => {\n this.stateListeners.delete(listener);\n };\n }\n\n getState() {\n return { ...this.state };\n }\n\n private async getRequestHeaders() {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n if (this.headers) {\n const extraHeaders =\n typeof this.headers === \"function\"\n ? await this.headers()\n : this.headers;\n Object.assign(headers, extraHeaders);\n }\n return headers;\n }\n\n private setState(updates: Partial<ClientState<TEvent>>) {\n this.state = { ...this.state, ...updates };\n this.stateListeners.forEach((l) => l(this.getState()));\n }\n\n async *send(\n event: TEvent,\n additionalBody?: Record<string, any>\n ): AsyncGenerator<TEvent> {\n if (this.abortController) this.abortController.abort();\n this.abortController = new AbortController();\n\n const optimisticEvent: TEvent = {\n id: generateId(),\n ...event\n } as TEvent;\n\n this.setState({\n streaming: true,\n error: null,\n events: [...this.state.events, optimisticEvent],\n });\n\n try {\n const headers = await this.getRequestHeaders();\n const response = await fetch(this.url, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n event: optimisticEvent,\n ...additionalBody,\n }),\n signal: this.abortController.signal,\n });\n\n if (!response.ok)\n throw new Error(`HTTP error! status: ${response.status}`);\n if (!response.body) throw new Error(\"No response body\");\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\\n\");\n buffer = lines.pop() || \"\";\n\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue;\n try {\n const incomingEvent: TEvent = JSON.parse(line.slice(6));\n const handled = this.handleIncomingEvent(incomingEvent);\n if (!handled) continue;\n yield incomingEvent;\n } catch (e) {\n console.error(\"Failed to parse event\", e);\n }\n }\n }\n this.setState({ streaming: false });\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") {\n this.setState({ streaming: false });\n return;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n this.setState({ error, streaming: false });\n throw error;\n }\n }\n\n private handleIncomingEvent(event: TEvent) {\n const events = [...this.state.events];\n\n // Replace optimistic event if IDs match, otherwise push\n const index = event.id ? events.findIndex((e) => e.id === event.id) : -1;\n if (index !== -1) {\n events[index] = event;\n } else {\n events.push(event);\n }\n\n this.setState({ events });\n return true;\n }\n\n reset(events: TEvent[] = []) {\n this.stop();\n this.setState({\n events,\n error: null,\n streaming: false,\n });\n }\n\n stop() {\n if (this.abortController) {\n this.abortController.abort();\n this.abortController = null;\n this.setState({ streaming: false });\n }\n }\n}\n"]}
|
package/dist/cli.js
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { MelonyClient } from './chunk-
|
|
2
|
+
import { MelonyClient } from './chunk-7YBEEXMK.js';
|
|
3
3
|
import './chunk-WAI5H335.js';
|
|
4
4
|
import 'dotenv/config';
|
|
5
5
|
import * as readline from 'readline/promises';
|
|
6
|
-
import * as http from 'http';
|
|
7
|
-
import * as fs from 'fs';
|
|
8
6
|
import * as path from 'path';
|
|
9
7
|
import { fileURLToPath } from 'url';
|
|
10
8
|
import { Command } from 'commander';
|
|
11
|
-
import open from 'open';
|
|
12
9
|
|
|
13
|
-
|
|
10
|
+
path.dirname(fileURLToPath(import.meta.url));
|
|
14
11
|
var program = new Command();
|
|
15
12
|
program.name("melony").description("Melony CLI - Fast, minimalist AI agent framework").version("0.1.0");
|
|
16
13
|
program.command("chat").description("Start an interactive chat session with a Melony agent").option("-u, --url <url>", "Server URL", process.env.MELONY_SERVER_URL ?? "http://localhost:4001/api/chat").action(async (options) => {
|
|
@@ -61,73 +58,6 @@ program.command("chat").description("Start an interactive chat session with a Me
|
|
|
61
58
|
console.log("\nGoodbye!");
|
|
62
59
|
rl.close();
|
|
63
60
|
});
|
|
64
|
-
program.command("studio").description("Open Melony Studio").option("-p, --port <port>", "Port to run the studio on", "4000").option("-u, --url <url>", "Agent server BASE_URL", process.env.MELONY_SERVER_URL ?? "http://localhost:4001").action(async (options) => {
|
|
65
|
-
const port = parseInt(options.port);
|
|
66
|
-
const baseUrl = options.url;
|
|
67
|
-
const studioRoot = path.resolve(__dirname$1, "../studio");
|
|
68
|
-
if (!fs.existsSync(studioRoot)) {
|
|
69
|
-
console.error("\u274C Studio files not found. Please run 'pnpm build' in the root first.");
|
|
70
|
-
process.exit(1);
|
|
71
|
-
}
|
|
72
|
-
const server = http.createServer((req, res) => {
|
|
73
|
-
let filePath = path.join(studioRoot, req.url === "/" ? "index.html" : req.url);
|
|
74
|
-
if (!filePath.startsWith(studioRoot)) {
|
|
75
|
-
res.statusCode = 403;
|
|
76
|
-
res.end("Forbidden");
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
if (!fs.existsSync(filePath) || fs.statSync(filePath).isDirectory()) {
|
|
80
|
-
filePath = path.join(studioRoot, "index.html");
|
|
81
|
-
}
|
|
82
|
-
const ext = path.extname(filePath).toLowerCase();
|
|
83
|
-
const mimeTypes = {
|
|
84
|
-
".html": "text/html",
|
|
85
|
-
".js": "text/javascript",
|
|
86
|
-
".css": "text/css",
|
|
87
|
-
".json": "application/json",
|
|
88
|
-
".png": "image/png",
|
|
89
|
-
".jpg": "image/jpg",
|
|
90
|
-
".gif": "image/gif",
|
|
91
|
-
".svg": "image/svg+xml",
|
|
92
|
-
".wav": "audio/wav",
|
|
93
|
-
".mp4": "video/mp4",
|
|
94
|
-
".woff": "application/font-woff",
|
|
95
|
-
".ttf": "application/font-ttf",
|
|
96
|
-
".eot": "application/vnd.ms-fontobject",
|
|
97
|
-
".otf": "application/font-otf",
|
|
98
|
-
".wasm": "application/wasm"
|
|
99
|
-
};
|
|
100
|
-
const contentType = mimeTypes[ext] || "application/octet-stream";
|
|
101
|
-
fs.readFile(filePath, "utf8", (err, content) => {
|
|
102
|
-
if (err) {
|
|
103
|
-
if (err.code === "ENOENT") {
|
|
104
|
-
res.statusCode = 404;
|
|
105
|
-
res.end("File not found");
|
|
106
|
-
} else {
|
|
107
|
-
res.statusCode = 500;
|
|
108
|
-
res.end(`Server error: ${err.code}`);
|
|
109
|
-
}
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
res.writeHead(200, { "Content-Type": contentType });
|
|
113
|
-
if (filePath.endsWith("index.html")) {
|
|
114
|
-
const injectedScript = `<script>window.MELONY_BASE_URL = "${baseUrl}";</script>`;
|
|
115
|
-
content = content.replace("<head>", `<head>${injectedScript}`);
|
|
116
|
-
}
|
|
117
|
-
res.end(content);
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
server.listen(port, () => {
|
|
121
|
-
const studioUrl = `http://localhost:${port}`;
|
|
122
|
-
console.log("------------------------------------------");
|
|
123
|
-
console.log("\u{1F34E} Melony Studio");
|
|
124
|
-
console.log(`Studio running at: ${studioUrl}`);
|
|
125
|
-
console.log(`Connecting to agent server: ${baseUrl}`);
|
|
126
|
-
console.log("Press Ctrl+C to stop");
|
|
127
|
-
console.log("------------------------------------------");
|
|
128
|
-
open(studioUrl);
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
61
|
if (!process.argv.slice(2).length) {
|
|
132
62
|
process.argv.push("chat");
|
|
133
63
|
}
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts"],"names":["__dirname"],"mappings":"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","file":"cli.js","sourcesContent":["#!/usr/bin/env node\nimport \"dotenv/config\";\nimport * as readline from \"node:readline/promises\";\nimport * as http from \"node:http\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { Command } from \"commander\";\nimport open from \"open\";\nimport { MelonyClient } from \"./client\";\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nconst program = new Command();\n\nprogram\n .name(\"melony\")\n .description(\"Melony CLI - Fast, minimalist AI agent framework\")\n .version(\"0.1.0\");\n\nprogram\n .command(\"chat\")\n .description(\"Start an interactive chat session with a Melony agent\")\n .option(\"-u, --url <url>\", \"Server URL\", process.env.MELONY_SERVER_URL ?? \"http://localhost:4001/api/chat\")\n .action(async (options) => {\n const client = new MelonyClient({\n url: options.url,\n });\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n console.log(\"------------------------------------------\");\n console.log(\"🍎 Melony Interactive CLI\");\n console.log(`Connected to: ${options.url}`);\n console.log(\"Type your message and press Enter. Type 'exit' to quit.\");\n console.log(\"------------------------------------------\");\n\n while (true) {\n const input = await rl.question(\"\\nYou: \");\n\n if (input.toLowerCase() === \"exit\" || input.toLowerCase() === \"quit\") {\n break;\n }\n\n if (!input.trim()) continue;\n\n process.stdout.write(\"Agent: \");\n\n try {\n const stream = client.send({\n type: \"user:text\",\n data: { content: input },\n } as any);\n\n let fullResponse = \"\";\n\n for await (const event of stream) {\n if (event.type === \"assistant:text-delta\") {\n const delta = (event.data as any).delta;\n process.stdout.write(delta);\n fullResponse += delta;\n } else if (event.type === \"assistant:text\") {\n if (!fullResponse) {\n process.stdout.write((event.data as any).content);\n }\n } else if (event.type.startsWith(\"action:\")) {\n console.log(`\\n[Action: ${JSON.stringify(event.data, null, 2)}]`);\n }\n }\n process.stdout.write(\"\\n\");\n } catch (error) {\n console.error(\"\\nError:\", error instanceof Error ? error.message : String(error));\n }\n }\n\n console.log(\"\\nGoodbye!\");\n rl.close();\n });\n\nprogram\n .command(\"studio\")\n .description(\"Open Melony Studio\")\n .option(\"-p, --port <port>\", \"Port to run the studio on\", \"4000\")\n .option(\"-u, --url <url>\", \"Agent server BASE_URL\", process.env.MELONY_SERVER_URL ?? \"http://localhost:4001\")\n .action(async (options) => {\n const port = parseInt(options.port);\n const baseUrl = options.url;\n \n // Path to the studio files (relative to the compiled cli.js in dist/)\n const studioRoot = path.resolve(__dirname, \"../studio\");\n \n if (!fs.existsSync(studioRoot)) {\n console.error(\"❌ Studio files not found. Please run 'pnpm build' in the root first.\");\n process.exit(1);\n }\n\n const server = http.createServer((req, res) => {\n let filePath = path.join(studioRoot, req.url === \"/\" ? \"index.html\" : req.url!);\n \n // Basic security: prevent directory traversal\n if (!filePath.startsWith(studioRoot)) {\n res.statusCode = 403;\n res.end(\"Forbidden\");\n return;\n }\n\n // If file doesn't exist, serve index.html (for SPA routing)\n if (!fs.existsSync(filePath) || fs.statSync(filePath).isDirectory()) {\n filePath = path.join(studioRoot, \"index.html\");\n }\n\n const ext = path.extname(filePath).toLowerCase();\n const mimeTypes: Record<string, string> = {\n \".html\": \"text/html\",\n \".js\": \"text/javascript\",\n \".css\": \"text/css\",\n \".json\": \"application/json\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpg\",\n \".gif\": \"image/gif\",\n \".svg\": \"image/svg+xml\",\n \".wav\": \"audio/wav\",\n \".mp4\": \"video/mp4\",\n \".woff\": \"application/font-woff\",\n \".ttf\": \"application/font-ttf\",\n \".eot\": \"application/vnd.ms-fontobject\",\n \".otf\": \"application/font-otf\",\n \".wasm\": \"application/wasm\",\n };\n\n const contentType = mimeTypes[ext] || \"application/octet-stream\";\n\n fs.readFile(filePath, \"utf8\", (err, content) => {\n if (err) {\n if (err.code === \"ENOENT\") {\n res.statusCode = 404;\n res.end(\"File not found\");\n } else {\n res.statusCode = 500;\n res.end(`Server error: ${err.code}`);\n }\n return;\n }\n\n res.writeHead(200, { \"Content-Type\": contentType });\n\n // Inject BASE_URL into index.html\n if (filePath.endsWith(\"index.html\")) {\n const injectedScript = `<script>window.MELONY_BASE_URL = \"${baseUrl}\";</script>`;\n content = content.replace(\"<head>\", `<head>${injectedScript}`);\n }\n\n res.end(content);\n });\n });\n\n server.listen(port, () => {\n const studioUrl = `http://localhost:${port}`;\n console.log(\"------------------------------------------\");\n console.log(\"🍎 Melony Studio\");\n console.log(`Studio running at: ${studioUrl}`);\n console.log(`Connecting to agent server: ${baseUrl}`);\n console.log(\"Press Ctrl+C to stop\");\n console.log(\"------------------------------------------\");\n \n open(studioUrl);\n });\n });\n\n// Default to chat if no command is provided\nif (!process.argv.slice(2).length) {\n process.argv.push(\"chat\");\n}\n\nprogram.parse();\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"names":[],"mappings":"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","file":"cli.js","sourcesContent":["#!/usr/bin/env node\nimport \"dotenv/config\";\nimport * as readline from \"node:readline/promises\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { Command } from \"commander\";\nimport { MelonyClient } from \"./client\";\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nconst program = new Command();\n\nprogram\n .name(\"melony\")\n .description(\"Melony CLI - Fast, minimalist AI agent framework\")\n .version(\"0.1.0\");\n\nprogram\n .command(\"chat\")\n .description(\"Start an interactive chat session with a Melony agent\")\n .option(\"-u, --url <url>\", \"Server URL\", process.env.MELONY_SERVER_URL ?? \"http://localhost:4001/api/chat\")\n .action(async (options) => {\n const client = new MelonyClient({\n url: options.url,\n });\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n console.log(\"------------------------------------------\");\n console.log(\"🍎 Melony Interactive CLI\");\n console.log(`Connected to: ${options.url}`);\n console.log(\"Type your message and press Enter. Type 'exit' to quit.\");\n console.log(\"------------------------------------------\");\n\n while (true) {\n const input = await rl.question(\"\\nYou: \");\n\n if (input.toLowerCase() === \"exit\" || input.toLowerCase() === \"quit\") {\n break;\n }\n\n if (!input.trim()) continue;\n\n process.stdout.write(\"Agent: \");\n\n try {\n const stream = client.send({\n type: \"user:text\",\n data: { content: input },\n } as any);\n\n let fullResponse = \"\";\n\n for await (const event of stream) {\n if (event.type === \"assistant:text-delta\") {\n const delta = (event.data as any).delta;\n process.stdout.write(delta);\n fullResponse += delta;\n } else if (event.type === \"assistant:text\") {\n if (!fullResponse) {\n process.stdout.write((event.data as any).content);\n }\n } else if (event.type.startsWith(\"action:\")) {\n console.log(`\\n[Action: ${JSON.stringify(event.data, null, 2)}]`);\n }\n }\n process.stdout.write(\"\\n\");\n } catch (error) {\n console.error(\"\\nError:\", error instanceof Error ? error.message : String(error));\n }\n }\n\n console.log(\"\\nGoodbye!\");\n rl.close();\n });\n\n// Default to chat if no command is provided\nif (!process.argv.slice(2).length) {\n process.argv.push(\"chat\");\n}\n\nprogram.parse();\n"]}
|
package/dist/client.d.ts
CHANGED
|
@@ -5,16 +5,17 @@ interface ClientState<TEvent extends Event = Event> {
|
|
|
5
5
|
events: TEvent[];
|
|
6
6
|
streaming: boolean;
|
|
7
7
|
error: Error | null;
|
|
8
|
+
context: Record<string, any>;
|
|
8
9
|
}
|
|
9
10
|
interface MelonyClientOptions<TEvent extends Event = Event> {
|
|
10
11
|
url: string;
|
|
11
12
|
initialEvents?: TEvent[];
|
|
13
|
+
initialContext?: Record<string, any>;
|
|
12
14
|
headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
|
|
13
15
|
}
|
|
14
16
|
declare class MelonyClient<TEvent extends Event = Event> {
|
|
15
17
|
private state;
|
|
16
18
|
readonly url: string;
|
|
17
|
-
readonly runId: string;
|
|
18
19
|
private headers?;
|
|
19
20
|
private lastServerState;
|
|
20
21
|
private abortController;
|
|
@@ -25,12 +26,14 @@ declare class MelonyClient<TEvent extends Event = Event> {
|
|
|
25
26
|
events: TEvent[];
|
|
26
27
|
streaming: boolean;
|
|
27
28
|
error: Error | null;
|
|
29
|
+
context: Record<string, any>;
|
|
28
30
|
};
|
|
29
31
|
private getRequestHeaders;
|
|
30
32
|
private setState;
|
|
31
|
-
send(event: TEvent): AsyncGenerator<TEvent>;
|
|
33
|
+
send(event: TEvent, additionalBody?: Record<string, any>): AsyncGenerator<TEvent>;
|
|
32
34
|
private handleIncomingEvent;
|
|
33
35
|
reset(events?: TEvent[]): void;
|
|
36
|
+
stop(): void;
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
export { type ClientState, Event, MelonyClient, type MelonyClientOptions };
|
package/dist/client.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -160,13 +160,13 @@ var MelonyBuilder = class {
|
|
|
160
160
|
async jsonResponse(event, options) {
|
|
161
161
|
const targetType = options?.targetType ?? "ui";
|
|
162
162
|
const runtime = this.build();
|
|
163
|
-
let
|
|
163
|
+
let data = null;
|
|
164
164
|
for await (const e of runtime.run(event, options)) {
|
|
165
165
|
if (e.type === targetType) {
|
|
166
|
-
|
|
166
|
+
data = e.data;
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
|
-
return new Response(JSON.stringify(
|
|
169
|
+
return new Response(JSON.stringify({ data }), {
|
|
170
170
|
headers: { "Content-Type": "application/json" }
|
|
171
171
|
});
|
|
172
172
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runtime.ts","../src/melony.ts","../src/utils/create-stream-response.ts","../src/builder.ts"],"names":["event"],"mappings":"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","file":"index.js","sourcesContent":["import {\n Event,\n RuntimeContext,\n Config,\n} from \"./types\";\nimport { generateId } from \"./utils/generate-id\";\n\n/**\n * Helper to check if a value is a Melony Event.\n */\nfunction isEvent(val: any): val is Event {\n return val && typeof val === \"object\" && typeof val.type === \"string\";\n}\n\n/**\n * The Melony Runtime.\n * Fully unopinionated - processes events through handlers.\n */\nexport class Runtime<TState = any, TEvent extends Event = Event> {\n public readonly config: Config<TState, TEvent>;\n private queue: TEvent[] = [];\n private isEmitting = false;\n\n constructor(config: Config<TState, TEvent>) {\n this.config = config;\n }\n\n /**\n * Process an incoming event through the runtime.\n * All event processing is handled by user-defined event handlers.\n */\n public async *run(\n event: TEvent, \n options?: { state?: TState; runId?: string }\n ): AsyncGenerator<TEvent> {\n const runId = options?.runId ?? generateId();\n \n const context: RuntimeContext<TState, TEvent> = {\n state: (options?.state ?? {}) as TState,\n runtime: this,\n runId,\n suspend: (event?: TEvent) => {\n throw event || { type: \"run-suspended\", data: {} };\n },\n };\n\n try {\n // Process the incoming event through handlers\n yield* this.runEventHandlers(event, context);\n } catch (error) {\n let eventToEmit: TEvent | undefined;\n\n if (isEvent(error)) {\n eventToEmit = error as TEvent;\n } else {\n eventToEmit = {\n type: \"error\",\n data: {\n message: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n },\n } as TEvent;\n }\n\n if (eventToEmit) {\n yield* this.emit(eventToEmit, context);\n }\n }\n }\n\n\n /**\n * Run all event handlers that match the given event type.\n */\n private async *runEventHandlers(\n event: TEvent,\n context?: RuntimeContext<TState, TEvent>,\n ): AsyncGenerator<TEvent> {\n const handlers = [\n ...(this.config.eventHandlers.get(event.type) || []),\n ...(this.config.eventHandlers.get(\"*\") || []),\n ];\n \n // First emit the event itself\n yield* this.emit(event, context);\n\n for (const handler of handlers) {\n const result = handler(event, context);\n if (result) {\n for await (const yieldedEvent of result) {\n // Recursively process yielded events through their handlers\n yield* this.runEventHandlers(yieldedEvent, context);\n }\n }\n }\n }\n\n /**\n * Internal helper to yield an event with metadata.\n */\n private async *emit(\n event: TEvent,\n context?: RuntimeContext<TState, TEvent>,\n ): AsyncGenerator<TEvent> {\n this.queue.push(event);\n\n if (this.isEmitting) return;\n\n this.isEmitting = true;\n try {\n while (this.queue.length > 0) {\n const current = this.queue.shift()!;\n yield current;\n }\n } finally {\n this.isEmitting = false;\n }\n }\n}\n","import { Runtime } from \"./runtime\";\n\nexport const MelonyRuntime = Runtime;","import { Event } from \"../types\";\n\n/**\n * Convert an async generator of events to an HTTP streaming response\n * Exported for backward compatibility and standalone usage\n */\nexport function createStreamResponse(\n generator: AsyncGenerator<Event>,\n): Response {\n const encoder = new TextEncoder();\n const stream = new ReadableStream({\n async start(controller) {\n try {\n for await (const message of generator) {\n // Format as SSE: data: {...}\\n\\n\n const chunk = `data: ${JSON.stringify(message)}\\n\\n`;\n controller.enqueue(encoder.encode(chunk));\n }\n controller.close();\n } catch (error) {\n controller.error(error);\n }\n },\n });\n\n return new Response(stream, {\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n },\n });\n}\n","import {\n Event,\n EventHandler,\n Config,\n RuntimeContext,\n} from \"./types\";\nimport { Runtime } from \"./runtime\";\nimport { createStreamResponse } from \"./utils/create-stream-response\";\n\n/**\n * A Melony plugin is a function that receives the builder and extends it.\n * This allows for modularizing common handlers.\n */\nexport type MelonyPlugin<TState = any, TEvent extends Event = Event> = (\n builder: MelonyBuilder<TState, TEvent>\n) => void;\n\n/**\n * Fluent builder for creating Melony agents with excellent developer experience.\n * Provides method chaining for handlers and plugins with full TypeScript support.\n */\nexport class MelonyBuilder<\n TState = any,\n TEvent extends Event = Event\n> {\n private config: Config<TState, TEvent>;\n\n constructor(initialConfig?: Partial<Config<TState, TEvent>>) {\n this.config = {\n eventHandlers: initialConfig?.eventHandlers ?? new Map(),\n };\n }\n\n /**\n * Add an event handler for a specific event type. Supports method chaining.\n * The handler receives the narrowed event type based on the eventType string.\n */\n on<K extends TEvent[\"type\"]>(\n eventType: K,\n handler: (\n event: Extract<TEvent, { type: K }>,\n context: RuntimeContext<TState, TEvent>\n ) => AsyncGenerator<TEvent, void, unknown> | void\n ): this {\n if (!this.config.eventHandlers.has(eventType)) {\n this.config.eventHandlers.set(eventType, []);\n }\n // Cast is safe because runtime only calls this handler for matching event types\n this.config.eventHandlers.get(eventType)!.push(handler as EventHandler<TState, TEvent>);\n return this;\n }\n\n /**\n * Use a plugin to extend the builder.\n * This is ideal for modularizing common handlers.\n */\n use(plugin: MelonyPlugin<TState, TEvent>): this {\n plugin(this);\n return this;\n }\n\n /**\n * Build and return the Melony runtime instance.\n * This is the final method in the fluent chain.\n */\n build(): Runtime<TState, TEvent> {\n return new Runtime(this.config);\n }\n\n /**\n * Execute and stream the response for an event.\n * This is a convenience method that builds the runtime and calls run().\n */\n async streamResponse(\n event: TEvent,\n options?: { state?: TState; runId?: string }\n ): Promise<Response> {\n const runtime = this.build();\n const generator = runtime.run(event, options);\n return createStreamResponse(generator);\n }\n\n /**\n * Execute the agent and return the data from the last event of a specific type as a JSON response.\n * Ideal for initialization or non-streaming requests where you only need the final UI state.\n */\n async jsonResponse(\n event: TEvent,\n options?: {\n state?: TState;\n runId?: string;\n targetType?: string; // Default to \"ui\"\n }\n ): Promise<Response> {\n const targetType = options?.targetType ?? \"ui\";\n const runtime = this.build();\n let result = null;\n\n for await (const e of runtime.run(event, options)) {\n if (e.type === targetType) {\n result = e.data;\n }\n }\n\n return new Response(JSON.stringify(result), {\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n /**\n * Get the current configuration (useful for debugging or serialization).\n */\n getConfig(): Config<TState, TEvent> {\n return { ...this.config };\n }\n}\n\n/**\n * Factory function to create a new Melony builder instance.\n * This is the entry point for the fluent API.\n */\nexport function melony<\n TState = any,\n TEvent extends Event = Event\n>(initialConfig?: Partial<Config<TState, TEvent>>): MelonyBuilder<TState, TEvent> {\n return new MelonyBuilder<TState, TEvent>(initialConfig);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/runtime.ts","../src/melony.ts","../src/utils/create-stream-response.ts","../src/builder.ts"],"names":["event"],"mappings":"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","file":"index.js","sourcesContent":["import {\n Event,\n RuntimeContext,\n Config,\n} from \"./types\";\nimport { generateId } from \"./utils/generate-id\";\n\n/**\n * Helper to check if a value is a Melony Event.\n */\nfunction isEvent(val: any): val is Event {\n return val && typeof val === \"object\" && typeof val.type === \"string\";\n}\n\n/**\n * The Melony Runtime.\n * Fully unopinionated - processes events through handlers.\n */\nexport class Runtime<TState = any, TEvent extends Event = Event> {\n public readonly config: Config<TState, TEvent>;\n private queue: TEvent[] = [];\n private isEmitting = false;\n\n constructor(config: Config<TState, TEvent>) {\n this.config = config;\n }\n\n /**\n * Process an incoming event through the runtime.\n * All event processing is handled by user-defined event handlers.\n */\n public async *run(\n event: TEvent, \n options?: { state?: TState; runId?: string }\n ): AsyncGenerator<TEvent> {\n const runId = options?.runId ?? generateId();\n \n const context: RuntimeContext<TState, TEvent> = {\n state: (options?.state ?? {}) as TState,\n runtime: this,\n runId,\n suspend: (event?: TEvent) => {\n throw event || { type: \"run-suspended\", data: {} };\n },\n };\n\n try {\n // Process the incoming event through handlers\n yield* this.runEventHandlers(event, context);\n } catch (error) {\n let eventToEmit: TEvent | undefined;\n\n if (isEvent(error)) {\n eventToEmit = error as TEvent;\n } else {\n eventToEmit = {\n type: \"error\",\n data: {\n message: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n },\n } as TEvent;\n }\n\n if (eventToEmit) {\n yield* this.emit(eventToEmit, context);\n }\n }\n }\n\n\n /**\n * Run all event handlers that match the given event type.\n */\n private async *runEventHandlers(\n event: TEvent,\n context?: RuntimeContext<TState, TEvent>,\n ): AsyncGenerator<TEvent> {\n const handlers = [\n ...(this.config.eventHandlers.get(event.type) || []),\n ...(this.config.eventHandlers.get(\"*\") || []),\n ];\n \n // First emit the event itself\n yield* this.emit(event, context);\n\n for (const handler of handlers) {\n const result = handler(event, context);\n if (result) {\n for await (const yieldedEvent of result) {\n // Recursively process yielded events through their handlers\n yield* this.runEventHandlers(yieldedEvent, context);\n }\n }\n }\n }\n\n /**\n * Internal helper to yield an event with metadata.\n */\n private async *emit(\n event: TEvent,\n context?: RuntimeContext<TState, TEvent>,\n ): AsyncGenerator<TEvent> {\n this.queue.push(event);\n\n if (this.isEmitting) return;\n\n this.isEmitting = true;\n try {\n while (this.queue.length > 0) {\n const current = this.queue.shift()!;\n yield current;\n }\n } finally {\n this.isEmitting = false;\n }\n }\n}\n","import { Runtime } from \"./runtime\";\n\nexport const MelonyRuntime = Runtime;","import { Event } from \"../types\";\n\n/**\n * Convert an async generator of events to an HTTP streaming response\n * Exported for backward compatibility and standalone usage\n */\nexport function createStreamResponse(\n generator: AsyncGenerator<Event>,\n): Response {\n const encoder = new TextEncoder();\n const stream = new ReadableStream({\n async start(controller) {\n try {\n for await (const message of generator) {\n // Format as SSE: data: {...}\\n\\n\n const chunk = `data: ${JSON.stringify(message)}\\n\\n`;\n controller.enqueue(encoder.encode(chunk));\n }\n controller.close();\n } catch (error) {\n controller.error(error);\n }\n },\n });\n\n return new Response(stream, {\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n },\n });\n}\n","import {\n Event,\n EventHandler,\n Config,\n RuntimeContext,\n} from \"./types\";\nimport { Runtime } from \"./runtime\";\nimport { createStreamResponse } from \"./utils/create-stream-response\";\n\n/**\n * A Melony plugin is a function that receives the builder and extends it.\n * This allows for modularizing common handlers.\n */\nexport type MelonyPlugin<TState = any, TEvent extends Event = Event> = (\n builder: MelonyBuilder<TState, TEvent>\n) => void;\n\n/**\n * Fluent builder for creating Melony agents with excellent developer experience.\n * Provides method chaining for handlers and plugins with full TypeScript support.\n */\nexport class MelonyBuilder<\n TState = any,\n TEvent extends Event = Event\n> {\n private config: Config<TState, TEvent>;\n\n constructor(initialConfig?: Partial<Config<TState, TEvent>>) {\n this.config = {\n eventHandlers: initialConfig?.eventHandlers ?? new Map(),\n };\n }\n\n /**\n * Add an event handler for a specific event type. Supports method chaining.\n * The handler receives the narrowed event type based on the eventType string.\n */\n on<K extends TEvent[\"type\"]>(\n eventType: K,\n handler: (\n event: Extract<TEvent, { type: K }>,\n context: RuntimeContext<TState, TEvent>\n ) => AsyncGenerator<TEvent, void, unknown> | void\n ): this {\n if (!this.config.eventHandlers.has(eventType)) {\n this.config.eventHandlers.set(eventType, []);\n }\n // Cast is safe because runtime only calls this handler for matching event types\n this.config.eventHandlers.get(eventType)!.push(handler as EventHandler<TState, TEvent>);\n return this;\n }\n\n /**\n * Use a plugin to extend the builder.\n * This is ideal for modularizing common handlers.\n */\n use(plugin: MelonyPlugin<TState, TEvent>): this {\n plugin(this);\n return this;\n }\n\n /**\n * Build and return the Melony runtime instance.\n * This is the final method in the fluent chain.\n */\n build(): Runtime<TState, TEvent> {\n return new Runtime(this.config);\n }\n\n /**\n * Execute and stream the response for an event.\n * This is a convenience method that builds the runtime and calls run().\n */\n async streamResponse(\n event: TEvent,\n options?: { state?: TState; runId?: string }\n ): Promise<Response> {\n const runtime = this.build();\n const generator = runtime.run(event, options);\n return createStreamResponse(generator);\n }\n\n /**\n * Execute the agent and return the data from the last event of a specific type as a JSON response.\n * Ideal for initialization or non-streaming requests where you only need the final UI state.\n */\n async jsonResponse(\n event: TEvent,\n options?: {\n state?: TState;\n runId?: string;\n targetType?: string; // Default to \"ui\"\n }\n ): Promise<Response> {\n const targetType = options?.targetType ?? \"ui\";\n const runtime = this.build();\n let data = null;\n\n for await (const e of runtime.run(event, options)) {\n if (e.type === targetType) {\n data = e.data;\n }\n }\n\n return new Response(JSON.stringify({ data }), {\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n /**\n * Get the current configuration (useful for debugging or serialization).\n */\n getConfig(): Config<TState, TEvent> {\n return { ...this.config };\n }\n}\n\n/**\n * Factory function to create a new Melony builder instance.\n * This is the entry point for the fluent API.\n */\nexport function melony<\n TState = any,\n TEvent extends Event = Event\n>(initialConfig?: Partial<Config<TState, TEvent>>): MelonyBuilder<TState, TEvent> {\n return new MelonyBuilder<TState, TEvent>(initialConfig);\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "melony",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.7",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -36,8 +36,7 @@
|
|
|
36
36
|
"module": "dist/index.js",
|
|
37
37
|
"types": "dist/index.d.ts",
|
|
38
38
|
"files": [
|
|
39
|
-
"dist"
|
|
40
|
-
"studio"
|
|
39
|
+
"dist"
|
|
41
40
|
],
|
|
42
41
|
"devDependencies": {
|
|
43
42
|
"@types/node": "^24.10.1",
|
|
@@ -47,13 +46,11 @@
|
|
|
47
46
|
},
|
|
48
47
|
"dependencies": {
|
|
49
48
|
"commander": "^14.0.2",
|
|
50
|
-
"dotenv": "^16.4.5"
|
|
51
|
-
"open": "^11.0.0"
|
|
49
|
+
"dotenv": "^16.4.5"
|
|
52
50
|
},
|
|
53
51
|
"scripts": {
|
|
54
|
-
"build": "tsup
|
|
55
|
-
"
|
|
56
|
-
"clean": "rimraf dist studio",
|
|
52
|
+
"build": "tsup",
|
|
53
|
+
"clean": "rimraf dist",
|
|
57
54
|
"dev": "tsup --watch",
|
|
58
55
|
"typecheck": "tsc --noEmit"
|
|
59
56
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"chunk-7DSKO2W5.js","sourcesContent":["import { Event } from \"./types\";\nimport { generateId } from \"./utils/generate-id\";\n\nexport type { Event };\nexport { generateId };\n\nexport interface ClientState<TEvent extends Event = Event> {\n events: TEvent[];\n streaming: boolean;\n error: Error | null;\n}\n\nexport interface MelonyClientOptions<TEvent extends Event = Event> {\n url: string;\n initialEvents?: TEvent[];\n headers?:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>);\n}\n\nexport class MelonyClient<TEvent extends Event = Event> {\n private state: ClientState<TEvent>;\n public readonly url: string;\n public readonly runId: string;\n private headers?: MelonyClientOptions<TEvent>[\"headers\"];\n private lastServerState: any = null;\n private abortController: AbortController | null = null;\n private stateListeners: Set<(state: ClientState<TEvent>) => void> = new Set();\n\n constructor(options: MelonyClientOptions<TEvent>) {\n this.url = options.url;\n this.headers = options.headers;\n this.runId = generateId();\n this.state = {\n events: options.initialEvents ?? [],\n streaming: false,\n error: null,\n };\n }\n\n subscribe(listener: (state: ClientState<TEvent>) => void) {\n this.stateListeners.add(listener);\n return () => {\n this.stateListeners.delete(listener);\n };\n }\n\n getState() {\n return { ...this.state };\n }\n\n private async getRequestHeaders() {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n if (this.headers) {\n const extraHeaders =\n typeof this.headers === \"function\"\n ? await this.headers()\n : this.headers;\n Object.assign(headers, extraHeaders);\n }\n return headers;\n }\n\n private setState(updates: Partial<ClientState<TEvent>>) {\n this.state = { ...this.state, ...updates };\n this.stateListeners.forEach((l) => l(this.getState()));\n }\n\n async *send(event: TEvent): AsyncGenerator<TEvent> {\n if (this.abortController) this.abortController.abort();\n this.abortController = new AbortController();\n\n const optimisticEvent: TEvent = {\n id: generateId(),\n ...event\n } as TEvent;\n\n this.setState({\n streaming: true,\n error: null,\n events: [...this.state.events, optimisticEvent],\n });\n\n try {\n const headers = await this.getRequestHeaders();\n const response = await fetch(this.url, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ \n event: optimisticEvent,\n runId: this.runId,\n }),\n signal: this.abortController.signal,\n });\n\n if (!response.ok)\n throw new Error(`HTTP error! status: ${response.status}`);\n if (!response.body) throw new Error(\"No response body\");\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\\n\");\n buffer = lines.pop() || \"\";\n\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue;\n try {\n const incomingEvent: TEvent = JSON.parse(line.slice(6));\n this.handleIncomingEvent(incomingEvent);\n yield incomingEvent;\n } catch (e) {\n console.error(\"Failed to parse event\", e);\n }\n }\n }\n this.setState({ streaming: false });\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") {\n this.setState({ streaming: false });\n return;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n this.setState({ error, streaming: false });\n throw error;\n }\n }\n\n private handleIncomingEvent(event: TEvent) {\n const events = [...this.state.events];\n\n // Replace optimistic event if IDs match, otherwise push\n const index = event.id ? events.findIndex((e) => e.id === event.id) : -1;\n if (index !== -1) {\n events[index] = event;\n } else {\n events.push(event);\n }\n\n this.setState({ events });\n }\n\n reset(events: TEvent[] = []) {\n if (this.abortController) this.abortController.abort();\n this.setState({\n events,\n error: null,\n streaming: false,\n });\n }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking: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-duration:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--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}}}@layer theme{:root,:host{--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-yellow-500:oklch(79.5% .184 86.047);--color-yellow-600:oklch(68.1% .162 75.834);--color-green-500:oklch(72.3% .219 149.579);--color-green-600:oklch(62.7% .194 149.214);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-gray-300:oklch(87.2% .01 258.338);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-lg:32rem;--container-2xl:42rem;--container-3xl:48rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--text-3xl:1.875rem;--text-3xl--line-height: 1.2 ;--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5/2.25);--text-5xl:3rem;--text-5xl--line-height:1;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--leading-snug:1.375;--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4,0,.6,1)infinite;--blur-sm:8px;--aspect-video:16/9;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:"Inter Variable",sans-serif;--default-mono-font-family:var(--font-mono)}}@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,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}*{border-color:var(--border);outline-color:var(--ring)}@supports (color:color-mix(in lab,red,red)){*{outline-color:color-mix(in oklab,var(--ring)50%,transparent)}}body{background-color:var(--background);width:100vw;height:100vh;color:var(--foreground);font-family:Inter Variable,sans-serif}#root{width:100vw;height:100vh}html{font-family:Inter Variable,sans-serif}}@layer components;@layer utilities{.\@container\/card-header{container:card-header/inline-size}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.inset-0{inset:calc(var(--spacing)*0)}.-top-12{top:calc(var(--spacing)*-12)}.top-0{top:calc(var(--spacing)*0)}.top-1{top:calc(var(--spacing)*1)}.top-1\/2{top:50%}.top-4{top:calc(var(--spacing)*4)}.top-\[50\%\]{top:50%}.right-0{right:calc(var(--spacing)*0)}.right-1{right:calc(var(--spacing)*1)}.right-2{right:calc(var(--spacing)*2)}.right-4{right:calc(var(--spacing)*4)}.-bottom-10{bottom:calc(var(--spacing)*-10)}.bottom-0{bottom:calc(var(--spacing)*0)}.bottom-1{bottom:calc(var(--spacing)*1)}.left-1{left:calc(var(--spacing)*1)}.left-1\/2{left:50%}.left-4{left:calc(var(--spacing)*4)}.left-\[50\%\]{left:50%}.isolate{isolation:isolate}.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}}.m-0{margin:calc(var(--spacing)*0)}.m-1{margin:calc(var(--spacing)*1)}.m-2{margin:calc(var(--spacing)*2)}.m-4{margin:calc(var(--spacing)*4)}.m-6{margin:calc(var(--spacing)*6)}.m-8{margin:calc(var(--spacing)*8)}.m-12{margin:calc(var(--spacing)*12)}.mx-auto{margin-inline:auto}.mt-8{margin-top:calc(var(--spacing)*8)}.mr-2{margin-right:calc(var(--spacing)*2)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.ml-1{margin-left:calc(var(--spacing)*1)}.ml-2{margin-left:calc(var(--spacing)*2)}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.field-sizing-content{field-sizing:content}.aspect-\[4\/3\]{aspect-ratio:4/3}.aspect-\[9\/16\]{aspect-ratio:9/16}.aspect-square{aspect-ratio:1}.aspect-video{aspect-ratio:var(--aspect-video)}.size-4{width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}.size-6{width:calc(var(--spacing)*6);height:calc(var(--spacing)*6)}.size-8{width:calc(var(--spacing)*8);height:calc(var(--spacing)*8)}.size-9{width:calc(var(--spacing)*9);height:calc(var(--spacing)*9)}.size-10{width:calc(var(--spacing)*10);height:calc(var(--spacing)*10)}.h-4{height:calc(var(--spacing)*4)}.h-5{height:calc(var(--spacing)*5)}.h-6{height:calc(var(--spacing)*6)}.h-8{height:calc(var(--spacing)*8)}.h-9{height:calc(var(--spacing)*9)}.h-10{height:calc(var(--spacing)*10)}.h-auto{height:auto}.h-full{height:100%}.max-h-\(--available-height\){max-height:var(--available-height)}.max-h-96{max-height:calc(var(--spacing)*96)}.max-h-\[85vh\]{max-height:85vh}.max-h-\[90vh\]{max-height:90vh}.max-h-\[200px\]{max-height:200px}.min-h-16{min-height:calc(var(--spacing)*16)}.min-h-\[44px\]{min-height:44px}.min-h-\[50vh\]{min-height:50vh}.w-\(--anchor-width\){width:var(--anchor-width)}.w-1\/2{width:50%}.w-1\/3{width:33.3333%}.w-1\/4{width:25%}.w-2\/3{width:66.6667%}.w-3\/4{width:75%}.w-4{width:calc(var(--spacing)*4)}.w-6{width:calc(var(--spacing)*6)}.w-8{width:calc(var(--spacing)*8)}.w-10{width:calc(var(--spacing)*10)}.w-32{width:calc(var(--spacing)*32)}.w-64{width:calc(var(--spacing)*64)}.w-auto{width:auto}.w-fit{width:fit-content}.w-full{width:100%}.w-max{width:max-content}.w-min{width:min-content}.max-w-2xl{max-width:var(--container-2xl)}.max-w-3xl{max-width:var(--container-3xl)}.max-w-\[85\%\]{max-width:85%}.max-w-\[90vw\]{max-width:90vw}.max-w-full{max-width:100%}.max-w-lg{max-width:var(--container-lg)}.min-w-0{min-width:calc(var(--spacing)*0)}.min-w-36{min-width:calc(var(--spacing)*36)}.min-w-48{min-width:calc(var(--spacing)*48)}.min-w-96{min-width:calc(var(--spacing)*96)}.flex-1{flex:1}.shrink-0{flex-shrink:0}.origin-\(--transform-origin\){transform-origin:var(--transform-origin)}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x)var(--tw-translate-y)}.translate-x-\[-50\%\]{--tw-translate-x:-50%;translate:var(--tw-translate-x)var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y: -50% ;translate:var(--tw-translate-x)var(--tw-translate-y)}.translate-y-\[-50\%\]{--tw-translate-y:-50%;translate:var(--tw-translate-x)var(--tw-translate-y)}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.resize{resize:both}.resize-none{resize:none}.list-none{list-style-type:none}.auto-rows-min{grid-auto-rows:min-content}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-row{flex-direction:row}.flex-nowrap{flex-wrap:nowrap}.flex-wrap{flex-wrap:wrap}.flex-wrap-reverse{flex-wrap:wrap-reverse}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.items-stretch{align-items:stretch}.justify-around{justify-content:space-around}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-start{justify-content:flex-start}.gap-0{gap:calc(var(--spacing)*0)}.gap-1{gap:calc(var(--spacing)*1)}.gap-1\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.gap-2\.5{gap:calc(var(--spacing)*2.5)}.gap-3{gap:calc(var(--spacing)*3)}.gap-4{gap:calc(var(--spacing)*4)}.gap-6{gap:calc(var(--spacing)*6)}.gap-8{gap:calc(var(--spacing)*8)}.gap-12{gap:calc(var(--spacing)*12)}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*4)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*6)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*6)*calc(1 - var(--tw-space-y-reverse)))}.overflow-hidden{overflow:hidden}.overflow-visible{overflow:visible}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:calc(var(--radius) + 8px)}.rounded-3xl{border-radius:calc(var(--radius) + 12px)}.rounded-4xl{border-radius:calc(var(--radius) + 16px)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-none{border-radius:0}.rounded-sm{border-radius:calc(var(--radius) - 4px)}.rounded-xl{border-radius:calc(var(--radius) + 4px)}.rounded-t-xl{border-top-left-radius:calc(var(--radius) + 4px);border-top-right-radius:calc(var(--radius) + 4px)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-\[1\.5px\]{border-style:var(--tw-border-style);border-width:1.5px}.border-none{--tw-border-style:none;border-style:none}.border-background{border-color:var(--background)}.border-blue-500{border-color:var(--color-blue-500)}.border-border{border-color:var(--border)}.border-destructive,.border-destructive\/20{border-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.border-destructive\/20{border-color:color-mix(in oklab,var(--destructive)20%,transparent)}}.border-foreground{border-color:var(--foreground)}.border-gray-300{border-color:var(--color-gray-300)}.border-green-500{border-color:var(--color-green-500)}.border-input{border-color:var(--input)}.border-muted{border-color:var(--muted)}.border-muted-foreground{border-color:var(--muted-foreground)}.border-primary{border-color:var(--primary)}.border-secondary{border-color:var(--secondary)}.border-transparent{border-color:#0000}.border-yellow-500{border-color:var(--color-yellow-500)}.bg-background{background-color:var(--background)}.bg-black{background-color:var(--color-black)}.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-black\/80{background-color:#000c}@supports (color:color-mix(in lab,red,red)){.bg-black\/80{background-color:color-mix(in oklab,var(--color-black)80%,transparent)}}.bg-blue-500{background-color:var(--color-blue-500)}.bg-border{background-color:var(--border)}.bg-card{background-color:var(--card)}.bg-destructive,.bg-destructive\/5{background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.bg-destructive\/5{background-color:color-mix(in oklab,var(--destructive)5%,transparent)}}.bg-destructive\/10{background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.bg-destructive\/10{background-color:color-mix(in oklab,var(--destructive)10%,transparent)}}.bg-foreground{background-color:var(--foreground)}.bg-green-500{background-color:var(--color-green-500)}.bg-input\/30{background-color:var(--input)}@supports (color:color-mix(in lab,red,red)){.bg-input\/30{background-color:color-mix(in oklab,var(--input)30%,transparent)}}.bg-muted{background-color:var(--muted)}.bg-muted-foreground{background-color:var(--muted-foreground)}.bg-popover{background-color:var(--popover)}.bg-primary{background-color:var(--primary)}.bg-secondary{background-color:var(--secondary)}.bg-transparent{background-color:#0000}.bg-yellow-500{background-color:var(--color-yellow-500)}.bg-clip-padding{background-clip:padding-box}.fill-muted-foreground{fill:var(--muted-foreground)}.fill-popover-foreground{fill:var(--popover-foreground)}.object-contain{object-fit:contain}.object-cover{object-fit:cover}.object-fill{object-fit:fill}.p-0{padding:calc(var(--spacing)*0)}.p-1{padding:calc(var(--spacing)*1)}.p-2{padding:calc(var(--spacing)*2)}.p-3{padding:calc(var(--spacing)*3)}.p-4{padding:calc(var(--spacing)*4)}.p-6{padding:calc(var(--spacing)*6)}.p-8{padding:calc(var(--spacing)*8)}.p-12{padding:calc(var(--spacing)*12)}.px-0{padding-inline:calc(var(--spacing)*0)}.px-1{padding-inline:calc(var(--spacing)*1)}.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-6{padding-inline:calc(var(--spacing)*6)}.py-0{padding-block:calc(var(--spacing)*0)}.py-0\.5{padding-block:calc(var(--spacing)*.5)}.py-1{padding-block:calc(var(--spacing)*1)}.py-2{padding-block:calc(var(--spacing)*2)}.py-3{padding-block:calc(var(--spacing)*3)}.py-4{padding-block:calc(var(--spacing)*4)}.py-6{padding-block:calc(var(--spacing)*6)}.pr-8{padding-right:calc(var(--spacing)*8)}.pb-2{padding-bottom:calc(var(--spacing)*2)}.pb-3{padding-bottom:calc(var(--spacing)*3)}.pb-36{padding-bottom:calc(var(--spacing)*36)}.pl-3{padding-left:calc(var(--spacing)*3)}.text-center{text-align:center}.text-justify{text-align:justify}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[15px\]{font-size:15px}.leading-none{--tw-leading:1;line-height:1}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-\[0\]{color:0}.text-background{color:var(--background)}.text-blue-600{color:var(--color-blue-600)}.text-border{color:var(--border)}.text-card-foreground{color:var(--card-foreground)}.text-destructive{color:var(--destructive)}.text-foreground{color:var(--foreground)}.text-green-600{color:var(--color-green-600)}.text-muted{color:var(--muted)}.text-muted-foreground{color:var(--muted-foreground)}.text-popover-foreground{color:var(--popover-foreground)}.text-primary{color:var(--primary)}.text-primary-foreground{color:var(--primary-foreground)}.text-secondary{color:var(--secondary)}.text-secondary-foreground{color:var(--secondary-foreground)}.text-transparent{color:#0000}.text-white{color:var(--color-white)}.text-yellow-600{color:var(--color-yellow-600)}.uppercase{text-transform:uppercase}.underline-offset-4{text-underline-offset:4px}.opacity-0{opacity:0}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.opacity-100{opacity:1}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);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 6px -1px var(--tw-shadow-color,#0000001a),0 2px 4px -2px var(--tw-shadow-color,#0000001a);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 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a),0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-1{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-2{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-foreground\/5{--tw-ring-color:var(--foreground)}@supports (color:color-mix(in lab,red,red)){.ring-foreground\/5{--tw-ring-color:color-mix(in oklab,var(--foreground)5%,transparent)}}.ring-foreground\/10{--tw-ring-color:var(--foreground)}@supports (color:color-mix(in lab,red,red)){.ring-foreground\/10{--tw-ring-color:color-mix(in oklab,var(--foreground)10%,transparent)}}.ring-primary{--tw-ring-color:var(--primary)}.ring-offset-1{--tw-ring-offset-width:1px;--tw-ring-offset-shadow:var(--tw-ring-inset,)0 0 0 var(--tw-ring-offset-width)var(--tw-ring-offset-color)}.ring-offset-background{--tw-ring-offset-color:var(--background)}.outline-hidden{--tw-outline-style:none;outline-style:none}@media(forced-colors:active){.outline-hidden{outline-offset:2px;outline:2px solid #0000}}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.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))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-100{--tw-duration:.1s;transition-duration:.1s}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-1000{--tw-duration:1s;transition-duration:1s}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}@media(hover:hover){.group-hover\:text-primary:is(:where(.group):hover *){color:var(--primary)}.group-hover\:opacity-100:is(:where(.group):hover *),.group-hover\/lightbox\:opacity-100:is(:where(.group\/lightbox):hover *){opacity:1}}.group-data-\[disabled\=true\]\:pointer-events-none:is(:where(.group)[data-disabled=true] *){pointer-events:none}.group-data-\[disabled\=true\]\:opacity-50:is(:where(.group)[data-disabled=true] *),.group-data-\[disabled\=true\]\/field\:opacity-50:is(:where(.group\/field)[data-disabled=true] *){opacity:.5}.group-data-\[size\=sm\]\/card\:px-4:is(:where(.group\/card)[data-size=sm] *){padding-inline:calc(var(--spacing)*4)}.peer-disabled\:cursor-not-allowed:is(:where(.peer):disabled~*){cursor:not-allowed}.peer-disabled\:opacity-50:is(:where(.peer):disabled~*){opacity:.5}.file\:inline-flex::file-selector-button{display:inline-flex}.file\:h-7::file-selector-button{height:calc(var(--spacing)*7)}.file\:border-0::file-selector-button{border-style:var(--tw-border-style);border-width:0}.file\:bg-transparent::file-selector-button{background-color:#0000}.file\:text-sm::file-selector-button{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.file\:font-medium::file-selector-button{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.file\:text-foreground::file-selector-button{color:var(--foreground)}.placeholder\:text-muted-foreground::placeholder{color:var(--muted-foreground)}.focus-within\:border-ring:focus-within{border-color:var(--ring)}@media(hover:hover){.hover\:scale-105:hover{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x)var(--tw-scale-y)}.hover\:scale-110:hover{--tw-scale-x:110%;--tw-scale-y:110%;--tw-scale-z:110%;scale:var(--tw-scale-x)var(--tw-scale-y)}.hover\:border-accent-foreground\/20:hover{border-color:var(--accent-foreground)}@supports (color:color-mix(in lab,red,red)){.hover\:border-accent-foreground\/20:hover{border-color:color-mix(in oklab,var(--accent-foreground)20%,transparent)}}.hover\:bg-accent:hover{background-color:var(--accent)}.hover\:bg-black\/60:hover{background-color:#0009}@supports (color:color-mix(in lab,red,red)){.hover\:bg-black\/60:hover{background-color:color-mix(in oklab,var(--color-black)60%,transparent)}}.hover\:bg-destructive\/20:hover{background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-destructive\/20:hover{background-color:color-mix(in oklab,var(--destructive)20%,transparent)}}.hover\:bg-input\/50:hover{background-color:var(--input)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-input\/50:hover{background-color:color-mix(in oklab,var(--input)50%,transparent)}}.hover\:bg-muted:hover{background-color:var(--muted)}.hover\:bg-primary\/80:hover{background-color:var(--primary)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-primary\/80:hover{background-color:color-mix(in oklab,var(--primary)80%,transparent)}}.hover\:bg-secondary\/80:hover{background-color:var(--secondary)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-secondary\/80:hover{background-color:color-mix(in oklab,var(--secondary)80%,transparent)}}.hover\:text-foreground:hover{color:var(--foreground)}.hover\:text-gray-300:hover{color:var(--color-gray-300)}.hover\:text-muted-foreground:hover{color:var(--muted-foreground)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-80:hover{opacity:.8}.hover\:opacity-90:hover{opacity:.9}.hover\:opacity-100:hover{opacity:1}}.focus\:bg-accent:focus{background-color:var(--accent)}.focus\:text-accent-foreground:focus{color:var(--accent-foreground)}.focus\:ring-1:focus{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + 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\:ring-primary:focus{--tw-ring-color:var(--primary)}.focus\:ring-ring:focus{--tw-ring-color:var(--ring)}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,)0 0 0 var(--tw-ring-offset-width)var(--tw-ring-offset-color)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}:is(.not-data-\[variant\=destructive\]\:focus\:\*\*\:text-accent-foreground:not([data-variant=destructive]):focus *){color:var(--accent-foreground)}.focus-visible\:border-destructive\/40:focus-visible{border-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.focus-visible\:border-destructive\/40:focus-visible{border-color:color-mix(in oklab,var(--destructive)40%,transparent)}}.focus-visible\:border-ring:focus-visible{border-color:var(--ring)}.focus-visible\:ring-0:focus-visible{--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-visible\:ring-\[3px\]:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(3px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:color-mix(in oklab,var(--destructive)20%,transparent)}}.focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab,red,red)){.focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:color-mix(in oklab,var(--ring)50%,transparent)}}.focus-visible\:ring-offset-0:focus-visible{--tw-ring-offset-width:0px;--tw-ring-offset-shadow:var(--tw-ring-inset,)0 0 0 var(--tw-ring-offset-width)var(--tw-ring-offset-color)}.active\:scale-90:active{--tw-scale-x:90%;--tw-scale-y:90%;--tw-scale-z:90%;scale:var(--tw-scale-x)var(--tw-scale-y)}.active\:scale-95:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x)var(--tw-scale-y)}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}@media(hover:hover){.disabled\:hover\:scale-100:disabled:hover{--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x)var(--tw-scale-y)}}.has-data-\[icon\=inline-end\]\:pr-1\.5:has([data-icon=inline-end]){padding-right:calc(var(--spacing)*1.5)}.has-data-\[icon\=inline-end\]\:pr-2:has([data-icon=inline-end]){padding-right:calc(var(--spacing)*2)}.has-data-\[icon\=inline-end\]\:pr-2\.5:has([data-icon=inline-end]){padding-right:calc(var(--spacing)*2.5)}.has-data-\[icon\=inline-end\]\:pr-3:has([data-icon=inline-end]){padding-right:calc(var(--spacing)*3)}.has-data-\[icon\=inline-start\]\:pl-1\.5:has([data-icon=inline-start]){padding-left:calc(var(--spacing)*1.5)}.has-data-\[icon\=inline-start\]\:pl-2:has([data-icon=inline-start]){padding-left:calc(var(--spacing)*2)}.has-data-\[icon\=inline-start\]\:pl-2\.5:has([data-icon=inline-start]){padding-left:calc(var(--spacing)*2.5)}.has-data-\[icon\=inline-start\]\:pl-3:has([data-icon=inline-start]){padding-left:calc(var(--spacing)*3)}.has-data-\[slot\=card-action\]\:grid-cols-\[1fr_auto\]:has([data-slot=card-action]){grid-template-columns:1fr auto}.has-data-\[slot\=card-description\]\:grid-rows-\[auto_auto\]:has([data-slot=card-description]){grid-template-rows:auto auto}.has-\[\>\[data-slot\=field-content\]\]\:items-start:has(>[data-slot=field-content]){align-items:flex-start}.has-\[\>img\:first-child\]\:pt-0:has(>img:first-child){padding-top:calc(var(--spacing)*0)}.aria-expanded\:bg-muted[aria-expanded=true]{background-color:var(--muted)}.aria-expanded\:bg-secondary[aria-expanded=true]{background-color:var(--secondary)}.aria-expanded\:text-foreground[aria-expanded=true]{color:var(--foreground)}.aria-expanded\:text-secondary-foreground[aria-expanded=true]{color:var(--secondary-foreground)}.aria-invalid\:border-destructive[aria-invalid=true]{border-color:var(--destructive)}.aria-invalid\:ring-\[3px\][aria-invalid=true]{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(3px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.aria-invalid\:ring-destructive\/20[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.aria-invalid\:ring-destructive\/20[aria-invalid=true]{--tw-ring-color:color-mix(in oklab,var(--destructive)20%,transparent)}}.data-closed\:overflow-hidden[data-closed]{overflow:hidden}.data-disabled\:pointer-events-none[data-disabled]{pointer-events:none}.data-disabled\:opacity-50[data-disabled]{opacity:.5}.data-\[disabled\]\:pointer-events-none[data-disabled]{pointer-events:none}.data-\[disabled\]\:opacity-50[data-disabled]{opacity:.5}.data-\[inset\]\:pl-8[data-inset]{padding-left:calc(var(--spacing)*8)}.data-\[invalid\=true\]\:text-destructive[data-invalid=true]{color:var(--destructive)}.data-\[orientation\=horizontal\]\:h-px[data-orientation=horizontal]{height:1px}.data-\[orientation\=horizontal\]\:w-full[data-orientation=horizontal]{width:100%}.data-\[orientation\=vertical\]\:w-px[data-orientation=vertical]{width:1px}.data-\[orientation\=vertical\]\:self-stretch[data-orientation=vertical]{align-self:stretch}.data-\[placeholder\]\:text-muted-foreground[data-placeholder]{color:var(--muted-foreground)}.data-\[size\=default\]\:h-9[data-size=default]{height:calc(var(--spacing)*9)}.data-\[size\=sm\]\:h-8[data-size=sm]{height:calc(var(--spacing)*8)}.data-\[size\=sm\]\:gap-4[data-size=sm]{gap:calc(var(--spacing)*4)}.data-\[size\=sm\]\:py-4[data-size=sm]{padding-block:calc(var(--spacing)*4)}:is(.\*\:data-\[slot\=select-value\]\:line-clamp-1>*)[data-slot=select-value]{-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}:is(.\*\:data-\[slot\=select-value\]\:flex>*)[data-slot=select-value]{display:flex}:is(.\*\:data-\[slot\=select-value\]\:items-center>*)[data-slot=select-value]{align-items:center}:is(.\*\:data-\[slot\=select-value\]\:gap-1\.5>*)[data-slot=select-value]{gap:calc(var(--spacing)*1.5)}.data-\[state\=open\]\:bg-accent[data-state=open]{background-color:var(--accent)}.data-\[state\=open\]\:text-muted-foreground[data-state=open]{color:var(--muted-foreground)}.data-\[variant\=destructive\]\:text-destructive[data-variant=destructive]{color:var(--destructive)}.data-\[variant\=destructive\]\:focus\:bg-destructive\/10[data-variant=destructive]:focus{background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.data-\[variant\=destructive\]\:focus\:bg-destructive\/10[data-variant=destructive]:focus{background-color:color-mix(in oklab,var(--destructive)10%,transparent)}}.data-\[variant\=destructive\]\:focus\:text-destructive[data-variant=destructive]:focus{color:var(--destructive)}@supports ((-webkit-backdrop-filter:var(--tw)) or (backdrop-filter:var(--tw))){.supports-backdrop-filter\: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,)}}@media(min-width:40rem){.sm\:rounded-lg{border-radius:var(--radius)}}@media(min-width:48rem){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.md\:text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}}@container field-group (min-width:28rem){.\@md\/field-group\:flex-row{flex-direction:row}.\@md\/field-group\:items-center{align-items:center}.\@md\/field-group\:has-\[\>\[data-slot\=field-content\]\]\:items-start:has(>[data-slot=field-content]){align-items:flex-start}}.dark\:bg-destructive\/20:is(.dark *){background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.dark\:bg-destructive\/20:is(.dark *){background-color:color-mix(in oklab,var(--destructive)20%,transparent)}}@media(hover:hover){.dark\:hover\:bg-destructive\/30:is(.dark *):hover{background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.dark\:hover\:bg-destructive\/30:is(.dark *):hover{background-color:color-mix(in oklab,var(--destructive)30%,transparent)}}.dark\:hover\:bg-input\/50:is(.dark *):hover{background-color:var(--input)}@supports (color:color-mix(in lab,red,red)){.dark\:hover\:bg-input\/50:is(.dark *):hover{background-color:color-mix(in oklab,var(--input)50%,transparent)}}.dark\:hover\:bg-muted\/50:is(.dark *):hover{background-color:var(--muted)}@supports (color:color-mix(in lab,red,red)){.dark\:hover\:bg-muted\/50:is(.dark *):hover{background-color:color-mix(in oklab,var(--muted)50%,transparent)}}}.dark\:focus-visible\:ring-destructive\/40:is(.dark *):focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.dark\:focus-visible\:ring-destructive\/40:is(.dark *):focus-visible{--tw-ring-color:color-mix(in oklab,var(--destructive)40%,transparent)}}.dark\:aria-invalid\:border-destructive\/50:is(.dark *)[aria-invalid=true]{border-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.dark\:aria-invalid\:border-destructive\/50:is(.dark *)[aria-invalid=true]{border-color:color-mix(in oklab,var(--destructive)50%,transparent)}}.dark\:aria-invalid\:ring-destructive\/40:is(.dark *)[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.dark\:aria-invalid\:ring-destructive\/40:is(.dark *)[aria-invalid=true]{--tw-ring-color:color-mix(in oklab,var(--destructive)40%,transparent)}}.dark\:data-\[variant\=destructive\]\:focus\:bg-destructive\/20:is(.dark *)[data-variant=destructive]:focus{background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.dark\:data-\[variant\=destructive\]\:focus\:bg-destructive\/20:is(.dark *)[data-variant=destructive]:focus{background-color:color-mix(in oklab,var(--destructive)20%,transparent)}}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}.\[\&_svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-3 svg:not([class*=size-]){width:calc(var(--spacing)*3);height:calc(var(--spacing)*3)}.\[\&_svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-4 svg:not([class*=size-]){width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}.\[\.border-b\]\:pb-6.border-b{padding-bottom:calc(var(--spacing)*6)}.group-data-\[size\=sm\]\/card\:\[\.border-b\]\:pb-4:is(:where(.group\/card)[data-size=sm] *).border-b{padding-bottom:calc(var(--spacing)*4)}@media(hover:hover){.\[a\]\:hover\:bg-destructive\/20:is(a):hover{background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.\[a\]\:hover\:bg-destructive\/20:is(a):hover{background-color:color-mix(in oklab,var(--destructive)20%,transparent)}}.\[a\]\:hover\:bg-muted:is(a):hover{background-color:var(--muted)}.\[a\]\:hover\:bg-primary\/80:is(a):hover{background-color:var(--primary)}@supports (color:color-mix(in lab,red,red)){.\[a\]\:hover\:bg-primary\/80:is(a):hover{background-color:color-mix(in oklab,var(--primary)80%,transparent)}}.\[a\]\:hover\:bg-secondary\/80:is(a):hover{background-color:var(--secondary)}@supports (color:color-mix(in lab,red,red)){.\[a\]\:hover\:bg-secondary\/80:is(a):hover{background-color:color-mix(in oklab,var(--secondary)80%,transparent)}}.\[a\]\:hover\:text-muted-foreground:is(a):hover{color:var(--muted-foreground)}}:is(.\*\:\[img\:first-child\]\:rounded-t-xl>*):is(img:first-child){border-top-left-radius:calc(var(--radius) + 4px);border-top-right-radius:calc(var(--radius) + 4px)}:is(.\*\:\[img\:last-child\]\:rounded-b-xl>*):is(img:last-child){border-bottom-right-radius:calc(var(--radius) + 4px);border-bottom-left-radius:calc(var(--radius) + 4px)}:is(.\*\:\[span\]\:last\:flex>*):is(span):last-child{display:flex}:is(.\*\:\[span\]\:last\:items-center>*):is(span):last-child{align-items:center}:is(.\*\:\[span\]\:last\:gap-2>*):is(span):last-child{gap:calc(var(--spacing)*2)}:is(.data-\[variant\=destructive\]\:\*\:\[svg\]\:text-destructive[data-variant=destructive]>*):is(svg){color:var(--destructive)}.\[\&\>\*\]\:w-full>*{width:100%}@container field-group (min-width:28rem){.\@md\/field-group\:\[\&\>\*\]\:w-auto>*{width:auto}}.\[\&\>\.sr-only\]\:w-auto>.sr-only{width:auto}.\[\&\>\[data-slot\=field-label\]\]\:flex-auto>[data-slot=field-label]{flex:auto}@container field-group (min-width:28rem){.\@md\/field-group\:\[\&\>\[data-slot\=field-label\]\]\:flex-auto>[data-slot=field-label]{flex:auto}}.has-\[\>\[data-slot\=field-content\]\]\:\[\&\>\[role\=checkbox\]\,\[role\=radio\]\]\:mt-px:has(>[data-slot=field-content])>[role=checkbox],.has-\[\>\[data-slot\=field-content\]\]\:\[\&\>\[role\=checkbox\]\,\[role\=radio\]\]\:mt-px:has(>[data-slot=field-content]) [role=radio]{margin-top:1px}@container field-group (min-width:28rem){.\@md\/field-group\:has-\[\>\[data-slot\=field-content\]\]\:\[\&\>\[role\=checkbox\]\,\[role\=radio\]\]\:mt-px:has(>[data-slot=field-content])>[role=checkbox],.\@md\/field-group\:has-\[\>\[data-slot\=field-content\]\]\:\[\&\>\[role\=checkbox\]\,\[role\=radio\]\]\:mt-px:has(>[data-slot=field-content]) [role=radio]{margin-top:1px}}.\[\&\>svg\]\:pointer-events-none>svg{pointer-events:none}.\[\&\>svg\]\:size-3\!>svg{width:calc(var(--spacing)*3)!important;height:calc(var(--spacing)*3)!important}}:root{--background:oklch(100% 0 0);--foreground:oklch(14.1% .005 285.823);--card:oklch(100% 0 0);--card-foreground:oklch(14.1% .005 285.823);--popover:oklch(100% 0 0);--popover-foreground:oklch(14.1% .005 285.823);--primary:oklch(21% .006 285.885);--primary-foreground:oklch(98.5% 0 0);--secondary:oklch(96.7% .001 286.375);--secondary-foreground:oklch(21% .006 285.885);--muted:oklch(96.7% .001 286.375);--muted-foreground:oklch(55.2% .016 285.938);--accent:oklch(96.7% .001 286.375);--accent-foreground:oklch(21% .006 285.885);--destructive:oklch(57.7% .245 27.325);--border:oklch(92% .004 286.32);--input:oklch(92% .004 286.32);--ring:oklch(70.5% .015 286.067);--chart-1:oklch(64.6% .222 41.116);--chart-2:oklch(60% .118 184.704);--chart-3:oklch(39.8% .07 227.392);--chart-4:oklch(82.8% .189 84.429);--chart-5:oklch(76.9% .188 70.08);--radius:.625rem;--sidebar:oklch(98.5% 0 0);--sidebar-foreground:oklch(14.1% .005 285.823);--sidebar-primary:oklch(21% .006 285.885);--sidebar-primary-foreground:oklch(98.5% 0 0);--sidebar-accent:oklch(96.7% .001 286.375);--sidebar-accent-foreground:oklch(21% .006 285.885);--sidebar-border:oklch(92% .004 286.32);--sidebar-ring:oklch(70.5% .015 286.067)}.dark{--background:oklch(14.1% .005 285.823);--foreground:oklch(98.5% 0 0);--card:oklch(21% .006 285.885);--card-foreground:oklch(98.5% 0 0);--popover:oklch(21% .006 285.885);--popover-foreground:oklch(98.5% 0 0);--primary:oklch(92% .004 286.32);--primary-foreground:oklch(21% .006 285.885);--secondary:oklch(27.4% .006 286.033);--secondary-foreground:oklch(98.5% 0 0);--muted:oklch(27.4% .006 286.033);--muted-foreground:oklch(70.5% .015 286.067);--accent:oklch(27.4% .006 286.033);--accent-foreground:oklch(98.5% 0 0);--destructive:oklch(70.4% .191 22.216);--border:oklch(100% 0 0/.1);--input:oklch(100% 0 0/.15);--ring:oklch(55.2% .016 285.938);--chart-1:oklch(48.8% .243 264.376);--chart-2:oklch(69.6% .17 162.48);--chart-3:oklch(76.9% .188 70.08);--chart-4:oklch(62.7% .265 303.9);--chart-5:oklch(64.5% .246 16.439);--sidebar:oklch(21% .006 285.885);--sidebar-foreground:oklch(98.5% 0 0);--sidebar-primary:oklch(48.8% .243 264.376);--sidebar-primary-foreground:oklch(98.5% 0 0);--sidebar-accent:oklch(27.4% .006 286.033);--sidebar-accent-foreground:oklch(98.5% 0 0);--sidebar-border:oklch(100% 0 0/.1);--sidebar-ring:oklch(55.2% .016 285.938)}@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-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-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-duration{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@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}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}
|