morpheus-cli 0.2.2 → 0.2.4
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 +64 -0
- package/dist/cli/commands/init.js +14 -14
- package/dist/config/manager.js +1 -1
- package/dist/config/schemas.js +2 -2
- package/dist/http/api.js +66 -1
- package/dist/runtime/memory/sati/index.js +0 -1
- package/dist/runtime/memory/sati/repository.js +7 -0
- package/dist/runtime/memory/sati/service.js +2 -2
- package/dist/runtime/memory/sati/system-prompts.js +3 -1
- package/dist/ui/assets/index-3USYAgWN.css +1 -0
- package/dist/ui/assets/index-Pd9zlYEP.js +58 -0
- package/dist/ui/index.html +2 -2
- package/package.json +2 -2
- package/dist/ui/assets/index-Ddyo4FWH.js +0 -50
- package/dist/ui/assets/index-tz0YVye-.css +0 -1
package/README.md
CHANGED
|
@@ -120,6 +120,7 @@ Morpheus features a dedicated middleware system called **Sati** (Mindfulness) th
|
|
|
120
120
|
- **Automated Storage**: Automatically extracts and saves preferences, project details, and facts from conversations.
|
|
121
121
|
- **Contextual Retrieval**: Injects relevant memories into the context based on your current query.
|
|
122
122
|
- **Data Privacy**: Stored in a local, independent SQLite database (`santi-memory.db`), ensuring sensitive data is handled securely and reducing context window usage.
|
|
123
|
+
- **Memory Management**: View and manage your long-term memories through the Web UI or via API endpoints.
|
|
123
124
|
|
|
124
125
|
### 📊 Usage Analytics
|
|
125
126
|
Track your token usage across different providers and models directly from the Web UI. View detailed breakdowns of input/output tokens and message counts to monitor costs and activity.
|
|
@@ -233,6 +234,69 @@ Morpheus supports external tools via **MCP (Model Context Protocol)**. Configure
|
|
|
233
234
|
}
|
|
234
235
|
```
|
|
235
236
|
|
|
237
|
+
## API Endpoints
|
|
238
|
+
|
|
239
|
+
Morpheus exposes several API endpoints for programmatic access to its features:
|
|
240
|
+
|
|
241
|
+
### Sati Memories Endpoints
|
|
242
|
+
|
|
243
|
+
#### GET `/api/sati/memories`
|
|
244
|
+
Retrieve all memories stored by the Sati agent (long-term memory).
|
|
245
|
+
|
|
246
|
+
* **Authentication:** Requires `Authorization` header with the password set in `THE_ARCHITECT_PASS`.
|
|
247
|
+
* **Response:**
|
|
248
|
+
```json
|
|
249
|
+
[
|
|
250
|
+
{
|
|
251
|
+
"id": "unique-id",
|
|
252
|
+
"category": "work",
|
|
253
|
+
"importance": "high",
|
|
254
|
+
"summary": "Memory summary",
|
|
255
|
+
"details": "Additional details of the memory",
|
|
256
|
+
"hash": "unique-hash",
|
|
257
|
+
"source": "source",
|
|
258
|
+
"created_at": "2023-01-01T00:00:00.000Z",
|
|
259
|
+
"updated_at": "2023-01-01T00:00:00.000Z",
|
|
260
|
+
"last_accessed_at": "2023-01-01T00:00:00.000Z",
|
|
261
|
+
"access_count": 5,
|
|
262
|
+
"version": 1,
|
|
263
|
+
"archived": false
|
|
264
|
+
}
|
|
265
|
+
]
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
#### DELETE `/api/sati/memories/:id`
|
|
269
|
+
Archive (soft delete) a specific memory from the Sati agent.
|
|
270
|
+
|
|
271
|
+
* **Authentication:** Requires `Authorization` header with the password set in `THE_ARCHITECT_PASS`.
|
|
272
|
+
* **Parameters:** `id` - ID of the memory to archive.
|
|
273
|
+
* **Response:**
|
|
274
|
+
```json
|
|
275
|
+
{
|
|
276
|
+
"success": true,
|
|
277
|
+
"message": "Memory archived successfully"
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
#### POST `/api/sati/memories/bulk-delete`
|
|
282
|
+
Archive (soft delete) multiple memories from the Sati agent at once.
|
|
283
|
+
|
|
284
|
+
* **Authentication:** Requires `Authorization` header with the password set in `THE_ARCHITECT_PASS`.
|
|
285
|
+
* **Body:**
|
|
286
|
+
```json
|
|
287
|
+
{
|
|
288
|
+
"ids": ["id1", "id2", "id3"]
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
* **Response:**
|
|
292
|
+
```json
|
|
293
|
+
{
|
|
294
|
+
"success": true,
|
|
295
|
+
"message": "X memories archived successfully",
|
|
296
|
+
"deletedCount": X
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
236
300
|
## Testing
|
|
237
301
|
|
|
238
302
|
We use **Vitest** for testing.
|
|
@@ -82,9 +82,9 @@ export const initCommand = new Command('init')
|
|
|
82
82
|
validate: (val) => (!isNaN(Number(val)) && Number(val) > 0) || 'Must be a positive number'
|
|
83
83
|
});
|
|
84
84
|
await configManager.set('llm.context_window', Number(contextWindow));
|
|
85
|
-
//
|
|
85
|
+
// Sati (Memory Agent) Configuration
|
|
86
86
|
display.log(chalk.blue('\nSati (Memory Agent) Configuration'));
|
|
87
|
-
const
|
|
87
|
+
const configureSati = await select({
|
|
88
88
|
message: 'Configure Sati separately?',
|
|
89
89
|
choices: [
|
|
90
90
|
{ name: 'No (Use main LLM settings)', value: 'no' },
|
|
@@ -96,10 +96,10 @@ export const initCommand = new Command('init')
|
|
|
96
96
|
let santiModel = model;
|
|
97
97
|
let santiApiKey = apiKey;
|
|
98
98
|
// If using main settings and no new key provided, use existing if available
|
|
99
|
-
if (
|
|
99
|
+
if (configureSati === 'no' && !santiApiKey && hasExistingKey) {
|
|
100
100
|
santiApiKey = currentConfig.llm.api_key;
|
|
101
101
|
}
|
|
102
|
-
if (
|
|
102
|
+
if (configureSati === 'yes') {
|
|
103
103
|
santiProvider = await select({
|
|
104
104
|
message: 'Select Sati LLM Provider:',
|
|
105
105
|
choices: [
|
|
@@ -110,37 +110,37 @@ export const initCommand = new Command('init')
|
|
|
110
110
|
],
|
|
111
111
|
default: currentConfig.santi?.provider || provider,
|
|
112
112
|
});
|
|
113
|
-
let
|
|
113
|
+
let defaultSatiModel = 'gpt-3.5-turbo';
|
|
114
114
|
switch (santiProvider) {
|
|
115
115
|
case 'openai':
|
|
116
|
-
|
|
116
|
+
defaultSatiModel = 'gpt-4o';
|
|
117
117
|
break;
|
|
118
118
|
case 'anthropic':
|
|
119
|
-
|
|
119
|
+
defaultSatiModel = 'claude-3-5-sonnet-20240620';
|
|
120
120
|
break;
|
|
121
121
|
case 'ollama':
|
|
122
|
-
|
|
122
|
+
defaultSatiModel = 'llama3';
|
|
123
123
|
break;
|
|
124
124
|
case 'gemini':
|
|
125
|
-
|
|
125
|
+
defaultSatiModel = 'gemini-pro';
|
|
126
126
|
break;
|
|
127
127
|
}
|
|
128
128
|
if (santiProvider === currentConfig.santi?.provider) {
|
|
129
|
-
|
|
129
|
+
defaultSatiModel = currentConfig.santi?.model || defaultSatiModel;
|
|
130
130
|
}
|
|
131
131
|
santiModel = await input({
|
|
132
132
|
message: 'Enter Sati Model Name:',
|
|
133
|
-
default:
|
|
133
|
+
default: defaultSatiModel,
|
|
134
134
|
});
|
|
135
|
-
const
|
|
136
|
-
const santiKeyMsg =
|
|
135
|
+
const hasExistingSatiKey = !!currentConfig.santi?.api_key;
|
|
136
|
+
const santiKeyMsg = hasExistingSatiKey
|
|
137
137
|
? 'Enter Sati API Key (leave empty to preserve existing):'
|
|
138
138
|
: 'Enter Sati API Key:';
|
|
139
139
|
const keyInput = await password({ message: santiKeyMsg });
|
|
140
140
|
if (keyInput) {
|
|
141
141
|
santiApiKey = keyInput;
|
|
142
142
|
}
|
|
143
|
-
else if (
|
|
143
|
+
else if (hasExistingSatiKey) {
|
|
144
144
|
santiApiKey = currentConfig.santi?.api_key;
|
|
145
145
|
}
|
|
146
146
|
else {
|
package/dist/config/manager.js
CHANGED
package/dist/config/schemas.js
CHANGED
|
@@ -15,7 +15,7 @@ export const LLMConfigSchema = z.object({
|
|
|
15
15
|
api_key: z.string().optional(),
|
|
16
16
|
context_window: z.number().int().positive().optional(),
|
|
17
17
|
});
|
|
18
|
-
export const
|
|
18
|
+
export const SatiConfigSchema = LLMConfigSchema.extend({
|
|
19
19
|
memory_limit: z.number().int().positive().optional(),
|
|
20
20
|
});
|
|
21
21
|
// Zod Schema matching MorpheusConfig interface
|
|
@@ -25,7 +25,7 @@ export const ConfigSchema = z.object({
|
|
|
25
25
|
personality: z.string().default(DEFAULT_CONFIG.agent.personality),
|
|
26
26
|
}).default(DEFAULT_CONFIG.agent),
|
|
27
27
|
llm: LLMConfigSchema.default(DEFAULT_CONFIG.llm),
|
|
28
|
-
santi:
|
|
28
|
+
santi: SatiConfigSchema.optional(),
|
|
29
29
|
audio: AudioConfigSchema.default(DEFAULT_CONFIG.audio),
|
|
30
30
|
memory: z.object({
|
|
31
31
|
limit: z.number().int().positive().optional(),
|
package/dist/http/api.js
CHANGED
|
@@ -5,6 +5,7 @@ import { DisplayManager } from '../runtime/display.js';
|
|
|
5
5
|
import fs from 'fs-extra';
|
|
6
6
|
import path from 'path';
|
|
7
7
|
import { SQLiteChatMessageHistory } from '../runtime/memory/sqlite.js';
|
|
8
|
+
import { SatiRepository } from '../runtime/memory/sati/repository.js';
|
|
8
9
|
async function readLastLines(filePath, n) {
|
|
9
10
|
try {
|
|
10
11
|
const content = await fs.readFile(filePath, 'utf8');
|
|
@@ -116,7 +117,7 @@ export function createApiRouter() {
|
|
|
116
117
|
// Sati config endpoints
|
|
117
118
|
router.get('/config/sati', (req, res) => {
|
|
118
119
|
try {
|
|
119
|
-
const satiConfig = configManager.
|
|
120
|
+
const satiConfig = configManager.getSatiConfig();
|
|
120
121
|
res.json(satiConfig);
|
|
121
122
|
}
|
|
122
123
|
catch (error) {
|
|
@@ -159,6 +160,70 @@ export function createApiRouter() {
|
|
|
159
160
|
res.status(500).json({ error: error.message });
|
|
160
161
|
}
|
|
161
162
|
});
|
|
163
|
+
// Sati memories endpoints
|
|
164
|
+
router.get('/sati/memories', async (req, res) => {
|
|
165
|
+
try {
|
|
166
|
+
const repository = SatiRepository.getInstance();
|
|
167
|
+
const memories = repository.getAllMemories();
|
|
168
|
+
// Convert dates to ISO strings for JSON serialization
|
|
169
|
+
const serializedMemories = memories.map(memory => ({
|
|
170
|
+
...memory,
|
|
171
|
+
created_at: memory.created_at.toISOString(),
|
|
172
|
+
updated_at: memory.updated_at.toISOString(),
|
|
173
|
+
last_accessed_at: memory.last_accessed_at ? memory.last_accessed_at.toISOString() : null
|
|
174
|
+
}));
|
|
175
|
+
res.json(serializedMemories);
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
res.status(500).json({ error: error.message });
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
router.delete('/sati/memories/:id', async (req, res) => {
|
|
182
|
+
try {
|
|
183
|
+
const { id } = req.params;
|
|
184
|
+
const repository = SatiRepository.getInstance();
|
|
185
|
+
const success = repository.archiveMemory(id);
|
|
186
|
+
if (!success) {
|
|
187
|
+
return res.status(404).json({ error: 'Memory not found' });
|
|
188
|
+
}
|
|
189
|
+
res.json({ success: true, message: 'Memory archived successfully' });
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
res.status(500).json({ error: error.message });
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
router.post('/sati/memories/bulk-delete', async (req, res) => {
|
|
196
|
+
try {
|
|
197
|
+
const { ids } = req.body;
|
|
198
|
+
if (!ids || !Array.isArray(ids) || ids.length === 0) {
|
|
199
|
+
return res.status(400).json({ error: 'Ids array is required and cannot be empty' });
|
|
200
|
+
}
|
|
201
|
+
const repository = SatiRepository.getInstance();
|
|
202
|
+
let deletedCount = 0;
|
|
203
|
+
// Use a transaction for atomicity, but check if db is not null
|
|
204
|
+
const db = repository['db'];
|
|
205
|
+
if (!db) {
|
|
206
|
+
return res.status(500).json({ error: 'Database connection is not available' });
|
|
207
|
+
}
|
|
208
|
+
const transaction = db.transaction((memoryIds) => {
|
|
209
|
+
for (const id of memoryIds) {
|
|
210
|
+
const success = repository.archiveMemory(id);
|
|
211
|
+
if (success) {
|
|
212
|
+
deletedCount++;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
transaction(ids);
|
|
217
|
+
res.json({
|
|
218
|
+
success: true,
|
|
219
|
+
message: `${deletedCount} memories archived successfully`,
|
|
220
|
+
deletedCount
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
res.status(500).json({ error: error.message });
|
|
225
|
+
}
|
|
226
|
+
});
|
|
162
227
|
// Keep PUT for backward compatibility if needed, or remove.
|
|
163
228
|
// Tasks says Implement POST. I'll remove PUT to avoid confusion or redirect it.
|
|
164
229
|
router.put('/config', async (req, res) => {
|
|
@@ -43,7 +43,6 @@ export class SatiMemoryMiddleware {
|
|
|
43
43
|
}
|
|
44
44
|
async afterAgent(generatedResponse, history) {
|
|
45
45
|
try {
|
|
46
|
-
// Phase 4 implementation (T013)
|
|
47
46
|
await this.service.evaluateAndPersist([
|
|
48
47
|
...history.slice(-5).map(m => ({
|
|
49
48
|
role: m._getType() === 'human' ? 'user' : 'assistant',
|
|
@@ -216,4 +216,11 @@ export class SatiRepository {
|
|
|
216
216
|
this.db = null;
|
|
217
217
|
}
|
|
218
218
|
}
|
|
219
|
+
archiveMemory(id) {
|
|
220
|
+
if (!this.db)
|
|
221
|
+
this.initialize();
|
|
222
|
+
const stmt = this.db.prepare('UPDATE long_term_memory SET archived = 1 WHERE id = ?');
|
|
223
|
+
const result = stmt.run(id);
|
|
224
|
+
return result.changes > 0;
|
|
225
|
+
}
|
|
219
226
|
}
|
|
@@ -23,7 +23,7 @@ export class SatiService {
|
|
|
23
23
|
this.repository.initialize();
|
|
24
24
|
}
|
|
25
25
|
async recover(currentMessage, recentMessages) {
|
|
26
|
-
const santiConfig = ConfigManager.getInstance().
|
|
26
|
+
const santiConfig = ConfigManager.getInstance().getSatiConfig();
|
|
27
27
|
const memoryLimit = santiConfig.memory_limit || 1000;
|
|
28
28
|
// Use the current message as the primary search query
|
|
29
29
|
// We could enhance this by extracting keywords from the last few messages
|
|
@@ -39,7 +39,7 @@ export class SatiService {
|
|
|
39
39
|
}
|
|
40
40
|
async evaluateAndPersist(conversation) {
|
|
41
41
|
try {
|
|
42
|
-
const santiConfig = ConfigManager.getInstance().
|
|
42
|
+
const santiConfig = ConfigManager.getInstance().getSatiConfig();
|
|
43
43
|
if (!santiConfig)
|
|
44
44
|
return;
|
|
45
45
|
// Use the main provider factory to get an agent (Reusing Zion configuration)
|
|
@@ -22,12 +22,14 @@ Classify any new memory into one of these types:
|
|
|
22
22
|
- **professional_profile**: Job title, industry, skills.
|
|
23
23
|
|
|
24
24
|
### CRITICAL RULES
|
|
25
|
-
0. **USE USER LANGUAGE**: Always use the user's own words for the summary. Do not rephrase or interpret. If user say in portguese "Eu gosto de café", the summary should be exactly "Eu gosto de café", not "User likes coffee".
|
|
26
25
|
1. **NO SECRETS**: NEVER store API keys, passwords, credit cards, or private tokens. If found, ignore them explicitly.
|
|
27
26
|
2. **NO DUPLICATES**: If the information is already covered by the \`existing_memory_summaries\`, DO NOT store it again.
|
|
28
27
|
3. **NO CHIT-CHAT**: Do not store trivial conversation like "Hello", "Thanks", "How are you?".
|
|
29
28
|
4. **IMPORTANCE**: Assign 'low', 'medium', or 'high' importance. Store only 'medium' or 'high' unless it's a specific user preference (which is always important).
|
|
30
29
|
|
|
30
|
+
### TOP IMPORTANT GUIDELINES
|
|
31
|
+
5. **OBEY THE USER**: If the user explicitly states something should be remembered, it must be stored with at least 'medium' importance.
|
|
32
|
+
|
|
31
33
|
### OUTPUT FORMAT
|
|
32
34
|
You MUST respond with a valid JSON object matching the \`ISatiEvaluationOutput\` interface:
|
|
33
35
|
{
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:Courier New,Courier,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}body{--tw-bg-opacity: 1;background-color:rgb(240 244 248 / var(--tw-bg-opacity, 1));font-family:Courier New,Courier,monospace;--tw-text-opacity: 1;color:rgb(26 26 26 / var(--tw-text-opacity, 1));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.3s}body:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(0 143 17 / var(--tw-text-opacity, 1))}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{--tw-bg-opacity: 1;background-color:rgb(240 244 248 / var(--tw-bg-opacity, 1))}:is(.dark *)::-webkit-scrollbar-track{--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}::-webkit-scrollbar-thumb{--tw-bg-opacity: 1;background-color:rgb(179 212 252 / var(--tw-bg-opacity, 1))}:is(.dark *)::-webkit-scrollbar-thumb{--tw-bg-opacity: 1;background-color:rgb(0 59 0 / var(--tw-bg-opacity, 1))}::-webkit-scrollbar-thumb:hover{--tw-bg-opacity: 1;background-color:rgb(74 144 226 / var(--tw-bg-opacity, 1))}:is(.dark *)::-webkit-scrollbar-thumb:hover{--tw-bg-opacity: 1;background-color:rgb(0 143 17 / var(--tw-bg-opacity, 1))}.container{width:100%}@media(min-width:640px){.container{max-width:640px}}@media(min-width:768px){.container{max-width:768px}}@media(min-width:1024px){.container{max-width:1024px}}@media(min-width:1280px){.container{max-width:1280px}}@media(min-width:1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.bottom-0{bottom:0}.left-0{left:0}.left-3{left:.75rem}.right-0{right:0}.top-0{top:0}.top-1\/2{top:50%}.z-10{z-index:10}.z-50{z-index:50}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mr-1{margin-right:.25rem}.mt-1{margin-top:.25rem}.mt-4{margin-top:1rem}.mt-8{margin-top:2rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-12{height:3rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-full{height:100%}.h-screen{height:100vh}.max-h-\[90vh\]{max-height:90vh}.min-h-screen{min-height:100vh}.w-10{width:2.5rem}.w-11{width:2.75rem}.w-12{width:3rem}.w-32{width:8rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-8{width:2rem}.w-full{width:100%}.min-w-max{min-width:-moz-max-content;min-width:max-content}.max-w-4xl{max-width:56rem}.max-w-6xl{max-width:72rem}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-sm{max-width:24rem}.max-w-xl{max-width:36rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.flex-shrink-0,.shrink-0{flex-shrink:0}.flex-grow{flex-grow:1}.caption-bottom{caption-side:bottom}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-1{--tw-translate-x: .25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-6{--tw-translate-x: 1.5rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-not-allowed{cursor:not-allowed}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.resize{resize:both}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.25rem * var(--tw-space-x-reverse));margin-left:calc(.25rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.space-y-8>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(2rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-azure-border>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:rgb(179 212 252 / var(--tw-divide-opacity, 1))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-t-md{border-top-left-radius:.375rem;border-top-right-radius:.375rem}.border{border-width:1px}.border-x{border-left-width:1px;border-right-width:1px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l{border-left-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-azure-border{--tw-border-opacity: 1;border-color:rgb(179 212 252 / var(--tw-border-opacity, 1))}.border-azure-primary{--tw-border-opacity: 1;border-color:rgb(0 102 204 / var(--tw-border-opacity, 1))}.border-matrix-primary{--tw-border-opacity: 1;border-color:rgb(0 59 0 / var(--tw-border-opacity, 1))}.border-red-500{--tw-border-opacity: 1;border-color:rgb(239 68 68 / var(--tw-border-opacity, 1))}.border-red-500\/50{border-color:#ef444480}.border-transparent{border-color:transparent}.bg-azure-active{--tw-bg-opacity: 1;background-color:rgb(187 222 251 / var(--tw-bg-opacity, 1))}.bg-azure-bg{--tw-bg-opacity: 1;background-color:rgb(240 244 248 / var(--tw-bg-opacity, 1))}.bg-azure-border{--tw-bg-opacity: 1;background-color:rgb(179 212 252 / var(--tw-bg-opacity, 1))}.bg-azure-hover{--tw-bg-opacity: 1;background-color:rgb(227 242 253 / var(--tw-bg-opacity, 1))}.bg-azure-primary{--tw-bg-opacity: 1;background-color:rgb(0 102 204 / var(--tw-bg-opacity, 1))}.bg-azure-primary\/10{background-color:#0066cc1a}.bg-azure-surface{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-azure-surface\/50{background-color:#ffffff80}.bg-black\/50{background-color:#00000080}.bg-red-500{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.bg-red-900\/10{background-color:#7f1d1d1a}.bg-red-900\/20{background-color:#7f1d1d33}.bg-slate-300{--tw-bg-opacity: 1;background-color:rgb(203 213 225 / var(--tw-bg-opacity, 1))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-\[linear-gradient\(rgba\(18\,16\,16\,0\)_50\%\,rgba\(0\,0\,0\,0\.1\)_50\%\)\,linear-gradient\(90deg\,rgba\(0\,255\,0\,0\.03\)\,rgba\(0\,255\,0\,0\.01\)\)\]{background-image:linear-gradient(#12101000 50%,#0000001a 50%),linear-gradient(90deg,#00ff0008,#00ff0003)}.bg-\[length\:100\%_2px\,3px_100\%\]{background-size:100% 2px,3px 100%}.p-0{padding:0}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-4{padding-bottom:1rem}.pb-px{padding-bottom:1px}.pl-10{padding-left:2.5rem}.pl-4{padding-left:1rem}.pr-4{padding-right:1rem}.pt-0{padding-top:0}.pt-16{padding-top:4rem}.pt-4{padding-top:1rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-middle{vertical-align:middle}.font-mono{font-family:Courier New,Courier,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-\[10px\]{font-size:10px}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-none{line-height:1}.tracking-tight{letter-spacing:-.025em}.tracking-tighter{letter-spacing:-.05em}.tracking-wider{letter-spacing:.05em}.tracking-widest{letter-spacing:.1em}.text-azure-accent{--tw-text-opacity: 1;color:rgb(33 150 243 / var(--tw-text-opacity, 1))}.text-azure-primary{--tw-text-opacity: 1;color:rgb(0 102 204 / var(--tw-text-opacity, 1))}.text-azure-text-muted{--tw-text-opacity: 1;color:rgb(136 153 168 / var(--tw-text-opacity, 1))}.text-azure-text-primary{--tw-text-opacity: 1;color:rgb(26 26 26 / var(--tw-text-opacity, 1))}.text-azure-text-primary\/80{color:#1a1a1acc}.text-azure-text-secondary{--tw-text-opacity: 1;color:rgb(92 107 125 / var(--tw-text-opacity, 1))}.text-blue-500{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity, 1))}.text-green-500{--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-red-700{--tw-text-opacity: 1;color:rgb(185 28 28 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-zinc-50{--tw-text-opacity: 1;color:rgb(250 250 250 / var(--tw-text-opacity, 1))}.underline-offset-4{text-underline-offset:4px}.placeholder-azure-text-secondary\/50::-moz-placeholder{color:#5c6b7d80}.placeholder-azure-text-secondary\/50::placeholder{color:#5c6b7d80}.opacity-0{opacity:0}.opacity-30{opacity:.3}.opacity-50{opacity:.5}.opacity-70{opacity:.7}.opacity-80{opacity:.8}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.ring-offset-white{--tw-ring-offset-color: #fff}.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(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.hover\:border-azure-primary:hover{--tw-border-opacity: 1;border-color:rgb(0 102 204 / var(--tw-border-opacity, 1))}.hover\:bg-azure-active:hover{--tw-bg-opacity: 1;background-color:rgb(187 222 251 / var(--tw-bg-opacity, 1))}.hover\:bg-azure-hover:hover{--tw-bg-opacity: 1;background-color:rgb(227 242 253 / var(--tw-bg-opacity, 1))}.hover\:bg-azure-hover\/50:hover{background-color:#e3f2fd80}.hover\:bg-azure-primary\/10:hover{background-color:#0066cc1a}.hover\:bg-azure-primary\/90:hover{background-color:#0066cce6}.hover\:bg-azure-secondary:hover{--tw-bg-opacity: 1;background-color:rgb(74 144 226 / var(--tw-bg-opacity, 1))}.hover\:bg-red-50:hover{--tw-bg-opacity: 1;background-color:rgb(254 242 242 / var(--tw-bg-opacity, 1))}.hover\:bg-red-500\/90:hover{background-color:#ef4444e6}.hover\:bg-transparent:hover{background-color:transparent}.hover\:text-azure-primary:hover{--tw-text-opacity: 1;color:rgb(0 102 204 / var(--tw-text-opacity, 1))}.hover\:text-azure-text-primary:hover{--tw-text-opacity: 1;color:rgb(26 26 26 / var(--tw-text-opacity, 1))}.hover\:text-blue-700:hover{--tw-text-opacity: 1;color:rgb(29 78 216 / var(--tw-text-opacity, 1))}.hover\:text-red-600:hover{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity, 1))}.hover\:text-red-700:hover{--tw-text-opacity: 1;color:rgb(185 28 28 / var(--tw-text-opacity, 1))}.hover\:underline:hover{text-decoration-line:underline}.focus\:border-azure-primary:focus{--tw-border-opacity: 1;border-color:rgb(0 102 204 / var(--tw-border-opacity, 1))}.focus\:border-red-500:focus{--tw-border-opacity: 1;border-color:rgb(239 68 68 / var(--tw-border-opacity, 1))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-1:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-azure-primary:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(0 102 204 / var(--tw-ring-opacity, 1))}.focus\:ring-red-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(239 68 68 / var(--tw-ring-opacity, 1))}.focus\:ring-zinc-950:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(12 12 12 / var(--tw-ring-opacity, 1))}.focus\:ring-offset-2:focus{--tw-ring-offset-width: 2px}.focus\:ring-offset-azure-bg:focus{--tw-ring-offset-color: #F0F4F8}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-zinc-950:focus-visible{--tw-ring-opacity: 1;--tw-ring-color: rgb(12 12 12 / var(--tw-ring-opacity, 1))}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width: 2px}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:opacity-50:disabled{opacity:.5}.group:hover .group-hover\:text-azure-primary{--tw-text-opacity: 1;color:rgb(0 102 204 / var(--tw-text-opacity, 1))}.dark\:divide-matrix-primary\/30:is(.dark *)>:not([hidden])~:not([hidden]){border-color:#003b004d}.dark\:rounded-none:is(.dark *){border-radius:0}.dark\:border-x:is(.dark *){border-left-width:1px;border-right-width:1px}.dark\:border-t:is(.dark *){border-top-width:1px}.dark\:border-green-500:is(.dark *){--tw-border-opacity: 1;border-color:rgb(34 197 94 / var(--tw-border-opacity, 1))}.dark\:border-green-800:is(.dark *){--tw-border-opacity: 1;border-color:rgb(22 101 52 / var(--tw-border-opacity, 1))}.dark\:border-matrix-highlight:is(.dark *){--tw-border-opacity: 1;border-color:rgb(0 255 65 / var(--tw-border-opacity, 1))}.dark\:border-matrix-primary:is(.dark *){--tw-border-opacity: 1;border-color:rgb(0 59 0 / var(--tw-border-opacity, 1))}.dark\:border-matrix-primary\/50:is(.dark *){border-color:#003b0080}.dark\:border-matrix-secondary:is(.dark *){--tw-border-opacity: 1;border-color:rgb(0 143 17 / var(--tw-border-opacity, 1))}.dark\:border-red-900\/50:is(.dark *){border-color:#7f1d1d80}.dark\:bg-black:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}.dark\:bg-black\/40:is(.dark *){background-color:#0006}.dark\:bg-green-900:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(20 83 45 / var(--tw-bg-opacity, 1))}.dark\:bg-matrix-base:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(13 2 8 / var(--tw-bg-opacity, 1))}.dark\:bg-matrix-base\/50:is(.dark *){background-color:#0d020880}.dark\:bg-matrix-highlight:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(0 255 65 / var(--tw-bg-opacity, 1))}.dark\:bg-matrix-highlight\/10:is(.dark *){background-color:#00ff411a}.dark\:bg-matrix-primary:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(0 59 0 / var(--tw-bg-opacity, 1))}.dark\:bg-matrix-primary\/20:is(.dark *){background-color:#003b0033}.dark\:bg-matrix-primary\/50:is(.dark *){background-color:#003b0080}.dark\:bg-red-900:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(127 29 29 / var(--tw-bg-opacity, 1))}.dark\:bg-zinc-800:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(39 39 42 / var(--tw-bg-opacity, 1))}.dark\:bg-zinc-900:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(24 24 27 / var(--tw-bg-opacity, 1))}.dark\:bg-zinc-900\/50:is(.dark *){background-color:#18181b80}.dark\:bg-zinc-950:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(12 12 12 / var(--tw-bg-opacity, 1))}.dark\:bg-zinc-950\/50:is(.dark *){background-color:#0c0c0c80}.dark\:text-black:is(.dark *){--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity, 1))}.dark\:text-blue-400:is(.dark *){--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.dark\:text-gray-300:is(.dark *){--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}.dark\:text-green-500:is(.dark *){--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}.dark\:text-matrix-highlight:is(.dark *){--tw-text-opacity: 1;color:rgb(0 255 65 / var(--tw-text-opacity, 1))}.dark\:text-matrix-highlight\/50:is(.dark *){color:#00ff4180}.dark\:text-matrix-highlight\/80:is(.dark *){color:#00ff41cc}.dark\:text-matrix-primary:is(.dark *){--tw-text-opacity: 1;color:rgb(0 59 0 / var(--tw-text-opacity, 1))}.dark\:text-matrix-secondary:is(.dark *){--tw-text-opacity: 1;color:rgb(0 143 17 / var(--tw-text-opacity, 1))}.dark\:text-red-300:is(.dark *){--tw-text-opacity: 1;color:rgb(252 165 165 / var(--tw-text-opacity, 1))}.dark\:text-red-400:is(.dark *){--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.dark\:text-white:is(.dark *){--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.dark\:text-zinc-50:is(.dark *){--tw-text-opacity: 1;color:rgb(250 250 250 / var(--tw-text-opacity, 1))}.dark\:placeholder-green-900:is(.dark *)::-moz-placeholder{--tw-placeholder-opacity: 1;color:rgb(20 83 45 / var(--tw-placeholder-opacity, 1))}.dark\:placeholder-green-900:is(.dark *)::placeholder{--tw-placeholder-opacity: 1;color:rgb(20 83 45 / var(--tw-placeholder-opacity, 1))}.dark\:placeholder-matrix-secondary\/50:is(.dark *)::-moz-placeholder{color:#008f1180}.dark\:placeholder-matrix-secondary\/50:is(.dark *)::placeholder{color:#008f1180}.dark\:opacity-20:is(.dark *){opacity:.2}.dark\:shadow-\[0_0_15px_rgba\(34\,197\,94\,0\.3\)\]:is(.dark *){--tw-shadow: 0 0 15px rgba(34,197,94,.3);--tw-shadow-colored: 0 0 15px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.dark\:ring-offset-zinc-950:is(.dark *){--tw-ring-offset-color: #0c0c0c}.dark\:hover\:border-matrix-highlight:hover:is(.dark *){--tw-border-opacity: 1;border-color:rgb(0 255 65 / var(--tw-border-opacity, 1))}.dark\:hover\:bg-green-700:hover:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(21 128 61 / var(--tw-bg-opacity, 1))}.dark\:hover\:bg-matrix-highlight\/10:hover:is(.dark *){background-color:#00ff411a}.dark\:hover\:bg-matrix-highlight\/90:hover:is(.dark *){background-color:#00ff41e6}.dark\:hover\:bg-matrix-primary\/10:hover:is(.dark *){background-color:#003b001a}.dark\:hover\:bg-matrix-primary\/50:hover:is(.dark *){background-color:#003b0080}.dark\:hover\:bg-matrix-secondary:hover:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(0 143 17 / var(--tw-bg-opacity, 1))}.dark\:hover\:bg-red-900\/20:hover:is(.dark *){background-color:#7f1d1d33}.dark\:hover\:bg-red-900\/90:hover:is(.dark *){background-color:#7f1d1de6}.dark\:hover\:bg-zinc-700\/80:hover:is(.dark *){background-color:#3f3f46cc}.dark\:hover\:bg-zinc-900:hover:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(24 24 27 / var(--tw-bg-opacity, 1))}.dark\:hover\:text-blue-300:hover:is(.dark *){--tw-text-opacity: 1;color:rgb(147 197 253 / var(--tw-text-opacity, 1))}.dark\:hover\:text-matrix-highlight:hover:is(.dark *){--tw-text-opacity: 1;color:rgb(0 255 65 / var(--tw-text-opacity, 1))}.dark\:hover\:text-matrix-secondary:hover:is(.dark *){--tw-text-opacity: 1;color:rgb(0 143 17 / var(--tw-text-opacity, 1))}.dark\:hover\:text-red-300:hover:is(.dark *){--tw-text-opacity: 1;color:rgb(252 165 165 / var(--tw-text-opacity, 1))}.dark\:focus\:border-green-500:focus:is(.dark *){--tw-border-opacity: 1;border-color:rgb(34 197 94 / var(--tw-border-opacity, 1))}.dark\:focus\:border-matrix-highlight:focus:is(.dark *){--tw-border-opacity: 1;border-color:rgb(0 255 65 / var(--tw-border-opacity, 1))}.dark\:focus\:ring-matrix-highlight:focus:is(.dark *){--tw-ring-opacity: 1;--tw-ring-color: rgb(0 255 65 / var(--tw-ring-opacity, 1))}.dark\:focus\:ring-matrix-secondary:focus:is(.dark *){--tw-ring-opacity: 1;--tw-ring-color: rgb(0 143 17 / var(--tw-ring-opacity, 1))}.dark\:focus\:ring-zinc-300:focus:is(.dark *){--tw-ring-opacity: 1;--tw-ring-color: rgb(212 212 216 / var(--tw-ring-opacity, 1))}.dark\:focus\:ring-offset-black:focus:is(.dark *){--tw-ring-offset-color: #000}.dark\:focus-visible\:ring-zinc-300:focus-visible:is(.dark *){--tw-ring-opacity: 1;--tw-ring-color: rgb(212 212 216 / var(--tw-ring-opacity, 1))}.group:hover .dark\:group-hover\:text-matrix-highlight:is(.dark *){--tw-text-opacity: 1;color:rgb(0 255 65 / var(--tw-text-opacity, 1))}@media(min-width:640px){.sm\:flex-row{flex-direction:row}.sm\:items-center{align-items:center}}@media(min-width:768px){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:p-6{padding:1.5rem}.md\:p-8{padding:2rem}.md\:pt-0{padding-top:0}}@media(min-width:1024px){.lg\:flex{display:flex}.lg\:hidden{display:none}.lg\:flex-row{flex-direction:row}.lg\:pt-0{padding-top:0}}.\[\&\:has\(\[role\=checkbox\]\)\]\:pr-0:has([role=checkbox]){padding-right:0}.\[\&_p\]\:leading-relaxed p{line-height:1.625}
|