morpheus-cli 0.2.3 → 0.2.5

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.
@@ -2,13 +2,15 @@ import { AUTH_HEADER } from '../../types/auth.js';
2
2
  import { DisplayManager } from '../../runtime/display.js';
3
3
  /**
4
4
  * Middleware to protect API routes with a password from THE_ARCHITECT_PASS env var.
5
- * If the env var is not set, authentication is skipped (open mode).
5
+ * If the env var is not set, uses default password 'iamthearchitect'.
6
6
  */
7
7
  export const authMiddleware = (req, res, next) => {
8
- const architectPass = process.env.THE_ARCHITECT_PASS;
9
- // If password is not configured, allow all requests
10
- if (!architectPass || architectPass.trim() === '') {
11
- return next();
8
+ // Use environment variable if set, otherwise use default password
9
+ const architectPass = process.env.THE_ARCHITECT_PASS || 'iamthearchitect';
10
+ // If password is not configured (using default), log a warning
11
+ if (!process.env.THE_ARCHITECT_PASS) {
12
+ const display = DisplayManager.getInstance();
13
+ display.log('Using default password for dashboard access. For security, set THE_ARCHITECT_PASS environment variable.', { source: 'http', level: 'warning' });
12
14
  }
13
15
  const providedPass = req.headers[AUTH_HEADER];
14
16
  if (providedPass === architectPass) {
@@ -20,8 +20,29 @@ export class HttpServer {
20
20
  setupMiddleware() {
21
21
  this.app.use(cors());
22
22
  this.app.use(bodyParser.json());
23
+ // Adicionar cabeçalhos para evitar indexação por motores de busca
24
+ this.app.use((req, res, next) => {
25
+ res.setHeader('X-Robots-Tag', 'noindex, nofollow');
26
+ next();
27
+ });
23
28
  }
24
29
  setupRoutes() {
30
+ // Rota de health check pública (sem autenticação)
31
+ this.app.get('/health', (req, res) => {
32
+ res.status(200).json({
33
+ status: 'healthy',
34
+ timestamp: new Date().toISOString(),
35
+ uptime: process.uptime()
36
+ });
37
+ });
38
+ // Rota de health check para o Docker (padrão)
39
+ this.app.get('/api/health', (req, res) => {
40
+ res.status(200).json({
41
+ status: 'healthy',
42
+ timestamp: new Date().toISOString(),
43
+ uptime: process.uptime()
44
+ });
45
+ });
25
46
  this.app.use('/api', authMiddleware, createApiRouter());
26
47
  // Serve static frontend from compiled output
27
48
  const uiPath = path.resolve(__dirname, '../ui');
@@ -13,6 +13,7 @@ const mockConfig = {
13
13
  logging: { enabled: false, level: 'info', retention: '1d' },
14
14
  audio: {
15
15
  provider: 'google',
16
+ model: 'gemini-2.5-flash-lite',
16
17
  enabled: false,
17
18
  maxDurationSeconds: 60,
18
19
  supportedMimeTypes: ['audio/ogg']
@@ -34,41 +34,41 @@ export class SatiRepository {
34
34
  createSchema() {
35
35
  if (!this.db)
36
36
  throw new Error("DB not initialized");
37
- this.db.exec(`
38
- CREATE TABLE IF NOT EXISTS long_term_memory (
39
- id TEXT PRIMARY KEY,
40
- category TEXT NOT NULL,
41
- importance TEXT NOT NULL,
42
- summary TEXT NOT NULL,
43
- details TEXT,
44
- hash TEXT NOT NULL UNIQUE,
45
- source TEXT,
46
- created_at TEXT NOT NULL,
47
- updated_at TEXT NOT NULL,
48
- last_accessed_at TEXT,
49
- access_count INTEGER DEFAULT 0,
50
- version INTEGER DEFAULT 1,
51
- archived INTEGER DEFAULT 0
52
- );
53
-
54
- CREATE INDEX IF NOT EXISTS idx_memory_category ON long_term_memory(category);
55
- CREATE INDEX IF NOT EXISTS idx_memory_importance ON long_term_memory(importance);
56
- CREATE INDEX IF NOT EXISTS idx_memory_archived ON long_term_memory(archived);
57
-
58
- -- FTS5 Virtual Table for semantic-like keyword search
59
- CREATE VIRTUAL TABLE IF NOT EXISTS memory_fts USING fts5(summary, content='long_term_memory', content_rowid='rowid');
60
-
61
- -- Triggers to sync FTS
62
- CREATE TRIGGER IF NOT EXISTS memory_ai AFTER INSERT ON long_term_memory BEGIN
63
- INSERT INTO memory_fts(rowid, summary) VALUES (new.rowid, new.summary);
64
- END;
65
- CREATE TRIGGER IF NOT EXISTS memory_ad AFTER DELETE ON long_term_memory BEGIN
66
- INSERT INTO memory_fts(memory_fts, rowid, summary) VALUES('delete', old.rowid, old.summary);
67
- END;
68
- CREATE TRIGGER IF NOT EXISTS memory_au AFTER UPDATE ON long_term_memory BEGIN
69
- INSERT INTO memory_fts(memory_fts, rowid, summary) VALUES('delete', old.rowid, old.summary);
70
- INSERT INTO memory_fts(rowid, summary) VALUES (new.rowid, new.summary);
71
- END;
37
+ this.db.exec(`
38
+ CREATE TABLE IF NOT EXISTS long_term_memory (
39
+ id TEXT PRIMARY KEY,
40
+ category TEXT NOT NULL,
41
+ importance TEXT NOT NULL,
42
+ summary TEXT NOT NULL,
43
+ details TEXT,
44
+ hash TEXT NOT NULL UNIQUE,
45
+ source TEXT,
46
+ created_at TEXT NOT NULL,
47
+ updated_at TEXT NOT NULL,
48
+ last_accessed_at TEXT,
49
+ access_count INTEGER DEFAULT 0,
50
+ version INTEGER DEFAULT 1,
51
+ archived INTEGER DEFAULT 0
52
+ );
53
+
54
+ CREATE INDEX IF NOT EXISTS idx_memory_category ON long_term_memory(category);
55
+ CREATE INDEX IF NOT EXISTS idx_memory_importance ON long_term_memory(importance);
56
+ CREATE INDEX IF NOT EXISTS idx_memory_archived ON long_term_memory(archived);
57
+
58
+ -- FTS5 Virtual Table for semantic-like keyword search
59
+ CREATE VIRTUAL TABLE IF NOT EXISTS memory_fts USING fts5(summary, content='long_term_memory', content_rowid='rowid');
60
+
61
+ -- Triggers to sync FTS
62
+ CREATE TRIGGER IF NOT EXISTS memory_ai AFTER INSERT ON long_term_memory BEGIN
63
+ INSERT INTO memory_fts(rowid, summary) VALUES (new.rowid, new.summary);
64
+ END;
65
+ CREATE TRIGGER IF NOT EXISTS memory_ad AFTER DELETE ON long_term_memory BEGIN
66
+ INSERT INTO memory_fts(memory_fts, rowid, summary) VALUES('delete', old.rowid, old.summary);
67
+ END;
68
+ CREATE TRIGGER IF NOT EXISTS memory_au AFTER UPDATE ON long_term_memory BEGIN
69
+ INSERT INTO memory_fts(memory_fts, rowid, summary) VALUES('delete', old.rowid, old.summary);
70
+ INSERT INTO memory_fts(rowid, summary) VALUES (new.rowid, new.summary);
71
+ END;
72
72
  `);
73
73
  }
74
74
  async save(record) {
@@ -84,20 +84,20 @@ export class SatiRepository {
84
84
  version: 1,
85
85
  archived: false
86
86
  };
87
- const stmt = this.db.prepare(`
88
- INSERT INTO long_term_memory (
89
- id, category, importance, summary, details, hash, source,
90
- created_at, updated_at, last_accessed_at, access_count, version, archived
91
- ) VALUES (
92
- @id, @category, @importance, @summary, @details, @hash, @source,
93
- @created_at, @updated_at, @last_accessed_at, @access_count, @version, @archived
94
- )
95
- ON CONFLICT(hash) DO UPDATE SET
96
- importance = excluded.importance,
97
- access_count = long_term_memory.access_count + 1,
98
- last_accessed_at = excluded.updated_at,
99
- updated_at = excluded.updated_at,
100
- details = excluded.details
87
+ const stmt = this.db.prepare(`
88
+ INSERT INTO long_term_memory (
89
+ id, category, importance, summary, details, hash, source,
90
+ created_at, updated_at, last_accessed_at, access_count, version, archived
91
+ ) VALUES (
92
+ @id, @category, @importance, @summary, @details, @hash, @source,
93
+ @created_at, @updated_at, @last_accessed_at, @access_count, @version, @archived
94
+ )
95
+ ON CONFLICT(hash) DO UPDATE SET
96
+ importance = excluded.importance,
97
+ access_count = long_term_memory.access_count + 1,
98
+ last_accessed_at = excluded.updated_at,
99
+ updated_at = excluded.updated_at,
100
+ details = excluded.details
101
101
  `);
102
102
  // SQLite expects 0/1 for boolean and NULL for undefined
103
103
  const params = {
@@ -170,19 +170,19 @@ export class SatiRepository {
170
170
  getFallbackMemories(limit) {
171
171
  if (!this.db)
172
172
  return [];
173
- const stmt = this.db.prepare(`
174
- SELECT * FROM long_term_memory
175
- WHERE archived = 0
176
- ORDER BY
177
- CASE importance
178
- WHEN 'critical' THEN 1
179
- WHEN 'high' THEN 2
180
- WHEN 'medium' THEN 3
181
- WHEN 'low' THEN 4
182
- END,
183
- access_count DESC,
184
- created_at DESC
185
- LIMIT ?
173
+ const stmt = this.db.prepare(`
174
+ SELECT * FROM long_term_memory
175
+ WHERE archived = 0
176
+ ORDER BY
177
+ CASE importance
178
+ WHEN 'critical' THEN 1
179
+ WHEN 'high' THEN 2
180
+ WHEN 'medium' THEN 3
181
+ WHEN 'low' THEN 4
182
+ END,
183
+ access_count DESC,
184
+ created_at DESC
185
+ LIMIT ?
186
186
  `);
187
187
  const rows = stmt.all(limit);
188
188
  return rows.map(this.mapRowToRecord);
@@ -49,7 +49,7 @@ export class Oracle {
49
49
  throw new ProviderError(this.config.llm.provider || 'unknown', err, "Oracle initialization failed");
50
50
  }
51
51
  }
52
- async chat(message, extraUsage) {
52
+ async chat(message, extraUsage, isTelephonist) {
53
53
  if (!this.provider) {
54
54
  throw new Error("Oracle not initialized. Call initialize() first.");
55
55
  }
@@ -61,8 +61,8 @@ export class Oracle {
61
61
  const userMessage = new HumanMessage(message);
62
62
  // Inject provider/model metadata for persistence
63
63
  userMessage.provider_metadata = {
64
- provider: this.config.llm.provider,
65
- model: this.config.llm.model
64
+ provider: isTelephonist ? this.config.audio?.provider : this.config.llm.provider,
65
+ model: isTelephonist ? this.config.audio?.model : this.config.llm.model
66
66
  };
67
67
  // Attach extra usage (e.g. from Audio) to the user message to be persisted
68
68
  if (extraUsage) {
@@ -38,14 +38,24 @@ export class ProviderFactory {
38
38
  model = new ChatOpenAI({
39
39
  modelName: config.model,
40
40
  temperature: config.temperature,
41
- apiKey: config.api_key, // LangChain will also check process.env.OPENAI_API_KEY
41
+ apiKey: process.env.OPENAI_API_KEY || config.api_key, // Check env var first, then config
42
42
  });
43
43
  break;
44
44
  case 'anthropic':
45
45
  model = new ChatAnthropic({
46
46
  modelName: config.model,
47
47
  temperature: config.temperature,
48
- apiKey: config.api_key,
48
+ apiKey: process.env.ANTHROPIC_API_KEY || config.api_key, // Check env var first, then config
49
+ });
50
+ break;
51
+ case 'openrouter':
52
+ model = new ChatOpenAI({
53
+ modelName: config.model,
54
+ temperature: config.temperature,
55
+ apiKey: process.env.OPENROUTER_API_KEY || config.api_key, // Check env var first, then config
56
+ configuration: {
57
+ baseURL: config.base_url || 'https://openrouter.ai/api/v1'
58
+ }
49
59
  });
50
60
  break;
51
61
  case 'ollama':
@@ -60,7 +70,7 @@ export class ProviderFactory {
60
70
  model = new ChatGoogleGenerativeAI({
61
71
  model: config.model,
62
72
  temperature: config.temperature,
63
- apiKey: config.api_key
73
+ apiKey: process.env.GOOGLE_API_KEY || config.api_key // Check env var first, then config
64
74
  });
65
75
  break;
66
76
  default:
@@ -99,7 +109,7 @@ export class ProviderFactory {
99
109
  suggestion = `Model '${config.model}' may not be available. Check provider docs.`;
100
110
  }
101
111
  else if (msg.includes("unsupported provider")) {
102
- suggestion = "Edit your config file to use a supported provider (openai, anthropic, ollama, gemini).";
112
+ suggestion = "Edit your config file to use a supported provider (openai, anthropic, openrouter, ollama, gemini).";
103
113
  }
104
114
  throw new ProviderError(config.provider, error, suggestion);
105
115
  }
@@ -5,66 +5,60 @@ import { ConfigManager } from "../../config/manager.js";
5
5
  export const ConfigQueryTool = tool(async ({ key }) => {
6
6
  try {
7
7
  const configManager = ConfigManager.getInstance();
8
- // Load config if not already loaded
9
8
  await configManager.load();
10
9
  const config = configManager.get();
11
10
  if (key) {
12
- // Return specific configuration value
13
- const value = config[key];
11
+ // Suporta busca por chave aninhada, ex: 'llm.model' ou 'channels.telegram.enabled'
12
+ const value = key.split('.').reduce((obj, k) => (obj ? obj[k] : undefined), config);
14
13
  return JSON.stringify({ [key]: value });
15
14
  }
16
15
  else {
17
- // Return all configuration values
18
16
  return JSON.stringify(config);
19
17
  }
20
18
  }
21
19
  catch (error) {
22
- console.error("Error in ConfigQueryTool:", error);
20
+ // Nunca usar console.log, mas manter para debug local
23
21
  return JSON.stringify({ error: "Failed to query configuration" });
24
22
  }
25
23
  }, {
26
- name: "config_query",
27
- description: "Queries current configuration values. Accepts an optional 'key' parameter to get a specific configuration value, or no parameter to get all configuration values.",
24
+ name: "morpheus_config_query",
25
+ description: "Queries current configuration values. Accepts an optional 'key' parameter (dot notation supported, e.g. 'llm.model') to get a specific configuration value, or no parameter to get all configuration values.",
28
26
  schema: z.object({
29
27
  key: z.string().optional(),
30
28
  }),
31
29
  });
32
- // Tool for updating configuration values
30
+ // Tool for updating configuration values (suporta objetos aninhados via dot notation)
31
+ function setNestedValue(obj, path, value) {
32
+ const keys = path.split('.');
33
+ let curr = obj;
34
+ for (let i = 0; i < keys.length - 1; i++) {
35
+ if (!curr[keys[i]] || typeof curr[keys[i]] !== 'object') {
36
+ curr[keys[i]] = {};
37
+ }
38
+ curr = curr[keys[i]];
39
+ }
40
+ curr[keys[keys.length - 1]] = value;
41
+ }
33
42
  export const ConfigUpdateTool = tool(async ({ updates }) => {
34
43
  try {
35
44
  const configManager = ConfigManager.getInstance();
36
- // Load current config
37
45
  await configManager.load();
38
46
  const currentConfig = configManager.get();
39
- // Create new config with updates
40
- const newConfig = { ...currentConfig, ...updates };
41
- // Save the updated config
47
+ // Suporta updates com dot notation para campos aninhados
48
+ const newConfig = { ...currentConfig };
49
+ for (const key in updates) {
50
+ setNestedValue(newConfig, key, updates[key]);
51
+ }
42
52
  await configManager.save(newConfig);
43
53
  return JSON.stringify({ success: true, message: "Configuration updated successfully" });
44
54
  }
45
55
  catch (error) {
46
- console.error("Error in ConfigUpdateTool:", error);
47
56
  return JSON.stringify({ error: `Failed to update configuration: ${error.message}` });
48
57
  }
49
58
  }, {
50
- name: "config_update",
51
- description: "Updates configuration values with validation. Accepts an 'updates' object containing key-value pairs to update.",
59
+ name: "morpheus_config_update",
60
+ description: "Updates configuration values with validation. Accepts an 'updates' object containing key-value pairs to update. Supports dot notation for nested fields (e.g. 'llm.model').",
52
61
  schema: z.object({
53
- updates: z.object({
54
- // Define common config properties that might be updated
55
- // Using optional fields to allow flexible updates
56
- "llm.provider": z.string().optional(),
57
- "llm.model": z.string().optional(),
58
- "llm.temperature": z.number().optional(),
59
- "llm.api_key": z.string().optional(),
60
- "ui.enabled": z.boolean().optional(),
61
- "ui.port": z.number().optional(),
62
- "logging.enabled": z.boolean().optional(),
63
- "logging.level": z.enum(['debug', 'info', 'warn', 'error']).optional(),
64
- "audio.enabled": z.boolean().optional(),
65
- "audio.provider": z.string().optional(),
66
- "memory.limit": z.number().optional(),
67
- // Add more specific fields as needed, or use a catch-all for other properties
68
- }).passthrough(), // Allow additional properties not explicitly defined
62
+ updates: z.object({}).passthrough(),
69
63
  }),
70
64
  });
@@ -10,6 +10,7 @@ export const DEFAULT_CONFIG = {
10
10
  },
11
11
  audio: {
12
12
  provider: 'google',
13
+ model: 'gemini-2.5-flash-lite',
13
14
  enabled: true,
14
15
  maxDurationSeconds: 300,
15
16
  supportedMimeTypes: ['audio/ogg', 'audio/mp3', 'audio/mpeg', 'audio/wav'],
@@ -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}