@realtimex/realtimex-alchemy 1.0.29 → 1.0.31
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/CHANGELOG.md +18 -0
- package/dist/api/index.js +36 -0
- package/dist/api/services/AlchemistService.js +82 -7
- package/dist/api/services/PersonaService.js +126 -0
- package/dist/api/services/SDKService.js +31 -11
- package/dist/assets/index-C8fnSmzc.css +1 -0
- package/dist/assets/index-Chr0bt8t.js +124 -0
- package/dist/index.html +2 -2
- package/package.json +3 -3
- package/dist/assets/index-BTK1bjIq.css +0 -1
- package/dist/assets/index-DsHssgbI.js +0 -124
package/dist/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.0.31] - 2026-01-24
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- **Database**: Dropped legacy embedding tables (`embedding_jobs`, `signal_embeddings`) and functions; migrated fully to RealTimeX SDK vector storage.
|
|
12
|
+
- **UI**: Removed `HighConfidenceIndicator` from Signal Cards to reduce visual clutter.
|
|
13
|
+
- **Maintenance**: Reduced console log noise in API and Alchemist Engine for cleaner debugging.
|
|
14
|
+
|
|
15
|
+
## [1.0.30] - 2026-01-24
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- **Active Learning**: Introduced `PersonaService` to automatically analyze user interactions (Boosts, Dismissals) and build a dynamic "User Persona" (Interests & Anti-patterns) for personalized content filtering.
|
|
19
|
+
- **Interactions**: Added "Boost" (Strong Interest) and "Dismiss" (Not Interested) actions to Signals, providing explicit feedback loops for the AI.
|
|
20
|
+
- **Notes**: Users can now attach private notes to any signal for personal knowledge management.
|
|
21
|
+
- **Database**: Added `user_persona` table and new signal columns (`is_boosted`, `is_dismissed`, `user_notes`) to support active learning.
|
|
22
|
+
|
|
23
|
+
### Improved
|
|
24
|
+
- **SDK**: Updated `@realtimex/sdk` to v1.1.3 for enhanced stability.
|
|
25
|
+
|
|
8
26
|
## [1.0.29] - 2026-01-23
|
|
9
27
|
|
|
10
28
|
### Added
|
package/dist/api/index.js
CHANGED
|
@@ -10,6 +10,7 @@ import { EventService } from './services/EventService.js';
|
|
|
10
10
|
import { SupabaseService } from './services/SupabaseService.js';
|
|
11
11
|
import { BrowserPathDetector } from './utils/BrowserPathDetector.js';
|
|
12
12
|
import { ProcessingEventService } from './services/ProcessingEventService.js';
|
|
13
|
+
import { SDKService } from './services/SDKService.js';
|
|
13
14
|
import fs from 'fs';
|
|
14
15
|
const __filename = fileURLToPath(import.meta.url);
|
|
15
16
|
const __dirname = path.dirname(__filename);
|
|
@@ -214,6 +215,41 @@ app.post('/api/llm/test', async (req, res) => {
|
|
|
214
215
|
res.status(500).json({ success: false, message: error.message });
|
|
215
216
|
}
|
|
216
217
|
});
|
|
218
|
+
// Proxy: Get Chat Providers
|
|
219
|
+
app.get('/api/sdk/providers/chat', async (req, res) => {
|
|
220
|
+
try {
|
|
221
|
+
if (!await SDKService.isAvailable()) {
|
|
222
|
+
console.warn('[API] SDK not available for chat providers');
|
|
223
|
+
return res.json({ success: false, message: 'SDK not available' });
|
|
224
|
+
}
|
|
225
|
+
// @ts-ignore - Dev Mode types
|
|
226
|
+
const sdk = SDKService.getSDK();
|
|
227
|
+
// @ts-ignore - Dev Mode types
|
|
228
|
+
const { providers } = await sdk.llm.chatProviders();
|
|
229
|
+
res.json({ success: true, providers });
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
console.error('[API] Failed to fetch chat providers:', error.message);
|
|
233
|
+
res.status(500).json({ success: false, message: error.message });
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
// Proxy: Get Embed Providers
|
|
237
|
+
app.get('/api/sdk/providers/embed', async (req, res) => {
|
|
238
|
+
try {
|
|
239
|
+
if (!await SDKService.isAvailable()) {
|
|
240
|
+
return res.json({ success: false, message: 'SDK not available' });
|
|
241
|
+
}
|
|
242
|
+
// @ts-ignore - Dev Mode types
|
|
243
|
+
const sdk = SDKService.getSDK();
|
|
244
|
+
// @ts-ignore - Dev Mode types
|
|
245
|
+
const { providers } = await sdk.llm.embedProviders();
|
|
246
|
+
res.json({ success: true, providers });
|
|
247
|
+
}
|
|
248
|
+
catch (error) {
|
|
249
|
+
console.error('[API] Failed to fetch embed providers:', error.message);
|
|
250
|
+
res.status(500).json({ success: false, message: error.message });
|
|
251
|
+
}
|
|
252
|
+
});
|
|
217
253
|
// Unified Static Assets Serving
|
|
218
254
|
const staticPath = process.env.ELECTRON_STATIC_PATH || path.join(__dirname, '..', '..', 'dist');
|
|
219
255
|
if (fs.existsSync(staticPath)) {
|
|
@@ -13,9 +13,76 @@ export class AlchemistService {
|
|
|
13
13
|
async process(entries, settings, supabase, userId, syncStartTime) {
|
|
14
14
|
if (!entries || entries.length === 0)
|
|
15
15
|
return;
|
|
16
|
+
// 0. Fetch Learning Context (Active Learning: Persona + Short-term)
|
|
17
|
+
console.log('[AlchemistService] Fetching learning context...');
|
|
18
|
+
// Fetch Blacklist
|
|
19
|
+
const { data: settingsData } = await supabase
|
|
20
|
+
.from('alchemy_settings')
|
|
21
|
+
.select('blacklist_domains')
|
|
22
|
+
.eq('user_id', userId)
|
|
23
|
+
.single();
|
|
24
|
+
const blacklist = (settingsData?.blacklist_domains || []);
|
|
25
|
+
// A. Fetch User Persona (Long-term Memory)
|
|
26
|
+
const { data: persona } = await supabase
|
|
27
|
+
.from('user_persona')
|
|
28
|
+
.select('*')
|
|
29
|
+
.eq('user_id', userId)
|
|
30
|
+
.single();
|
|
31
|
+
// B. Fetch Recent Explicit Directives (Short-term / High Priority)
|
|
32
|
+
// User Notes (Last 5)
|
|
33
|
+
const { data: userNotes } = await supabase
|
|
34
|
+
.from('signals')
|
|
35
|
+
.select('title, user_notes')
|
|
36
|
+
.eq('user_id', userId)
|
|
37
|
+
.not('user_notes', 'is', null)
|
|
38
|
+
.order('updated_at', { ascending: false })
|
|
39
|
+
.limit(5);
|
|
40
|
+
// Recent Boosts (Last 5) - Immediate Drift
|
|
41
|
+
const { data: recentBoosts } = await supabase
|
|
42
|
+
.from('signals')
|
|
43
|
+
.select('title, summary')
|
|
44
|
+
.eq('user_id', userId)
|
|
45
|
+
.eq('is_boosted', true)
|
|
46
|
+
.order('created_at', { ascending: false })
|
|
47
|
+
.limit(5);
|
|
48
|
+
// Filter entries based on blacklist
|
|
49
|
+
const allowedEntries = entries.filter(entry => {
|
|
50
|
+
try {
|
|
51
|
+
const domain = new URL(entry.url).hostname;
|
|
52
|
+
const isBlacklisted = blacklist.some(b => domain.includes(b));
|
|
53
|
+
if (isBlacklisted) {
|
|
54
|
+
console.log(`[AlchemistService] Skipped blacklisted domain: ${domain}`);
|
|
55
|
+
}
|
|
56
|
+
return !isBlacklisted;
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
if (allowedEntries.length === 0) {
|
|
63
|
+
console.log('[AlchemistService] No entries remaining after blacklist filtering.');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
// Prepare Learning Context String
|
|
67
|
+
let learningContext = "";
|
|
68
|
+
// 1. Long-term Persona (Base Layer)
|
|
69
|
+
if (persona) {
|
|
70
|
+
learningContext += `\nUSER PERSONA (Long-term Profile):\n`;
|
|
71
|
+
learningContext += `Interests: ${persona.interest_summary}\n`;
|
|
72
|
+
learningContext += `Dislikes: ${persona.anti_patterns}\n`;
|
|
73
|
+
}
|
|
74
|
+
// 2. Short-term / Explicit (Overlay Layer)
|
|
75
|
+
if (recentBoosts && recentBoosts.length > 0) {
|
|
76
|
+
learningContext += `\nIMMEDIATE PRIORITIES (Recent Boosts):\n`;
|
|
77
|
+
recentBoosts.forEach(b => learningContext += `- ${b.title}: ${b.summary}\n`);
|
|
78
|
+
}
|
|
79
|
+
if (userNotes && userNotes.length > 0) {
|
|
80
|
+
learningContext += `\nUSER DIRECTIVES (Explicit Notes - Override Rules):\n`;
|
|
81
|
+
userNotes.forEach(n => learningContext += `- Regarding "${n.title}": "${n.user_notes}"\n`);
|
|
82
|
+
}
|
|
16
83
|
// Track stats for completion event
|
|
17
84
|
const stats = {
|
|
18
|
-
total:
|
|
85
|
+
total: allowedEntries.length,
|
|
19
86
|
signals: 0,
|
|
20
87
|
skipped: 0,
|
|
21
88
|
errors: 0
|
|
@@ -24,7 +91,7 @@ export class AlchemistService {
|
|
|
24
91
|
provider: settings.llm_provider || 'realtimexai',
|
|
25
92
|
model: settings.llm_model || 'gpt-4o'
|
|
26
93
|
});
|
|
27
|
-
for (const entry of
|
|
94
|
+
for (const entry of allowedEntries) {
|
|
28
95
|
// Emit: Reading
|
|
29
96
|
await this.processingEvents.log({
|
|
30
97
|
eventType: 'analysis',
|
|
@@ -61,7 +128,7 @@ export class AlchemistService {
|
|
|
61
128
|
userId
|
|
62
129
|
}, supabase);
|
|
63
130
|
// 3. LLM Analysis
|
|
64
|
-
const response = await this.analyzeContent(content, entry.url, settings);
|
|
131
|
+
const response = await this.analyzeContent(content, entry.url, settings, learningContext);
|
|
65
132
|
const duration = Date.now() - startAnalysis;
|
|
66
133
|
if (response.relevant) {
|
|
67
134
|
// Emit: Signal Found
|
|
@@ -149,24 +216,32 @@ export class AlchemistService {
|
|
|
149
216
|
},
|
|
150
217
|
userId
|
|
151
218
|
}, supabase);
|
|
219
|
+
// 6. Trigger Background Persona Consolidation (don't await)
|
|
220
|
+
import('./PersonaService.js').then(({ personaService }) => {
|
|
221
|
+
personaService.consolidatePersona(userId, supabase).catch(err => {
|
|
222
|
+
console.error('[AlchemistService] Background persona update failed:', err);
|
|
223
|
+
});
|
|
224
|
+
});
|
|
152
225
|
}
|
|
153
|
-
async analyzeContent(content, url, settings) {
|
|
226
|
+
async analyzeContent(content, url, settings, learningContext = "") {
|
|
154
227
|
const sdk = SDKService.getSDK();
|
|
155
228
|
if (!sdk) {
|
|
156
229
|
throw new Error('RealTimeX SDK not available');
|
|
157
230
|
}
|
|
158
231
|
const prompt = `
|
|
159
232
|
Act as "The Alchemist", a high-level intelligence analyst.
|
|
160
|
-
Analyze the following article value.
|
|
233
|
+
Analyze the following article value based on the content and the User's Interests.
|
|
234
|
+
|
|
235
|
+
${learningContext}
|
|
161
236
|
|
|
162
237
|
Input:
|
|
163
238
|
URL: ${url}
|
|
164
239
|
Content: ${content}
|
|
165
240
|
|
|
166
241
|
CRITICAL SCORING:
|
|
167
|
-
High Score (80-100): Original research, concrete data points, contrarian insights, deep technical details, official documentation.
|
|
242
|
+
High Score (80-100): Original research, concrete data points, contrarian insights, deep technical details, official documentation. MATCHES USER INTERESTS/BOOSTED TOPICS.
|
|
168
243
|
Medium Score (50-79): Decent summaries, useful aggregate news, tutorials, reference material, software documentation.
|
|
169
|
-
Low Score (0-49): Marketing fluff, SEO clickbait, generic listicles, navigation menus only, login pages,
|
|
244
|
+
Low Score (0-49): Marketing fluff, SEO clickbait, generic listicles, navigation menus only, login pages, site footers, OR MATCHES USER DISLIKES (Dismissed topics).
|
|
170
245
|
|
|
171
246
|
Return STRICT JSON:
|
|
172
247
|
{
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { SDKService } from './SDKService.js';
|
|
2
|
+
export class PersonaService {
|
|
3
|
+
static instance;
|
|
4
|
+
constructor() { }
|
|
5
|
+
static getInstance() {
|
|
6
|
+
if (!PersonaService.instance) {
|
|
7
|
+
PersonaService.instance = new PersonaService();
|
|
8
|
+
}
|
|
9
|
+
return PersonaService.instance;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Consolidates recent user interactions into a structured persona.
|
|
13
|
+
* This describes what the user likes and dislikes based on their feedback.
|
|
14
|
+
*/
|
|
15
|
+
async consolidatePersona(userId, supabase) {
|
|
16
|
+
console.log('[PersonaService] Consolidating user persona...');
|
|
17
|
+
// 1. Fetch recent interactions (Last 50)
|
|
18
|
+
// Favorites & Boosts (Positive)
|
|
19
|
+
const { data: positives } = await supabase
|
|
20
|
+
.from('signals')
|
|
21
|
+
.select('title, summary, category, is_boosted, is_favorite, user_notes')
|
|
22
|
+
.or('is_boosted.eq.true,is_favorite.eq.true')
|
|
23
|
+
.eq('user_id', userId)
|
|
24
|
+
.order('updated_at', { ascending: false })
|
|
25
|
+
.limit(50);
|
|
26
|
+
// Dismissals (Negative)
|
|
27
|
+
const { data: negatives } = await supabase
|
|
28
|
+
.from('signals')
|
|
29
|
+
.select('title, summary, category')
|
|
30
|
+
.eq('is_dismissed', true)
|
|
31
|
+
.eq('user_id', userId)
|
|
32
|
+
.order('updated_at', { ascending: false })
|
|
33
|
+
.limit(50);
|
|
34
|
+
if ((!positives || positives.length === 0) && (!negatives || negatives.length === 0)) {
|
|
35
|
+
console.log('[PersonaService] No interactions to consolidate.');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
// 2. Fetch existing persona to update it (Incremental learning)
|
|
39
|
+
const { data: existingPersona } = await supabase
|
|
40
|
+
.from('user_persona')
|
|
41
|
+
.select('*')
|
|
42
|
+
.eq('user_id', userId)
|
|
43
|
+
.single();
|
|
44
|
+
// 3. Construct LLM Prompt
|
|
45
|
+
const prompt = `
|
|
46
|
+
Act as an expert profiler. Analyze the User's feedback history to build a technical "User Persona".
|
|
47
|
+
|
|
48
|
+
CURRENT PERSONA (Previous State):
|
|
49
|
+
Interests: ${existingPersona?.interest_summary || "None"}
|
|
50
|
+
Dislikes: ${existingPersona?.anti_patterns || "None"}
|
|
51
|
+
|
|
52
|
+
RECENT POSITIVE INTERACTIONS (Favorites/Boosts/Notes):
|
|
53
|
+
${positives?.map(p => `- ${p.title} (${p.category}) ${p.user_notes ? `[NOTE: ${p.user_notes}]` : ''}`).join('\n') || "None"}
|
|
54
|
+
|
|
55
|
+
RECENT NEGATIVE INTERACTIONS (Dismissals):
|
|
56
|
+
${negatives?.map(n => `- ${n.title} (${n.category})`).join('\n') || "None"}
|
|
57
|
+
|
|
58
|
+
TASK:
|
|
59
|
+
Synthesize this data into a concise, high-level summary.
|
|
60
|
+
1. "interest_summary": 2-3 sentences describing the user's specific technical interests (e.g., "Focuses on React performance and Rust backend. Likes in-depth tutorials, avoids surface-level news.").
|
|
61
|
+
2. "anti_patterns": 1-2 sentences describing what they avoid (e.g., "Dislikes marketing fluff, Web3 hype, and generic product announcements.").
|
|
62
|
+
|
|
63
|
+
Return strictly JSON:
|
|
64
|
+
{
|
|
65
|
+
"interest_summary": "...",
|
|
66
|
+
"anti_patterns": "..."
|
|
67
|
+
}
|
|
68
|
+
`;
|
|
69
|
+
// 4. Call LLM
|
|
70
|
+
const sdk = SDKService.getSDK();
|
|
71
|
+
if (!sdk) {
|
|
72
|
+
console.error('[PersonaService] SDK not available for persona consolidation.');
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// We use a cheap/fast model for this if available, or just the default
|
|
76
|
+
try {
|
|
77
|
+
const response = await sdk.llm.chat([
|
|
78
|
+
{ role: 'system', content: 'You are a precise analyzer. Return ONLY valid JSON.' },
|
|
79
|
+
{ role: 'user', content: prompt }
|
|
80
|
+
], {
|
|
81
|
+
// Use default model from settings or allow override?
|
|
82
|
+
// For now, we rely on the SDK's default or configured model.
|
|
83
|
+
// ideally we fetch settings here too, but for simplicity we assume default env var or settings are handled in SDKService/Alchemist
|
|
84
|
+
});
|
|
85
|
+
const content = response.response?.content || '{}';
|
|
86
|
+
const parsed = this.parseJSON(content);
|
|
87
|
+
if (parsed.interest_summary && parsed.anti_patterns) {
|
|
88
|
+
// 5. Update Database
|
|
89
|
+
const { error } = await supabase
|
|
90
|
+
.from('user_persona')
|
|
91
|
+
.upsert({
|
|
92
|
+
user_id: userId,
|
|
93
|
+
interest_summary: parsed.interest_summary,
|
|
94
|
+
anti_patterns: parsed.anti_patterns,
|
|
95
|
+
last_updated_at: new Date().toISOString()
|
|
96
|
+
}, { onConflict: 'user_id' });
|
|
97
|
+
if (error) {
|
|
98
|
+
console.error('[PersonaService] Failed to save persona:', error);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
console.log('[PersonaService] Persona updated successfully.');
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
console.error('[PersonaService] LLM error:', err);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
parseJSON(input) {
|
|
110
|
+
try {
|
|
111
|
+
const jsonMatch = input.match(/\{[\s\S]*\}/);
|
|
112
|
+
const jsonStr = jsonMatch ? jsonMatch[0] : input;
|
|
113
|
+
const cleaned = jsonStr
|
|
114
|
+
.replace(/<\|[\s\S]*?\|>/g, '') // remove think blocks
|
|
115
|
+
.replace(/```json/g, '')
|
|
116
|
+
.replace(/```/g, '')
|
|
117
|
+
.trim();
|
|
118
|
+
return JSON.parse(cleaned);
|
|
119
|
+
}
|
|
120
|
+
catch (e) {
|
|
121
|
+
console.error('[PersonaService] JSON Parse Error:', e);
|
|
122
|
+
return {};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
export const personaService = PersonaService.getInstance();
|
|
@@ -15,18 +15,30 @@ export class SDKService {
|
|
|
15
15
|
this.initAttempted = true;
|
|
16
16
|
try {
|
|
17
17
|
this.instance = new RealtimeXSDK({
|
|
18
|
+
realtimex: {
|
|
19
|
+
// @ts-ignore - Dev Mode feature
|
|
20
|
+
apiKey: 'SXKX93J-QSWMB04-K9E0GRE-J5DA8J0'
|
|
21
|
+
},
|
|
18
22
|
permissions: [
|
|
19
|
-
//
|
|
20
|
-
'
|
|
21
|
-
'
|
|
22
|
-
//
|
|
23
|
-
'
|
|
24
|
-
//
|
|
25
|
-
'
|
|
26
|
-
'
|
|
23
|
+
'api.agents', // List agents
|
|
24
|
+
'api.workspaces', // List workspaces
|
|
25
|
+
'api.threads', // List threads
|
|
26
|
+
'webhook.trigger', // Trigger agents
|
|
27
|
+
'activities.read', // Read activities
|
|
28
|
+
'activities.write', // Write activities
|
|
29
|
+
'llm.chat', // Chat completion
|
|
30
|
+
'llm.embed', // Generate embeddings
|
|
31
|
+
'llm.providers', // List LLM providers (chat, embed)
|
|
32
|
+
'vectors.read', // Query vectors
|
|
33
|
+
'vectors.write', // Store vectors
|
|
27
34
|
],
|
|
28
35
|
});
|
|
29
36
|
console.log('[SDKService] RealTimeX SDK initialized successfully');
|
|
37
|
+
// Verify connection with Desktop App
|
|
38
|
+
// @ts-ignore - Dev Mode feature
|
|
39
|
+
this.instance.ping()
|
|
40
|
+
.then((status) => console.log('[SDKService] Desktop App Connection:', status))
|
|
41
|
+
.catch((err) => console.warn('[SDKService] Desktop App Connection failed:', err.message));
|
|
30
42
|
}
|
|
31
43
|
catch (error) {
|
|
32
44
|
console.warn('[SDKService] Failed to initialize SDK:', error.message);
|
|
@@ -52,9 +64,17 @@ export class SDKService {
|
|
|
52
64
|
const sdk = this.getSDK();
|
|
53
65
|
if (!sdk)
|
|
54
66
|
return false;
|
|
55
|
-
// Try to
|
|
56
|
-
|
|
57
|
-
|
|
67
|
+
// Try to ping first (faster)
|
|
68
|
+
try {
|
|
69
|
+
// @ts-ignore - Dev Mode feature
|
|
70
|
+
await sdk.ping();
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
// Fallback to providers check if ping not available/fails
|
|
75
|
+
await sdk.llm.chatProviders();
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
58
78
|
}
|
|
59
79
|
catch (error) {
|
|
60
80
|
console.warn('[SDKService] SDK not available:', error);
|
|
@@ -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:Outfit,system-ui,sans-serif;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:JetBrains Mono,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{background-color:var(--bg);color:var(--fg);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:Outfit,system-ui,sans-serif}::-moz-selection{background-color:var(--selection-bg)}::selection{background-color:var(--selection-bg)}.glass{background-color:var(--glass-bg);border-radius:1rem;border-width:1px;border-color:var(--border);--tw-backdrop-blur: blur(24px);-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)}.glow-primary{box-shadow:0 0 20px var(--glow-color)}.custom-scrollbar::-webkit-scrollbar{width:6px}.custom-scrollbar::-webkit-scrollbar-track{background-color:transparent}.custom-scrollbar::-webkit-scrollbar-thumb{border-radius:9999px;background-color:var(--border)}.custom-scrollbar::-webkit-scrollbar-thumb:hover{background-color:#f7f8ff33}input:-webkit-autofill,input:-webkit-autofill:hover,input:-webkit-autofill:focus,input:-webkit-autofill:active{-webkit-box-shadow:0 0 0 1000px var(--surface) inset!important;-webkit-text-fill-color:var(--fg)!important;caret-color:var(--fg)!important}.scrollbar-on-hover::-webkit-scrollbar{width:6px;height:6px}.scrollbar-on-hover::-webkit-scrollbar-track{background-color:transparent}.scrollbar-on-hover::-webkit-scrollbar-thumb{background-color:transparent;-webkit-transition:background-color .2s;transition:background-color .2s}.scrollbar-on-hover:hover::-webkit-scrollbar-thumb{border-radius:9999px;background-color:var(--border)}.scrollbar-on-hover:hover::-webkit-scrollbar-thumb:hover{background-color:#f7f8ff33}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.visible{visibility:visible}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.-right-1{right:-.25rem}.-top-1{top:-.25rem}.bottom-6{bottom:1.5rem}.left-3{left:.75rem}.right-0{right:0}.right-2{right:.5rem}.right-3{right:.75rem}.right-6{right:1.5rem}.top-0{top:0}.top-1\/2{top:50%}.top-12{top:3rem}.top-2{top:.5rem}.top-3{top:.75rem}.z-0{z-index:0}.z-10{z-index:10}.z-40{z-index:40}.z-50{z-index:50}.z-\[100\]{z-index:100}.z-\[60\]{z-index:60}.z-\[70\]{z-index:70}.col-span-2{grid-column:span 2 / span 2}.m-4{margin:1rem}.-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-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-0{margin-left:0}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-4{margin-left:1rem}.ml-auto{margin-left:auto}.mr-0{margin-right:0}.mt-0{margin-top:0}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.mt-auto{margin-top:auto}.line-clamp-1{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.line-clamp-3{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3}.block{display:block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-2{height:.5rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-32{height:8rem}.h-4{height:1rem}.h-40{height:10rem}.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}.max-h-96{max-height:24rem}.max-h-\[600px\]{max-height:600px}.max-h-\[80vh\]{max-height:80vh}.max-h-\[90vh\]{max-height:90vh}.max-h-\[calc\(80vh-88px\)\]{max-height:calc(80vh - 88px)}.w-10{width:2.5rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-16{width:4rem}.w-2{width:.5rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.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-\[120px\]{width:120px}.w-\[450px\]{width:450px}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.w-screen{width:100vw}.min-w-0{min-width:0px}.min-w-\[20px\]{min-width:20px}.min-w-\[300px\]{min-width:300px}.min-w-\[40px\]{min-width:40px}.min-w-max{min-width:-moz-max-content;min-width:max-content}.max-w-2xl{max-width:42rem}.max-w-3xl{max-width:48rem}.max-w-4xl{max-width:56rem}.max-w-7xl{max-width:80rem}.max-w-\[240px\]{max-width:240px}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.flex-\[2\]{flex:2}.flex-shrink-0,.shrink-0{flex-shrink:0}.-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\/2{--tw-translate-x: 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))}.-rotate-90{--tw-rotate: -90deg;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))}.rotate-180{--tw-rotate: 180deg;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))}.scale-105{--tw-scale-x: 1.05;--tw-scale-y: 1.05;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 ping{75%,to{transform:scale(2);opacity:0}}.animate-ping{animation:ping 1s cubic-bezier(0,0,.2,1) infinite}@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}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.list-none{list-style-type:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.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-8{gap:2rem}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * 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-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * 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))}.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-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-3xl{border-radius:1.5rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-2{border-width:2px}.border-4{border-width:4px}.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-amber-500\/10{border-color:#f59e0b1a}.border-blue-400{--tw-border-opacity: 1;border-color:rgb(96 165 250 / var(--tw-border-opacity, 1))}.border-blue-400\/30{border-color:#60a5fa4d}.border-blue-500\/30{border-color:#3b82f64d}.border-border{border-color:var(--border)}.border-cyan-500\/30{border-color:#06b6d44d}.border-emerald-500\/20{border-color:#10b98133}.border-gray-400\/30{border-color:#9ca3af4d}.border-gray-500\/30{border-color:#6b72804d}.border-green-500\/20{border-color:#22c55e33}.border-green-500\/30{border-color:#22c55e4d}.border-orange-500\/20{border-color:#f9731633}.border-orange-500\/30{border-color:#f973164d}.border-primary{border-color:var(--primary)}.border-purple-500\/30{border-color:#a855f74d}.border-red-500\/20{border-color:#ef444433}.border-red-500\/30{border-color:#ef44444d}.border-teal-500\/30{border-color:#14b8a64d}.border-white\/10{border-color:#ffffff1a}.border-white\/30{border-color:#ffffff4d}.border-white\/5{border-color:#ffffff0d}.border-yellow-400\/30{border-color:#facc154d}.border-yellow-500\/20{border-color:#eab30833}.border-yellow-500\/30{border-color:#eab3084d}.border-t-primary{border-top-color:var(--primary)}.border-t-transparent{border-top-color:transparent}.border-t-white{--tw-border-opacity: 1;border-top-color:rgb(255 255 255 / var(--tw-border-opacity, 1))}.bg-accent{background-color:var(--accent)}.bg-amber-500\/5{background-color:#f59e0b0d}.bg-bg{background-color:var(--bg)}.bg-black\/20{background-color:#0003}.bg-black\/40{background-color:#0006}.bg-black\/50{background-color:#00000080}.bg-black\/60{background-color:#0009}.bg-blue-400\/20{background-color:#60a5fa33}.bg-blue-500\/10{background-color:#3b82f61a}.bg-blue-500\/20{background-color:#3b82f633}.bg-cyan-500\/20{background-color:#06b6d433}.bg-emerald-500\/10{background-color:#10b9811a}.bg-emerald-500\/20{background-color:#10b98133}.bg-emerald-500\/5{background-color:#10b9810d}.bg-gray-400\/20{background-color:#9ca3af33}.bg-gray-500\/20{background-color:#6b728033}.bg-green-500{--tw-bg-opacity: 1;background-color:rgb(34 197 94 / var(--tw-bg-opacity, 1))}.bg-green-500\/10{background-color:#22c55e1a}.bg-green-500\/20{background-color:#22c55e33}.bg-orange-400{--tw-bg-opacity: 1;background-color:rgb(251 146 60 / var(--tw-bg-opacity, 1))}.bg-orange-500{--tw-bg-opacity: 1;background-color:rgb(249 115 22 / var(--tw-bg-opacity, 1))}.bg-orange-500\/10{background-color:#f973161a}.bg-orange-500\/20{background-color:#f9731633}.bg-primary{background-color:var(--primary)}.bg-purple-500\/20{background-color:#a855f733}.bg-red-500\/10{background-color:#ef44441a}.bg-red-500\/20{background-color:#ef444433}.bg-success{background-color:var(--success)}.bg-surface{background-color:var(--surface)}.bg-teal-500\/20{background-color:#14b8a633}.bg-white\/5{background-color:#ffffff0d}.bg-yellow-400\/20{background-color:#facc1533}.bg-yellow-500\/10{background-color:#eab3081a}.bg-yellow-500\/5{background-color:#eab3080d}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.bg-gradient-to-t{background-image:linear-gradient(to top,var(--tw-gradient-stops))}.from-bg{--tw-gradient-from: var(--bg) var(--tw-gradient-from-position);--tw-gradient-to: rgb(255 255 255 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-orange-500{--tw-gradient-from: #f97316 var(--tw-gradient-from-position);--tw-gradient-to: rgb(249 115 22 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-primary{--tw-gradient-from: var(--primary) var(--tw-gradient-from-position);--tw-gradient-to: rgb(255 255 255 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.to-accent{--tw-gradient-to: var(--accent) var(--tw-gradient-to-position)}.to-red-500{--tw-gradient-to: #ef4444 var(--tw-gradient-to-position)}.to-red-600{--tw-gradient-to: #dc2626 var(--tw-gradient-to-position)}.fill-current{fill:currentColor}.object-cover{-o-object-fit:cover;object-fit:cover}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.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-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-12{padding-bottom:3rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pb-4{padding-bottom:1rem}.pl-10{padding-left:2.5rem}.pr-10{padding-right:2.5rem}.pr-4{padding-right:1rem}.pt-1{padding-top:.25rem}.pt-2{padding-top:.5rem}.pt-4{padding-top:1rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:JetBrains Mono,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-\[11px\]{font-size:11px}.text-\[9px\]{font-size:9px}.text-base{font-size:1rem;line-height:1.5rem}.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-black{font-weight:900}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.italic{font-style:italic}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.leading-tight{line-height:1.25}.tracking-\[0\.2em\]{letter-spacing:.2em}.tracking-\[0\.3em\]{letter-spacing:.3em}.tracking-\[0\.4em\]{letter-spacing:.4em}.tracking-tight{letter-spacing:-.025em}.tracking-tighter{letter-spacing:-.05em}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.tracking-widest{letter-spacing:.1em}.text-accent{color:var(--accent)}.text-amber-500{--tw-text-opacity: 1;color:rgb(245 158 11 / var(--tw-text-opacity, 1))}.text-blue-400{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.text-blue-500{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity, 1))}.text-current{color:currentColor}.text-cyan-400{--tw-text-opacity: 1;color:rgb(34 211 238 / var(--tw-text-opacity, 1))}.text-cyan-500{--tw-text-opacity: 1;color:rgb(6 182 212 / var(--tw-text-opacity, 1))}.text-emerald-500{--tw-text-opacity: 1;color:rgb(16 185 129 / var(--tw-text-opacity, 1))}.text-error{color:var(--error)}.text-fg{color:var(--fg)}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.text-green-400{--tw-text-opacity: 1;color:rgb(74 222 128 / var(--tw-text-opacity, 1))}.text-green-500{--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}.text-orange-400{--tw-text-opacity: 1;color:rgb(251 146 60 / var(--tw-text-opacity, 1))}.text-orange-500{--tw-text-opacity: 1;color:rgb(249 115 22 / var(--tw-text-opacity, 1))}.text-primary{color:var(--primary)}.text-purple-400{--tw-text-opacity: 1;color:rgb(192 132 252 / var(--tw-text-opacity, 1))}.text-purple-500{--tw-text-opacity: 1;color:rgb(168 85 247 / var(--tw-text-opacity, 1))}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.text-success{color:var(--success)}.text-teal-400{--tw-text-opacity: 1;color:rgb(45 212 191 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-yellow-400{--tw-text-opacity: 1;color:rgb(250 204 21 / var(--tw-text-opacity, 1))}.text-yellow-500{--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity, 1))}.underline{text-decoration-line:underline}.accent-primary{accent-color:var(--primary)}.opacity-0{opacity:0}.opacity-20{opacity:.2}.opacity-40{opacity:.4}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.opacity-75{opacity:.75}.opacity-80{opacity:.8}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px 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-\[0_0_15px_rgba\(239\,68\,68\,0\.1\)\]{--tw-shadow: 0 0 15px rgba(239,68,68,.1);--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)}.shadow-\[0_0_20px_rgba\(234\,179\,8\,0\.1\)\]{--tw-shadow: 0 0 20px rgba(234,179,8,.1);--tw-shadow-colored: 0 0 20px 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-inner{--tw-shadow: inset 0 2px 4px 0 rgb(0 0 0 / .05);--tw-shadow-colored: inset 0 2px 4px 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-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}.blur-3xl{--tw-blur: blur(64px);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)}.blur-md{--tw-blur: blur(12px);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)}.blur-xl{--tw-blur: blur(24px);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)}.grayscale{--tw-grayscale: grayscale(100%);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)}.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-md{--tw-backdrop-blur: blur(12px);-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)}.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-all{transition-property:all;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}.duration-500{transition-duration:.5s}:root{--bg: oklch(15% .02 280);--fg: oklch(98% .01 280);--primary: oklch(65% .25 280);--accent: oklch(85% .2 90);--surface: oklch(20% .02 280);--border: oklch(35% .03 280 / .6);--success: oklch(75% .15 150);--error: oklch(65% .2 25);--glass-bg: oklch(25% .03 280 / .4);--glow-color: oklch(65% .25 280 / .3);--selection-bg: oklch(65% .25 280 / .3);--border-hover: oklch(50% .15 280 / .8)}:root[data-theme=light]{--bg: oklch(96% .005 280);--fg: oklch(15% .02 280);--primary: oklch(50% .25 280);--accent: oklch(60% .2 50);--surface: oklch(100% 0 0);--border: oklch(75% .02 280 / .8);--success: oklch(45% .15 150);--error: oklch(50% .2 25);--glass-bg: oklch(100% 0 0 / .7);--glow-color: oklch(50% .25 280 / .2);--selection-bg: oklch(50% .25 280 / .25);--border-hover: oklch(60% .15 280 / .9)}@keyframes pulse-gold{0%{box-shadow:0 0 #fac70066;box-shadow:0 0 oklch(85% .2 90 / .4)}70%{box-shadow:0 0 0 10px #fac70000;box-shadow:0 0 0 10px oklch(85% .2 90 / 0)}to{box-shadow:0 0 #fac70000;box-shadow:0 0 oklch(85% .2 90 / 0)}}.animate-pulse-gold{animation:pulse-gold 2s infinite}h1,h2,h3,h4{letter-spacing:-.025em}.font-mono{font-family:JetBrains Mono,monospace}.before\:mr-2:before{content:var(--tw-content);margin-right:.5rem}.before\:text-primary:before{content:var(--tw-content);color:var(--primary)}.before\:content-\[\'•\'\]:before{--tw-content: "•";content:var(--tw-content)}.first\:mt-0:first-child{margin-top:0}.autofill\:bg-surface:-webkit-autofill{background-color:var(--surface)}.autofill\:bg-surface:autofill{background-color:var(--surface)}.autofill\:text-fg:-webkit-autofill{color:var(--fg)}.autofill\:text-fg:autofill{color:var(--fg)}.hover\:z-10:hover{z-index:10}.hover\:scale-105:hover{--tw-scale-x: 1.05;--tw-scale-y: 1.05;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))}.hover\:scale-\[1\.01\]:hover{--tw-scale-x: 1.01;--tw-scale-y: 1.01;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))}.hover\:scale-\[1\.02\]:hover{--tw-scale-x: 1.02;--tw-scale-y: 1.02;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))}.hover\:border-\[var\(--border-hover\)\]:hover{border-color:var(--border-hover)}.hover\:bg-black\/10:hover{background-color:#0000001a}.hover\:bg-blue-500\/20:hover{background-color:#3b82f633}.hover\:bg-error:hover{background-color:var(--error)}.hover\:bg-orange-500:hover{--tw-bg-opacity: 1;background-color:rgb(249 115 22 / var(--tw-bg-opacity, 1))}.hover\:bg-red-500\/20:hover{background-color:#ef444433}.hover\:bg-surface:hover{background-color:var(--surface)}.hover\:bg-white\/10:hover{background-color:#ffffff1a}.hover\:bg-white\/5:hover{background-color:#ffffff0d}.hover\:bg-yellow-500\/20:hover{background-color:#eab30833}.hover\:text-accent:hover{color:var(--accent)}.hover\:text-blue-400:hover{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.hover\:text-error:hover{color:var(--error)}.hover\:text-fg:hover{color:var(--fg)}.hover\:text-primary:hover{color:var(--primary)}.hover\:text-red-400:hover{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.hover\:text-white:hover{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.hover\:text-yellow-500:hover{--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity, 1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.focus\:border-\[var\(--border-hover\)\]:focus{border-color:var(--border-hover)}.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-green-500\/30:focus{--tw-ring-color: rgb(34 197 94 / .3)}.focus\:ring-red-500\/30:focus{--tw-ring-color: rgb(239 68 68 / .3)}.active\:scale-95:active{--tw-scale-x: .95;--tw-scale-y: .95;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))}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:grayscale:disabled{--tw-grayscale: grayscale(100%);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)}.disabled\:hover\:scale-100:hover:disabled{--tw-scale-x: 1;--tw-scale-y: 1;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))}.group:hover .group-hover\:block{display:block}.group\/btn:hover .group-hover\/btn\:translate-x-0\.5{--tw-translate-x: .125rem;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))}.group:hover .group-hover\:text-accent{color:var(--accent)}.group:hover .group-hover\:text-blue-400{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.group:hover .group-hover\:text-primary{color:var(--primary)}.group:hover .group-hover\:opacity-100{opacity:1}@media(min-width:640px){.sm\:h-12{height:3rem}.sm\:w-12{width:3rem}}@media(min-width:768px){.md\:w-2\/3{width:66.666667%}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media(min-width:1024px){.lg\:w-1\/2{width:50%}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}
|