@elizaos/plugin-knowledge 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,409 +1,183 @@
1
1
  # Knowledge Plugin for ElizaOS
2
2
 
3
- This plugin provides Retrieval Augmented Generation (Knowledge) capabilities for ElizaOS agents, allowing them to load, index, and query knowledge from various sources.
3
+ This plugin gives your agent the ability to learn from documents and answer questions based on that knowledge.
4
4
 
5
- ## Quick Setup
5
+ ## 🚀 Quick Start (No Configuration Needed!)
6
6
 
7
- > **⚠️ Note**: `TEXT_PROVIDER` and `TEXT_MODEL` configuration are temporarily disabled. The plugin currently uses `runtime.useModel(TEXT_LARGE)` for text generation. Full provider configuration support will be added soon.
7
+ If you already have **plugin-openai** configured in your agent, this plugin works automatically! Just add it to your agent and you're done.
8
8
 
9
- ### Basic Setup (With plugin-openai)
9
+ ```typescript
10
+ import { knowledgePlugin } from '@elizaos/plugin-knowledge';
10
11
 
11
- If you already have plugin-openai configured, you don't need any additional environment variables! The Knowledge plugin will automatically use your OpenAI configuration.
12
+ // Add to your agent's plugins
13
+ plugins: [
14
+ '@elizaos/plugin-knowledge',
15
+ // ... other plugins
16
+ ];
17
+ ```
12
18
 
13
- 1. Make sure you have plugin-openai configured with:
19
+ That's it! Your agent can now process and learn from documents.
14
20
 
15
- ```env
16
- OPENAI_API_KEY=your-openai-api-key
17
- OPENAI_EMBEDDING_MODEL=text-embedding-3-small
18
- ```
21
+ ## 📁 Auto-Load Documents on Startup
19
22
 
20
- 2. Add the Knowledge plugin to your agent's configuration
21
- 3. That's it! The plugin will work without any additional variables
23
+ Want your agent to automatically learn from documents when it starts? Just:
22
24
 
23
- ### Enabling Contextual Knowledge
25
+ 1. **Add this to your `.env` file:**
24
26
 
25
- If you want enhanced Knowledge capabilities with contextual embeddings, add:
27
+ ```env
28
+ LOAD_DOCS_ON_STARTUP=true
29
+ ```
26
30
 
27
- > **Note**: The TEXT_PROVIDER and TEXT_MODEL settings below are temporarily disabled. The plugin will use `runtime.useModel(TEXT_LARGE)` for now.
31
+ 2. **Create a `docs` folder in your project root and add your documents:**
28
32
 
29
- ```env
30
- # Enable contextual Knowledge
31
- CTX_KNOWLEDGE_ENABLED=true
33
+ ```
34
+ your-project/
35
+ ├── .env
36
+ ├── docs/ <-- Create this folder
37
+ │ ├── guide.pdf
38
+ │ ├── manual.txt
39
+ │ └── notes.md
40
+ └── ... other files
41
+ ```
32
42
 
33
- # Required text generation settings (TEMPORARILY DISABLED)
34
- TEXT_PROVIDER=openrouter # Choose your provider: openai, anthropic, openrouter, or google
35
- TEXT_MODEL=anthropic/claude-3.5-sonnet # Model for your chosen provider
43
+ 3. **Start your agent** - it will automatically load all documents from the `docs` folder!
36
44
 
37
- # Provider-specific API key (based on TEXT_PROVIDER)
38
- OPENROUTER_API_KEY=your-openrouter-api-key
39
- # OR ANTHROPIC_API_KEY=your-anthropic-api-key
40
- # OR GOOGLE_API_KEY=your-google-api-key
41
- # OR use existing OPENAI_API_KEY
42
- ```
45
+ ### Supported File Types
43
46
 
44
- ### Custom Embedding Configuration (Without plugin-openai)
47
+ - 📄 **Documents:** PDF, TXT, MD, DOC, DOCX
48
+ - 💻 **Code:** JS, TS, PY, and many more
49
+ - 📊 **Data:** JSON, CSV, XML, YAML
45
50
 
46
- If you're not using plugin-openai or want to use different embedding settings:
51
+ ## 💬 How to Use
47
52
 
48
- ```env
49
- # Required embedding settings
50
- EMBEDDING_PROVIDER=openai # or google
51
- TEXT_EMBEDDING_MODEL=text-embedding-3-small
53
+ Once documents are loaded, just ask your agent questions naturally:
52
54
 
53
- # Provider-specific API key
54
- OPENAI_API_KEY=your-openai-api-key # if using openai
55
- # OR GOOGLE_API_KEY=your-google-api-key # if using google
55
+ - "What does the guide say about setup?"
56
+ - "Search your knowledge for information about configuration"
57
+ - "What do you know about [topic]?"
56
58
 
57
- # Optional: Custom embedding dimension
58
- EMBEDDING_DIMENSION=1536
59
- ```
59
+ Your agent will search through all loaded documents and provide relevant answers!
60
60
 
61
- ## Advanced Configuration
61
+ ## 🎯 Actions Available
62
62
 
63
- ### Recommended Configurations for Contextual Knowledge
63
+ The plugin provides these actions that your agent can use:
64
64
 
65
- For optimal performance with contextual Knowledge, we recommend these provider combinations:
65
+ 1. **PROCESS_KNOWLEDGE** - Add new documents or text to the knowledge base
66
66
 
67
- **Option 1: OpenRouter with Claude/Gemini (Best for cost efficiency)**
67
+ - "Process the document at /path/to/file.pdf"
68
+ - "Remember this: The sky is blue"
68
69
 
69
- ```env
70
- # If using with plugin-openai, only need these additions:
71
- CTX_KNOWLEDGE_ENABLED=true
72
- TEXT_PROVIDER=openrouter
73
- TEXT_MODEL=anthropic/claude-3.5-sonnet # or google/gemini-2.5-flash-preview
74
- OPENROUTER_API_KEY=your-openrouter-api-key
75
- ```
70
+ 2. **SEARCH_KNOWLEDGE** - Search the knowledge base
71
+ - "Search your knowledge for quantum computing"
76
72
 
77
- **Option 2: OpenAI for Everything**
73
+ ## 🌐 Web Interface
78
74
 
79
- ```env
80
- # If using with plugin-openai, only need these additions:
81
- CTX_KNOWLEDGE_ENABLED=true
82
- TEXT_PROVIDER=openai
83
- TEXT_MODEL=gpt-4o
84
- ```
85
-
86
- **Option 3: Google AI for Everything**
75
+ The plugin includes a web interface for managing documents! Access it at:
87
76
 
88
- ```env
89
- EMBEDDING_PROVIDER=google
90
- TEXT_EMBEDDING_MODEL=text-embedding-004
91
- TEXT_PROVIDER=google
92
- TEXT_MODEL=gemini-1.5-pro-latest
93
- GOOGLE_API_KEY=your-google-api-key
94
- CTX_KNOWLEDGE_ENABLED=true
77
+ ```
78
+ http://localhost:3000/api/agents/[your-agent-id]/plugins/knowledge/display
95
79
  ```
96
80
 
97
- ### Advanced Rate Limiting Options
81
+ ---
98
82
 
99
- ```env
100
- # Rate limiting (optional)
101
- MAX_CONCURRENT_REQUESTS=30 # Default: 30
102
- REQUESTS_PER_MINUTE=60 # Default: 60
103
- TOKENS_PER_MINUTE=150000 # Default: 150000
104
- ```
83
+ ## ⚠️ Advanced Configuration (Developers Only)
105
84
 
106
- ### Custom API Endpoints
85
+ **Note: If you're not a developer, don't use the settings below! The plugin works great with just the quick start setup above.**
107
86
 
108
- ```env
109
- # Only needed if using custom API endpoints
110
- OPENAI_BASE_URL=https://your-openai-proxy.com/v1
111
- ANTHROPIC_BASE_URL=https://your-anthropic-proxy.com
112
- OPENROUTER_BASE_URL=https://your-openrouter-proxy.com/api/v1
113
- GOOGLE_BASE_URL=https://your-google-proxy.com
114
- ```
87
+ <details>
88
+ <summary>Click to show advanced configuration options</summary>
115
89
 
116
- ### Knowledge Document Path
90
+ ### Custom Document Path
117
91
 
118
- By default, the plugin looks for knowledge documents in a `docs` folder in your project root. You can customize this location using the `KNOWLEDGE_PATH` environment variable:
92
+ Change where documents are loaded from:
119
93
 
120
94
  ```env
121
- # Custom path to your knowledge documents
122
95
  KNOWLEDGE_PATH=/path/to/your/documents
123
-
124
- # Examples:
125
- # KNOWLEDGE_PATH=./my-docs # Relative path from project root
126
- # KNOWLEDGE_PATH=/home/user/docs # Absolute path
127
- # KNOWLEDGE_PATH=../shared/knowledge # Relative path to parent directory
128
96
  ```
129
97
 
130
- **How it works:**
131
- - If `KNOWLEDGE_PATH` is set, the plugin will use that directory for loading knowledge documents
132
- - If `KNOWLEDGE_PATH` is not set, the plugin defaults to `./docs` (a `docs` folder in your project root)
133
- - Both relative and absolute paths are supported
134
- - If the specified path doesn't exist, the plugin will log a warning but continue to function
135
-
136
- **Supported document formats:**
137
- - PDF files (`.pdf`)
138
- - Text files (`.txt`, `.md`)
139
- - And other formats supported by the document processor
98
+ ### Enhanced Contextual Knowledge
140
99
 
141
- ### Token Limits
100
+ For better understanding of complex documents:
142
101
 
143
102
  ```env
144
- # Advanced token handling (optional)
145
- MAX_INPUT_TOKENS=4000 # Default: 4000
146
- MAX_OUTPUT_TOKENS=4096 # Default: 4096
147
- ```
148
-
149
- ## Architecture
150
-
151
- The plugin is built with a modular, clean architecture that follows SOLID principles:
152
-
153
- ```
154
- packages/plugin-knowledge/
155
- ├── src/
156
- │ ├── index.ts # Main entry point and plugin definition
157
- │ ├── service.ts # Knowledge service implementation
158
- │ ├── types.ts # Type definitions
159
- │ ├── llm.ts # LLM interactions (text generation, embeddings)
160
- │ ├── config.ts # Configuration validation
161
- │ ├── ctx-embeddings.ts # Contextual embedding generation
162
- │ ├── document-processor.ts # Shared document processing utilities
163
- │ └── utils.ts # Utility functions
164
- ├── README.md # This file
165
- └── package.json # Package definition
166
- ```
167
-
168
- ### Database-Specific Processing Paths
169
-
170
- The Knowledge plugin adapts to the database technology being used:
171
-
172
- 1. **PostgreSQL Mode**: Uses worker threads to offload document processing from the main thread
173
- 2. **PGLite Mode**: Uses synchronous processing in the main thread due to PGLite's single-threaded nature
174
-
175
- This allows the plugin to work optimally with both databases while maintaining the same functionality.
176
-
177
- ### Processing Flow
178
-
179
- The document processing flow follows these steps regardless of database type:
180
-
181
- 1. Extract text from the document based on content type
182
- 2. Store the main document in the database
183
- 3. Split the document into chunks
184
- 4. Generate embeddings for each chunk (with optional context enrichment)
185
- 5. Store the chunks with embeddings in the database
186
-
187
- ## Component Overview
188
-
189
- - **KnowledgeService**: Core service that manages document processing and storage
190
- - **Document Processor**: Provides shared document processing utilities for both processing paths
191
-
192
- ## Features
193
-
194
- - Document upload and processing (PDF, text, and other formats)
195
- - Contextual chunking and embedding generation
196
- - Robust error handling and recovery
197
- - Rate limiting to respect provider limitations
198
- - Support for multiple LLM providers
199
-
200
- ## API Routes
201
-
202
- The Knowledge plugin provides a comprehensive REST API for managing knowledge documents. All routes are prefixed with `/api/agents/{agentId}/plugins/knowledge`.
203
-
204
- ### Knowledge Panel UI
205
-
206
- #### GET `/display`
207
- Access the web-based knowledge management interface.
208
-
209
- - **URL**: `/api/agents/{agentId}/plugins/knowledge/display`
210
- - **Method**: GET
211
- - **Public**: Yes
212
- - **Description**: Serves the HTML frontend for managing knowledge documents
213
- - **Response**: HTML page with embedded configuration
214
-
215
- ### Document Management
216
-
217
- #### POST `/documents` - Upload Knowledge
218
- Upload files or URLs to create knowledge documents.
219
-
220
- **File Upload:**
221
- ```bash
222
- curl -X POST \
223
- "/api/agents/{agentId}/plugins/knowledge/documents" \
224
- -H "Content-Type: multipart/form-data" \
225
- -F "files=@document.pdf" \
226
- -F "documentId=optional-custom-id" \
227
- -F "worldId=optional-world-id"
228
- ```
229
-
230
- **URL Upload:**
231
- ```bash
232
- curl -X POST \
233
- "/api/agents/{agentId}/plugins/knowledge/documents" \
234
- -H "Content-Type: application/json" \
235
- -d '{
236
- "fileUrls": ["https://example.com/document.pdf"],
237
- "worldId": "optional-world-id"
238
- }'
239
- ```
240
-
241
- **Request Parameters:**
242
- - `files`: File(s) to upload (multipart)
243
- - `fileUrl` or `fileUrls`: URL(s) to fetch content from (JSON)
244
- - `documentId` or `documentIds`: Optional custom document IDs
245
- - `worldId`: Optional world ID for scoping
246
-
247
- **Response:**
248
- ```json
249
- {
250
- "success": true,
251
- "data": [
252
- {
253
- "id": "document-uuid",
254
- "filename": "document.pdf",
255
- "status": "success",
256
- "fragmentCount": 15,
257
- "createdAt": 1703123456789
258
- }
259
- ]
260
- }
103
+ CTX_KNOWLEDGE_ENABLED=true
104
+ TEXT_PROVIDER=openrouter
105
+ TEXT_MODEL=anthropic/claude-3.5-sonnet
106
+ OPENROUTER_API_KEY=your-api-key
261
107
  ```
262
108
 
263
- **Supported File Types:**
264
- - **Documents**: PDF, DOC, DOCX
265
- - **Text**: TXT, MD, HTML, JSON, XML, YAML
266
- - **Code**: JS, TS, PY, JAVA, C, CPP, CS, PHP, RB, GO, RS, and more
267
- - **Config**: INI, CFG, CONF, ENV
268
- - **Data**: CSV, TSV, LOG
269
-
270
- #### GET `/documents` - List Documents
271
- Retrieve all knowledge documents.
109
+ ### Custom Embedding Configuration
272
110
 
273
- ```bash
274
- curl "/api/agents/{agentId}/plugins/knowledge/documents?limit=20&before=1703123456789&includeEmbedding=false"
275
- ```
111
+ If not using plugin-openai:
276
112
 
277
- **Query Parameters:**
278
- - `limit`: Number of documents to return (default: 20)
279
- - `before`: Timestamp for pagination (default: current time)
280
- - `includeEmbedding`: Include embedding data (default: false)
281
- - `fileUrls`: Filter by specific URLs (comma-separated)
282
-
283
- **Response:**
284
- ```json
285
- {
286
- "success": true,
287
- "data": {
288
- "memories": [
289
- {
290
- "id": "document-uuid",
291
- "content": { "text": "..." },
292
- "metadata": {
293
- "type": "document",
294
- "title": "Document Title",
295
- "filename": "document.pdf",
296
- "fileType": "application/pdf",
297
- "fileSize": 1024,
298
- "timestamp": 1703123456789,
299
- "source": "upload"
300
- },
301
- "createdAt": 1703123456789
302
- }
303
- ],
304
- "urlFiltered": false,
305
- "totalFound": 1,
306
- "totalRequested": 0
307
- }
308
- }
113
+ ```env
114
+ EMBEDDING_PROVIDER=openai
115
+ TEXT_EMBEDDING_MODEL=text-embedding-3-small
116
+ OPENAI_API_KEY=your-api-key
309
117
  ```
310
118
 
311
- #### GET `/documents/:knowledgeId` - Get Specific Document
312
- Retrieve a specific knowledge document by ID.
313
-
314
- ```bash
315
- curl "/api/agents/{agentId}/plugins/knowledge/documents/{documentId}"
316
- ```
119
+ ### All Configuration Options
317
120
 
318
- **Response:**
319
- ```json
320
- {
321
- "success": true,
322
- "data": {
323
- "document": {
324
- "id": "document-uuid",
325
- "content": { "text": "..." },
326
- "metadata": { "..." },
327
- "createdAt": 1703123456789
328
- }
329
- }
330
- }
331
- ```
121
+ ```env
122
+ # Document Loading
123
+ LOAD_DOCS_ON_STARTUP=true # Auto-load from docs folder
124
+ KNOWLEDGE_PATH=/custom/path # Custom document path
332
125
 
333
- #### DELETE `/documents/:knowledgeId` - Delete Document
334
- Delete a knowledge document and all its fragments.
126
+ # Contextual Enhancement (improves understanding)
127
+ CTX_KNOWLEDGE_ENABLED=true # Enable contextual embeddings
335
128
 
336
- ```bash
337
- curl -X DELETE "/api/agents/{agentId}/plugins/knowledge/documents/{documentId}"
338
- ```
129
+ # Embedding Provider (if not using plugin-openai)
130
+ EMBEDDING_PROVIDER=openai # or google
131
+ TEXT_EMBEDDING_MODEL=text-embedding-3-small
132
+ EMBEDDING_DIMENSION=1536
339
133
 
340
- **Response:**
341
- ```json
342
- {
343
- "success": true,
344
- "data": null
345
- }
346
- ```
134
+ # Text Generation Provider (for contextual mode)
135
+ TEXT_PROVIDER=openai # or anthropic, openrouter, google
136
+ TEXT_MODEL=gpt-4o # Model name for your provider
347
137
 
348
- ### Knowledge Fragments
138
+ # API Keys (based on providers used)
139
+ OPENAI_API_KEY=your-key
140
+ ANTHROPIC_API_KEY=your-key
141
+ OPENROUTER_API_KEY=your-key
142
+ GOOGLE_API_KEY=your-key
349
143
 
350
- #### GET `/knowledges` - List Knowledge Chunks
351
- Retrieve knowledge fragments/chunks for detailed analysis or graph view.
144
+ # Rate Limiting
145
+ MAX_CONCURRENT_REQUESTS=30
146
+ REQUESTS_PER_MINUTE=60
147
+ TOKENS_PER_MINUTE=150000
352
148
 
353
- ```bash
354
- curl "/api/agents/{agentId}/plugins/knowledge/knowledges?limit=100&documentId=optional-filter"
149
+ # Token Limits
150
+ MAX_INPUT_TOKENS=4000
151
+ MAX_OUTPUT_TOKENS=4096
355
152
  ```
356
153
 
357
- **Query Parameters:**
358
- - `limit`: Number of chunks to return (default: 100)
359
- - `before`: Timestamp for pagination (default: current time)
360
- - `documentId`: Filter chunks by parent document ID
361
-
362
- **Response:**
363
- ```json
364
- {
365
- "success": true,
366
- "data": {
367
- "chunks": [
368
- {
369
- "id": "fragment-uuid",
370
- "content": { "text": "chunk content..." },
371
- "metadata": {
372
- "type": "fragment",
373
- "documentId": "parent-document-uuid",
374
- "position": 0,
375
- "timestamp": 1703123456789
376
- },
377
- "embedding": [0.1, 0.2, ...], // If included
378
- "createdAt": 1703123456789
379
- }
380
- ]
381
- }
382
- }
383
- ```
154
+ ### API Routes Reference
384
155
 
385
- ## Usage
156
+ - `POST /api/agents/{agentId}/plugins/knowledge/documents` - Upload documents
157
+ - `GET /api/agents/{agentId}/plugins/knowledge/documents` - List documents
158
+ - `GET /api/agents/{agentId}/plugins/knowledge/documents/{id}` - Get specific document
159
+ - `DELETE /api/agents/{agentId}/plugins/knowledge/documents/{id}` - Delete document
160
+ - `GET /api/agents/{agentId}/plugins/knowledge/display` - Web interface
386
161
 
387
162
  ### Programmatic Usage
388
163
 
389
164
  ```typescript
390
165
  import { KnowledgeService } from '@elizaos/plugin-knowledge';
391
166
 
392
- // Add knowledge to an agent
167
+ // Add knowledge programmatically
393
168
  const result = await knowledgeService.addKnowledge({
394
169
  clientDocumentId: 'unique-id',
395
- content: documentContent, // Base64 string for binary files or plain text for text files
170
+ content: documentContent,
396
171
  contentType: 'application/pdf',
397
172
  originalFilename: 'document.pdf',
398
173
  worldId: 'world-id',
399
- roomId: 'optional-room-id', // Optional scoping
400
- entityId: 'optional-entity-id', // Optional scoping
174
+ roomId: 'room-id',
175
+ entityId: 'entity-id',
401
176
  });
402
-
403
- console.log(`Document stored with ID: ${result.storedDocumentMemoryId}`);
404
- console.log(`Created ${result.fragmentCount} searchable fragments`);
405
177
  ```
406
178
 
407
- ## License
179
+ </details>
180
+
181
+ ## 📝 License
408
182
 
409
183
  See the ElizaOS license for details.
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "index.html": {
3
- "file": "assets/index-BwFQYb4z.js",
3
+ "file": "assets/index-DlJcnv-R.js",
4
4
  "name": "index",
5
5
  "src": "index.html",
6
6
  "isEntry": true,
7
7
  "css": [
8
- "assets/index-Bjc7mMWy.css"
8
+ "assets/index-DiVvUMt0.css"
9
9
  ]
10
10
  }
11
11
  }
@@ -0,0 +1 @@
1
+ /*! tailwindcss v4.1.10 | MIT License | https://tailwindcss.com */@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-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-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-translate-x:0;--tw-translate-y:0;--tw-translate-z:0}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-orange-500:oklch(70.5% .213 47.604);--color-orange-600:oklch(64.6% .222 41.116);--color-yellow-500:oklch(79.5% .184 86.047);--color-green-500:oklch(72.3% .219 149.579);--color-blue-500:oklch(62.3% .214 259.815);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-700:oklch(37.3% .034 259.733);--spacing:.25rem;--container-md:28rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--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);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--leading-relaxed:1.625;--animate-spin:spin 1s linear 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)}}@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%;-moz-tab-size:4;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}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}:root{--background:0 0% 97.65%;--foreground:0 0% 12.55%;--muted:0 0% 93.73%;--muted-foreground:0 0% 39.22%;--popover:0 0% 98.82%;--popover-foreground:0 0% 12.55%;--card:0 0% 98.82%;--card-foreground:0 0% 12.55%;--border:0 0% 84.71%;--input:0 0% 94.12%;--primary:22.93 92.59% 52.35%;--primary-foreground:44 0% 100%;--secondary:34.05 100% 85.49%;--secondary-foreground:16.27 50.43% 22.94%;--accent:0 0% 90.98%;--accent-foreground:0 0% 12.55%;--destructive:10.16 77.87% 53.92%;--destructive-foreground:0 0% 100%;--ring:24.8 79.79% 63.14%;--chart-1:22.93 92.59% 52.35%;--chart-2:34.05 100% 85.49%;--chart-3:0 0% 90.98%;--chart-4:34.05 100% 88.49%;--chart-5:22.93 95.59% 52.35%;--radius:.5rem}.dark{--background:0 0% 6.67%;--foreground:0 0% 93.33%;--muted:0 0% 13.33%;--muted-foreground:0 0% 70.59%;--popover:0 0% 9.8%;--popover-foreground:0 0% 93.33%;--card:0 0% 9.8%;--card-foreground:0 0% 93.33%;--border:44 14% 11%;--input:0 0% 28.24%;--primary:22.93 92.59% 52.35%;--primary-foreground:29.51 0% 100%;--secondary:28.5 64.52% 12.16%;--secondary-foreground:29.51 100% 88.04%;--accent:0 0% 16.47%;--accent-foreground:0 0% 93.33%;--destructive:10.16 77.87% 53.92%;--destructive-foreground:0 0% 100%;--ring:23.11 59.8% 40%;--chart-1:22.93 92.59% 52.35%;--chart-2:28.5 64.52% 12.16%;--chart-3:0 0% 16.47%;--chart-4:28.5 64.52% 15.16%;--chart-5:22.93 95.59% 52.35%}*{border-color:hsl(var(--border))}body{background-color:hsl(var(--background));color:hsl(var(--foreground))}}@layer components;@layer utilities{.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{inset:calc(var(--spacing)*0)}.top-3{top:calc(var(--spacing)*3)}.top-4{top:calc(var(--spacing)*4)}.top-16{top:calc(var(--spacing)*16)}.right-4{right:calc(var(--spacing)*4)}.left-3{left:calc(var(--spacing)*3)}.left-4{left:calc(var(--spacing)*4)}.z-50{z-index:50}.col-span-2{grid-column:span 2/span 2}.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}}.container,.mx-auto{margin-inline:auto}.mt-1{margin-top:calc(var(--spacing)*1)}.mt-2{margin-top:calc(var(--spacing)*2)}.mt-4{margin-top:calc(var(--spacing)*4)}.mt-6{margin-top:calc(var(--spacing)*6)}.mt-8{margin-top:calc(var(--spacing)*8)}.mr-1\.5{margin-right:calc(var(--spacing)*1.5)}.mr-2{margin-right:calc(var(--spacing)*2)}.mb-1{margin-bottom:calc(var(--spacing)*1)}.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)}.ml-auto{margin-left:auto}.line-clamp-1{-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-clamp-3{-webkit-line-clamp:3;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.table{display:table}.size-6{width:calc(var(--spacing)*6);height:calc(var(--spacing)*6)}.h-1\/3{height:33.3333%}.h-2{height:calc(var(--spacing)*2)}.h-2\/3{height:66.6667%}.h-3{height:calc(var(--spacing)*3)}.h-3\.5{height:calc(var(--spacing)*3.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-9{height:calc(var(--spacing)*9)}.h-10{height:calc(var(--spacing)*10)}.h-11{height:calc(var(--spacing)*11)}.h-12{height:calc(var(--spacing)*12)}.h-40{height:calc(var(--spacing)*40)}.h-full{height:100%}.max-h-40{max-height:calc(var(--spacing)*40)}.max-h-\[95vh\]{max-height:95vh}.max-h-full{max-height:100%}.w-3{width:calc(var(--spacing)*3)}.w-3\.5{width:calc(var(--spacing)*3.5)}.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-12{width:calc(var(--spacing)*12)}.w-full{width:100%}.max-w-\[95vw\]{max-width:95vw}.max-w-full{max-width:100%}.max-w-md{max-width:var(--container-md)}.min-w-\[60px\]{min-width:60px}.min-w-full{min-width:100%}.flex-1{flex:1}.flex-shrink-0{flex-shrink:0}.caption-bottom{caption-side:bottom}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.animate-spin{animation:var(--animate-spin)}.cursor-pointer{cursor:pointer}.resize{resize:both}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.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-1{gap:calc(var(--spacing)*1)}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*1)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*1)*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)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*2)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*3)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*3)*calc(1 - var(--tw-space-y-reverse)))}: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)))}.gap-x-4{column-gap:calc(var(--spacing)*4)}.gap-y-1{row-gap:calc(var(--spacing)*1)}.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)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-border{border-color:hsl(var(--border))}.border-gray-500\/60{border-color:#6a728299}@supports (color:color-mix(in lab,red,red)){.border-gray-500\/60{border-color:color-mix(in oklab,var(--color-gray-500)60%,transparent)}}.border-input{border-color:hsl(var(--input))}.border-orange-600\/60{border-color:#f0510099}@supports (color:color-mix(in lab,red,red)){.border-orange-600\/60{border-color:color-mix(in oklab,var(--color-orange-600)60%,transparent)}}.bg-accent,.bg-accent\/20{background-color:hsl(var(--accent))}@supports (color:color-mix(in lab,red,red)){.bg-accent\/20{background-color:color-mix(in oklab,hsl(var(--accent))20%,transparent)}}.bg-background,.bg-background\/80{background-color:hsl(var(--background))}@supports (color:color-mix(in lab,red,red)){.bg-background\/80{background-color:color-mix(in oklab,hsl(var(--background))80%,transparent)}}.bg-card,.bg-card\/50{background-color:hsl(var(--card))}@supports (color:color-mix(in lab,red,red)){.bg-card\/50{background-color:color-mix(in oklab,hsl(var(--card))50%,transparent)}}.bg-card\/90{background-color:hsl(var(--card))}@supports (color:color-mix(in lab,red,red)){.bg-card\/90{background-color:color-mix(in oklab,hsl(var(--card))90%,transparent)}}.bg-destructive,.bg-destructive\/10{background-color:hsl(var(--destructive))}@supports (color:color-mix(in lab,red,red)){.bg-destructive\/10{background-color:color-mix(in oklab,hsl(var(--destructive))10%,transparent)}}.bg-gray-200{background-color:var(--color-gray-200)}.bg-gray-400\/90{background-color:#99a1afe6}@supports (color:color-mix(in lab,red,red)){.bg-gray-400\/90{background-color:color-mix(in oklab,var(--color-gray-400)90%,transparent)}}.bg-muted,.bg-muted\/30{background-color:hsl(var(--muted))}@supports (color:color-mix(in lab,red,red)){.bg-muted\/30{background-color:color-mix(in oklab,hsl(var(--muted))30%,transparent)}}.bg-muted\/50{background-color:hsl(var(--muted))}@supports (color:color-mix(in lab,red,red)){.bg-muted\/50{background-color:color-mix(in oklab,hsl(var(--muted))50%,transparent)}}.bg-orange-500\/90{background-color:#fe6e00e6}@supports (color:color-mix(in lab,red,red)){.bg-orange-500\/90{background-color:color-mix(in oklab,var(--color-orange-500)90%,transparent)}}.bg-primary{background-color:hsl(var(--primary))}.bg-secondary{background-color:hsl(var(--secondary))}.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-12{padding:calc(var(--spacing)*12)}.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)}.px-8{padding-inline:calc(var(--spacing)*8)}.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)}.pt-0{padding-top:calc(var(--spacing)*0)}.pt-4{padding-top:calc(var(--spacing)*4)}.pb-2{padding-bottom:calc(var(--spacing)*2)}.pb-4{padding-bottom:calc(var(--spacing)*4)}.pl-10{padding-left:calc(var(--spacing)*10)}.text-center{text-align:center}.text-left{text-align:left}.align-middle{vertical-align:middle}.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-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-\[10px\]{font-size:10px}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.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-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-accent-foreground{color:hsl(var(--accent-foreground))}.text-blue-500{color:var(--color-blue-500)}.text-card-foreground{color:hsl(var(--card-foreground))}.text-destructive{color:hsl(var(--destructive))}.text-destructive-foreground{color:hsl(var(--destructive-foreground))}.text-foreground{color:hsl(var(--foreground))}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-green-500{color:var(--color-green-500)}.text-muted-foreground{color:hsl(var(--muted-foreground))}.text-primary-foreground{color:hsl(var(--primary-foreground))}.text-primary\/80{color:hsl(var(--primary))}@supports (color:color-mix(in lab,red,red)){.text-primary\/80{color:color-mix(in oklab,hsl(var(--primary))80%,transparent)}}.text-red-500{color:var(--color-red-500)}.text-red-600{color:var(--color-red-600)}.text-secondary-foreground{color:hsl(var(--secondary-foreground))}.text-yellow-500{color:var(--color-yellow-500)}.opacity-0{opacity:0}.opacity-20{opacity:.2}.opacity-30{opacity:.3}.opacity-70{opacity:.7}.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-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)}.ring{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-offset-background{--tw-ring-offset-color:hsl(var(--background))}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.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,visibility,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-300{--tw-duration:.3s;transition-duration:.3s;animation-duration:.3s}@media (hover:hover){.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.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)}.placeholder\:text-muted-foreground::placeholder{color:hsl(var(--muted-foreground))}@media (hover:hover){.hover\:bg-accent:hover,.hover\:bg-accent\/10:hover{background-color:hsl(var(--accent))}@supports (color:color-mix(in lab,red,red)){.hover\:bg-accent\/10:hover{background-color:color-mix(in oklab,hsl(var(--accent))10%,transparent)}}.hover\:bg-destructive\/10:hover{background-color:hsl(var(--destructive))}@supports (color:color-mix(in lab,red,red)){.hover\:bg-destructive\/10:hover{background-color:color-mix(in oklab,hsl(var(--destructive))10%,transparent)}}.hover\:bg-destructive\/90:hover{background-color:hsl(var(--destructive))}@supports (color:color-mix(in lab,red,red)){.hover\:bg-destructive\/90:hover{background-color:color-mix(in oklab,hsl(var(--destructive))90%,transparent)}}.hover\:bg-muted\/50:hover{background-color:hsl(var(--muted))}@supports (color:color-mix(in lab,red,red)){.hover\:bg-muted\/50:hover{background-color:color-mix(in oklab,hsl(var(--muted))50%,transparent)}}.hover\:bg-primary\/90:hover{background-color:hsl(var(--primary))}@supports (color:color-mix(in lab,red,red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab,hsl(var(--primary))90%,transparent)}}.hover\:text-accent-foreground:hover{color:hsl(var(--accent-foreground))}.hover\:text-destructive:hover{color:hsl(var(--destructive))}}.focus-visible\:ring-2:focus-visible{--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-visible\:ring-ring:focus-visible{--tw-ring-color:hsl(var(--ring))}.focus-visible\:ring-offset-2:focus-visible{--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-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.data-\[state\=active\]\:bg-background[data-state=active]{background-color:hsl(var(--background))}.data-\[state\=active\]\:text-foreground[data-state=active]{color:hsl(var(--foreground))}.data-\[state\=active\]\:shadow[data-state=active]{--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)}.data-\[state\=selected\]\:bg-muted[data-state=selected]{background-color:hsl(var(--muted))}@media (min-width:40rem){.sm\:mr-2{margin-right:calc(var(--spacing)*2)}.sm\:ml-0{margin-left:calc(var(--spacing)*0)}.sm\:hidden{display:none}.sm\:inline{display:inline}.sm\:w-auto{width:auto}.sm\:flex-row{flex-direction:row}.sm\:items-center{align-items:center}}@media (min-width:48rem){.md\:hidden{display:none}.md\:inline{display:inline}}.dark\:bg-gray-700:is(.dark *){background-color:var(--color-gray-700)}.\[\&_tr\]\:border-b tr{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.\[\&_tr\:last-child\]\:border-0 tr:last-child{border-style:var(--tw-border-style);border-width:0}.\[\&\:has\(\[role\=checkbox\]\)\]\:pr-0:has([role=checkbox]){padding-right:calc(var(--spacing)*0)}.\[\&\>\[role\=checkbox\]\]\:translate-y-\[2px\]>[role=checkbox]{--tw-translate-y:2px;translate:var(--tw-translate-x)var(--tw-translate-y)}.\[\&\>tr\]\:last\:border-b-0>tr:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}}:root{color-scheme:dark}body{background-color:hsl(var(--background));font-family:var(--font-mono);color:hsl(var(--foreground))}@keyframes enter{0%{opacity:var(--tw-enter-opacity,1);transform:translate3d(var(--tw-enter-translate-x,0),var(--tw-enter-translate-y,0),0)scale3d(var(--tw-enter-scale,1),var(--tw-enter-scale,1),var(--tw-enter-scale,1))rotate(var(--tw-enter-rotate,0))}}@keyframes exit{to{opacity:var(--tw-exit-opacity,1);transform:translate3d(var(--tw-exit-translate-x,0),var(--tw-exit-translate-y,0),0)scale3d(var(--tw-exit-scale,1),var(--tw-exit-scale,1),var(--tw-exit-scale,1))rotate(var(--tw-exit-rotate,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-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-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}@keyframes spin{to{transform:rotate(360deg)}}