morpheus-cli 0.1.9 → 0.1.11
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/dist/channels/__tests__/telegram.test.js +3 -3
- package/dist/channels/telegram.js +14 -14
- package/dist/cli/commands/start.js +8 -8
- package/dist/config/manager.js +2 -0
- package/dist/config/mcp-loader.js +4 -4
- package/dist/config/paths.js +2 -1
- package/dist/http/api.js +1 -1
- package/dist/runtime/__tests__/manual_start_verify.js +7 -7
- package/dist/runtime/__tests__/manual_us1.js +5 -5
- package/dist/runtime/__tests__/oracle.test.js +92 -0
- package/dist/runtime/__tests__/oracle_memory_limit.test.js +53 -0
- package/dist/runtime/__tests__/oracle_persistence.test.js +154 -0
- package/dist/runtime/display.js +5 -5
- package/dist/runtime/migration.js +28 -0
- package/dist/runtime/oracle.js +229 -0
- package/dist/runtime/providers/factory.js +4 -4
- package/dist/runtime/scaffold.js +3 -0
- package/dist/runtime/telephonist.js +55 -0
- package/dist/runtime/tools/__tests__/construtor.test.js +42 -0
- package/dist/runtime/tools/factory.js +5 -5
- package/dist/ui/assets/index-AEbYNHuy.css +1 -0
- package/dist/ui/assets/{index-DpbRiL07.js → index-BjnI8c1U.js} +12 -12
- package/dist/ui/index.html +2 -2
- package/package.json +1 -1
- package/dist/ui/assets/index-CMGsLiNG.css +0 -1
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { HumanMessage, SystemMessage } from "@langchain/core/messages";
|
|
2
|
+
import { ProviderFactory } from "./providers/factory.js";
|
|
3
|
+
import { Construtor } from "./tools/factory.js";
|
|
4
|
+
import { ConfigManager } from "../config/manager.js";
|
|
5
|
+
import { ProviderError } from "./errors.js";
|
|
6
|
+
import { DisplayManager } from "./display.js";
|
|
7
|
+
import { SQLiteChatMessageHistory } from "./memory/sqlite.js";
|
|
8
|
+
export class Oracle {
|
|
9
|
+
provider;
|
|
10
|
+
config;
|
|
11
|
+
history;
|
|
12
|
+
display = DisplayManager.getInstance();
|
|
13
|
+
databasePath;
|
|
14
|
+
constructor(config, overrides) {
|
|
15
|
+
this.config = config || ConfigManager.getInstance().get();
|
|
16
|
+
this.databasePath = overrides?.databasePath;
|
|
17
|
+
}
|
|
18
|
+
async initialize() {
|
|
19
|
+
if (!this.config.llm) {
|
|
20
|
+
throw new Error("LLM configuration missing in config object.");
|
|
21
|
+
}
|
|
22
|
+
// Basic validation before provider creation
|
|
23
|
+
if (!this.config.llm.provider) {
|
|
24
|
+
throw new Error("LLM provider not specified in configuration.");
|
|
25
|
+
}
|
|
26
|
+
// Note: API Key validation is delegated to ProviderFactory or the Provider itself
|
|
27
|
+
// to allow for Environment Variable fallback supported by LangChain.
|
|
28
|
+
try {
|
|
29
|
+
const tools = await Construtor.create();
|
|
30
|
+
this.provider = await ProviderFactory.create(this.config.llm, tools);
|
|
31
|
+
if (!this.provider) {
|
|
32
|
+
throw new Error("Provider factory returned undefined");
|
|
33
|
+
}
|
|
34
|
+
// Initialize persistent memory with SQLite
|
|
35
|
+
this.history = new SQLiteChatMessageHistory({
|
|
36
|
+
sessionId: "default",
|
|
37
|
+
databasePath: this.databasePath,
|
|
38
|
+
limit: this.config.memory?.limit || 100, // Fallback purely defensive if config type allows optional
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
if (err instanceof ProviderError)
|
|
43
|
+
throw err; // Re-throw known errors
|
|
44
|
+
// Wrap unknown errors
|
|
45
|
+
throw new ProviderError(this.config.llm.provider || 'unknown', err, "Oracle initialization failed");
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async chat(message, extraUsage) {
|
|
49
|
+
if (!this.provider) {
|
|
50
|
+
throw new Error("Oracle not initialized. Call initialize() first.");
|
|
51
|
+
}
|
|
52
|
+
if (!this.history) {
|
|
53
|
+
throw new Error("Message history not initialized. Call initialize() first.");
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
this.display.log('Processing message...', { source: 'Oracle' });
|
|
57
|
+
const userMessage = new HumanMessage(message);
|
|
58
|
+
// Inject provider/model metadata for persistence
|
|
59
|
+
userMessage.provider_metadata = {
|
|
60
|
+
provider: this.config.llm.provider,
|
|
61
|
+
model: this.config.llm.model
|
|
62
|
+
};
|
|
63
|
+
// Attach extra usage (e.g. from Audio) to the user message to be persisted
|
|
64
|
+
if (extraUsage) {
|
|
65
|
+
userMessage.usage_metadata = extraUsage;
|
|
66
|
+
}
|
|
67
|
+
const systemMessage = new SystemMessage(`
|
|
68
|
+
You are ${this.config.agent.name}, ${this.config.agent.personality}, the Oracle.
|
|
69
|
+
|
|
70
|
+
Your role is to orchestrate tools, MCPs, and language models to accurately fulfill the Architect’s request.
|
|
71
|
+
|
|
72
|
+
You are an operator, not a guesser.
|
|
73
|
+
Accuracy, verification, and task completion are more important than speed.
|
|
74
|
+
|
|
75
|
+
--------------------------------------------------
|
|
76
|
+
CORE OPERATING PRINCIPLES
|
|
77
|
+
--------------------------------------------------
|
|
78
|
+
|
|
79
|
+
1. TOOL EVALUATION FIRST
|
|
80
|
+
|
|
81
|
+
Before generating any final answer, evaluate whether an available tool or MCP can provide a more accurate, up-to-date, or authoritative result.
|
|
82
|
+
|
|
83
|
+
If a tool can provide the answer, you MUST call the tool.
|
|
84
|
+
|
|
85
|
+
Never generate speculative values when a tool can verify them.
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
2. ACTIVE INTENT TRACKING (CRITICAL)
|
|
89
|
+
|
|
90
|
+
You must always maintain the current active user intent until it is fully resolved.
|
|
91
|
+
|
|
92
|
+
If you ask a clarification question, the original intent remains ACTIVE.
|
|
93
|
+
|
|
94
|
+
When the user responds to a clarification, you MUST:
|
|
95
|
+
|
|
96
|
+
- Combine the new information with the original request
|
|
97
|
+
- Resume the same task
|
|
98
|
+
- Continue the tool evaluation process
|
|
99
|
+
- Complete the original objective
|
|
100
|
+
|
|
101
|
+
You MUST NOT:
|
|
102
|
+
- Treat clarification answers as new unrelated requests
|
|
103
|
+
- Drop the original task
|
|
104
|
+
- Change subject unexpectedly
|
|
105
|
+
|
|
106
|
+
Clarifications are part of the same execution chain.
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
3. NO HISTORICAL ASSUMPTIONS FOR DYNAMIC DATA
|
|
110
|
+
|
|
111
|
+
If the user asks something that:
|
|
112
|
+
|
|
113
|
+
- may change over time
|
|
114
|
+
- depends on system state
|
|
115
|
+
- depends on filesystem
|
|
116
|
+
- depends on external APIs
|
|
117
|
+
- was previously asked in the conversation
|
|
118
|
+
|
|
119
|
+
You MUST NOT reuse previous outputs as final truth.
|
|
120
|
+
|
|
121
|
+
You MUST:
|
|
122
|
+
- Re-evaluate available tools
|
|
123
|
+
- Re-execute relevant tools
|
|
124
|
+
- Provide a fresh result
|
|
125
|
+
|
|
126
|
+
Repeated queries require fresh verification.
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
4. HISTORY IS CONTEXT, NOT SOURCE OF TRUTH
|
|
130
|
+
|
|
131
|
+
Conversation history provides context, not verified data.
|
|
132
|
+
|
|
133
|
+
Never assume:
|
|
134
|
+
- System state
|
|
135
|
+
- File contents
|
|
136
|
+
- Database values
|
|
137
|
+
- API responses
|
|
138
|
+
|
|
139
|
+
based only on previous messages.
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
5. TASK RESOLUTION LOOP
|
|
143
|
+
|
|
144
|
+
You must operate in this loop:
|
|
145
|
+
|
|
146
|
+
- Identify intent
|
|
147
|
+
- Determine missing information (if any)
|
|
148
|
+
- Ask clarification ONLY if necessary
|
|
149
|
+
- When clarification is received, resume original task
|
|
150
|
+
- Evaluate tools
|
|
151
|
+
- Execute tools if applicable
|
|
152
|
+
- Deliver verified answer
|
|
153
|
+
|
|
154
|
+
Do not break this loop.
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
6. TOOL PRIORITY OVER LANGUAGE GUESSING
|
|
158
|
+
|
|
159
|
+
If a tool can compute, fetch, inspect, or verify something, prefer tool usage.
|
|
160
|
+
|
|
161
|
+
Never hallucinate values retrievable via tools.
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
7. FINAL ANSWER POLICY
|
|
165
|
+
|
|
166
|
+
Provide a natural language answer only if:
|
|
167
|
+
|
|
168
|
+
- No tool is relevant
|
|
169
|
+
- Tools are unavailable
|
|
170
|
+
- The request is purely conceptual
|
|
171
|
+
|
|
172
|
+
Otherwise, use tools first.
|
|
173
|
+
|
|
174
|
+
--------------------------------------------------
|
|
175
|
+
|
|
176
|
+
You are a deterministic orchestration layer.
|
|
177
|
+
You do not drift.
|
|
178
|
+
You do not abandon tasks.
|
|
179
|
+
You do not speculate when verification is possible.
|
|
180
|
+
|
|
181
|
+
You maintain intent until resolution.
|
|
182
|
+
|
|
183
|
+
`);
|
|
184
|
+
// Load existing history from database
|
|
185
|
+
const previousMessages = await this.history.getMessages();
|
|
186
|
+
const messages = [
|
|
187
|
+
systemMessage,
|
|
188
|
+
...previousMessages,
|
|
189
|
+
userMessage
|
|
190
|
+
];
|
|
191
|
+
const response = await this.provider.invoke({ messages });
|
|
192
|
+
// Identify new messages generated during the interaction
|
|
193
|
+
// The `messages` array passed to invoke had length `messages.length`
|
|
194
|
+
// The `response.messages` contains the full state.
|
|
195
|
+
// New messages start after the inputs.
|
|
196
|
+
const startNewMessagesIndex = messages.length;
|
|
197
|
+
const newGeneratedMessages = response.messages.slice(startNewMessagesIndex);
|
|
198
|
+
// Persist User Message first
|
|
199
|
+
await this.history.addMessage(userMessage);
|
|
200
|
+
// Persist all new intermediate tool calls and responses
|
|
201
|
+
for (const msg of newGeneratedMessages) {
|
|
202
|
+
// Inject provider/model metadata search interactors
|
|
203
|
+
msg.provider_metadata = {
|
|
204
|
+
provider: this.config.llm.provider,
|
|
205
|
+
model: this.config.llm.model
|
|
206
|
+
};
|
|
207
|
+
await this.history.addMessage(msg);
|
|
208
|
+
}
|
|
209
|
+
this.display.log('Response generated.', { source: 'Oracle' });
|
|
210
|
+
const lastMessage = response.messages[response.messages.length - 1];
|
|
211
|
+
return (typeof lastMessage.content === 'string') ? lastMessage.content : JSON.stringify(lastMessage.content);
|
|
212
|
+
}
|
|
213
|
+
catch (err) {
|
|
214
|
+
throw new ProviderError(this.config.llm.provider, err, "Chat request failed");
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
async getHistory() {
|
|
218
|
+
if (!this.history) {
|
|
219
|
+
throw new Error("Message history not initialized. Call initialize() first.");
|
|
220
|
+
}
|
|
221
|
+
return await this.history.getMessages();
|
|
222
|
+
}
|
|
223
|
+
async clearMemory() {
|
|
224
|
+
if (!this.history) {
|
|
225
|
+
throw new Error("Message history not initialized. Call initialize() first.");
|
|
226
|
+
}
|
|
227
|
+
await this.history.clear();
|
|
228
|
+
}
|
|
229
|
+
}
|
|
@@ -14,15 +14,15 @@ export class ProviderFactory {
|
|
|
14
14
|
const toolMonitoringMiddleware = createMiddleware({
|
|
15
15
|
name: "ToolMonitoringMiddleware",
|
|
16
16
|
wrapToolCall: (request, handler) => {
|
|
17
|
-
display.log(`Executing tool: ${request.toolCall.name}`, { level: "warning", source: '
|
|
18
|
-
display.log(`Arguments: ${JSON.stringify(request.toolCall.args)}`, { level: "info", source: '
|
|
17
|
+
display.log(`Executing tool: ${request.toolCall.name}`, { level: "warning", source: 'ConstructLoad' });
|
|
18
|
+
display.log(`Arguments: ${JSON.stringify(request.toolCall.args)}`, { level: "info", source: 'ConstructLoad' });
|
|
19
19
|
try {
|
|
20
20
|
const result = handler(request);
|
|
21
|
-
display.log("Tool completed successfully", { level: "info", source: '
|
|
21
|
+
display.log("Tool completed successfully", { level: "info", source: 'ConstructLoad' });
|
|
22
22
|
return result;
|
|
23
23
|
}
|
|
24
24
|
catch (e) {
|
|
25
|
-
display.log(`Tool failed: ${e}`, { level: "error", source: '
|
|
25
|
+
display.log(`Tool failed: ${e}`, { level: "error", source: 'ConstructLoad' });
|
|
26
26
|
throw e;
|
|
27
27
|
}
|
|
28
28
|
},
|
package/dist/runtime/scaffold.js
CHANGED
|
@@ -4,6 +4,7 @@ import { ConfigManager } from '../config/manager.js';
|
|
|
4
4
|
import { DEFAULT_MCP_TEMPLATE } from '../types/mcp.js';
|
|
5
5
|
import chalk from 'chalk';
|
|
6
6
|
import ora from 'ora';
|
|
7
|
+
import { migrateConfigFile } from './migration.js';
|
|
7
8
|
export async function scaffold() {
|
|
8
9
|
const spinner = ora('Ensuring Morpheus environment...').start();
|
|
9
10
|
try {
|
|
@@ -15,6 +16,8 @@ export async function scaffold() {
|
|
|
15
16
|
fs.ensureDir(PATHS.cache),
|
|
16
17
|
fs.ensureDir(PATHS.commands),
|
|
17
18
|
]);
|
|
19
|
+
// Migrate config.yaml -> zaion.yaml if needed
|
|
20
|
+
await migrateConfigFile();
|
|
18
21
|
// Create config if not exists
|
|
19
22
|
const configManager = ConfigManager.getInstance();
|
|
20
23
|
if (!(await fs.pathExists(PATHS.config))) {
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { GoogleGenAI } from '@google/genai';
|
|
2
|
+
export class Telephonist {
|
|
3
|
+
async transcribe(filePath, mimeType, apiKey) {
|
|
4
|
+
try {
|
|
5
|
+
const ai = new GoogleGenAI({ apiKey });
|
|
6
|
+
// Upload the file
|
|
7
|
+
const uploadResult = await ai.files.upload({
|
|
8
|
+
file: filePath,
|
|
9
|
+
config: { mimeType }
|
|
10
|
+
});
|
|
11
|
+
// Generate content (transcription)
|
|
12
|
+
// using gemini-1.5-flash as it is fast and supports audio
|
|
13
|
+
const response = await ai.models.generateContent({
|
|
14
|
+
model: 'gemini-2.5-flash-lite',
|
|
15
|
+
contents: [
|
|
16
|
+
{
|
|
17
|
+
role: 'user',
|
|
18
|
+
parts: [
|
|
19
|
+
{
|
|
20
|
+
fileData: {
|
|
21
|
+
fileUri: uploadResult.uri,
|
|
22
|
+
mimeType: uploadResult.mimeType
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
{ text: "Transcribe this audio message accurately. Return only the transcribed text without any additional commentary." }
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
});
|
|
30
|
+
// The new SDK returns text directly on the response object
|
|
31
|
+
const text = response.text;
|
|
32
|
+
if (!text) {
|
|
33
|
+
throw new Error('No transcription generated');
|
|
34
|
+
}
|
|
35
|
+
// Extract usage metadata
|
|
36
|
+
const usage = response.usageMetadata;
|
|
37
|
+
const usageMetadata = {
|
|
38
|
+
input_tokens: usage?.promptTokenCount ?? 0,
|
|
39
|
+
output_tokens: usage?.candidatesTokenCount ?? 0,
|
|
40
|
+
total_tokens: usage?.totalTokenCount ?? 0,
|
|
41
|
+
input_token_details: {
|
|
42
|
+
cache_read: usage?.cachedContentTokenCount ?? 0
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
return { text, usage: usageMetadata };
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
// Wrap error for clarity
|
|
49
|
+
if (error instanceof Error) {
|
|
50
|
+
throw new Error(`Audio transcription failed: ${error.message}`);
|
|
51
|
+
}
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { Construtor } from '../factory.js';
|
|
3
|
+
import { MultiServerMCPClient } from "@langchain/mcp-adapters";
|
|
4
|
+
vi.mock("@langchain/mcp-adapters", () => {
|
|
5
|
+
return {
|
|
6
|
+
MultiServerMCPClient: vi.fn(),
|
|
7
|
+
};
|
|
8
|
+
});
|
|
9
|
+
vi.mock("../../display.js", () => ({
|
|
10
|
+
DisplayManager: {
|
|
11
|
+
getInstance: () => ({
|
|
12
|
+
log: vi.fn(),
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
}));
|
|
16
|
+
describe('Construtor', () => {
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
vi.resetAllMocks();
|
|
19
|
+
});
|
|
20
|
+
it('should create tools successfully', async () => {
|
|
21
|
+
const mockGetTools = vi.fn().mockResolvedValue(['tool1', 'tool2']);
|
|
22
|
+
// Mock the constructor and getTools method
|
|
23
|
+
MultiServerMCPClient.mockImplementation(function () {
|
|
24
|
+
return {
|
|
25
|
+
getTools: mockGetTools
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
const tools = await Construtor.create();
|
|
29
|
+
expect(MultiServerMCPClient).toHaveBeenCalled();
|
|
30
|
+
expect(mockGetTools).toHaveBeenCalled();
|
|
31
|
+
expect(tools).toEqual(['tool1', 'tool2']);
|
|
32
|
+
});
|
|
33
|
+
it('should return empty array on failure', async () => {
|
|
34
|
+
MultiServerMCPClient.mockImplementation(function () {
|
|
35
|
+
return {
|
|
36
|
+
getTools: vi.fn().mockRejectedValue(new Error('MCP Failed'))
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
const tools = await Construtor.create();
|
|
40
|
+
expect(tools).toEqual([]);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -29,7 +29,7 @@ function sanitizeSchema(obj) {
|
|
|
29
29
|
* Creates a proxy that intercepts schema access and sanitizes the output.
|
|
30
30
|
*/
|
|
31
31
|
function wrapToolWithSanitizedSchema(tool) {
|
|
32
|
-
display.log('Tool loaded: - ' + tool.name, { source: '
|
|
32
|
+
display.log('Tool loaded: - ' + tool.name, { source: 'Construtor' });
|
|
33
33
|
// The MCP tools have a schema property that returns JSON Schema
|
|
34
34
|
// We need to intercept and sanitize it
|
|
35
35
|
const originalSchema = tool.schema;
|
|
@@ -40,13 +40,13 @@ function wrapToolWithSanitizedSchema(tool) {
|
|
|
40
40
|
}
|
|
41
41
|
return tool;
|
|
42
42
|
}
|
|
43
|
-
export class
|
|
43
|
+
export class Construtor {
|
|
44
44
|
static async create() {
|
|
45
45
|
const display = DisplayManager.getInstance();
|
|
46
46
|
const mcpServers = await loadMCPConfig();
|
|
47
47
|
const serverCount = Object.keys(mcpServers).length;
|
|
48
48
|
if (serverCount === 0) {
|
|
49
|
-
display.log('No MCP servers configured in mcps.json', { level: 'info', source: '
|
|
49
|
+
display.log('No MCP servers configured in mcps.json', { level: 'info', source: 'Construtor' });
|
|
50
50
|
return [];
|
|
51
51
|
}
|
|
52
52
|
const client = new MultiServerMCPClient({
|
|
@@ -67,11 +67,11 @@ export class ToolsFactory {
|
|
|
67
67
|
const tools = await client.getTools();
|
|
68
68
|
// Sanitize tool schemas to remove fields not supported by Gemini
|
|
69
69
|
const sanitizedTools = tools.map(tool => wrapToolWithSanitizedSchema(tool));
|
|
70
|
-
display.log(`Loaded ${sanitizedTools.length} MCP tools (schemas sanitized for Gemini compatibility)`, { level: 'info', source: '
|
|
70
|
+
display.log(`Loaded ${sanitizedTools.length} MCP tools (schemas sanitized for Gemini compatibility)`, { level: 'info', source: 'Construtor' });
|
|
71
71
|
return sanitizedTools;
|
|
72
72
|
}
|
|
73
73
|
catch (error) {
|
|
74
|
-
display.log(`Failed to initialize MCP tools: ${error}`, { level: 'warning', source: '
|
|
74
|
+
display.log(`Failed to initialize MCP tools: ${error}`, { level: 'warning', source: 'Construtor' });
|
|
75
75
|
return []; // Return empty tools on failure to allow agent to start
|
|
76
76
|
}
|
|
77
77
|
}
|
|
@@ -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}.static{position:static}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.top-0{top:0}.z-10{z-index:10}.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}.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-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-8{height:2rem}.h-full{height:100%}.h-screen{height:100vh}.min-h-screen{min-height:100vh}.w-11{width:2.75rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-full{width:100%}.max-w-4xl{max-width:56rem}.max-w-6xl{max-width:72rem}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.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}.cursor-not-allowed{cursor:not-allowed}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.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-center{justify-content:center}.justify-between{justify-content:space-between}.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-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}.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-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}.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-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-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-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.pb-4{padding-bottom:1rem}.pb-px{padding-bottom:1px}.pl-4{padding-left:1rem}.pr-4{padding-right:1rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.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}.uppercase{text-transform:uppercase}.italic{font-style:italic}.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-green-500{--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}.text-matrix-secondary{--tw-text-opacity: 1;color:rgb(0 143 17 / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.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-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}.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-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\:text-azure-primary:hover{--tw-text-opacity: 1;color:rgb(0 102 204 / var(--tw-text-opacity, 1))}.hover\:text-red-600:hover{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity, 1))}.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-offset-2:focus{--tw-ring-offset-width: 2px}.focus\:ring-offset-azure-bg:focus{--tw-ring-offset-color: #F0F4F8}.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\: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-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-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-white:is(.dark *){--tw-text-opacity: 1;color:rgb(255 255 255 / 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\: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\/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-zinc-900:hover:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(24 24 27 / var(--tw-bg-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\: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-offset-black:focus:is(.dark *){--tw-ring-offset-color: #000}.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: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))}}
|