@gravito/zenith 1.0.1 โ 1.1.1
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/CHANGELOG.md +25 -0
- package/ECOSYSTEM_EXPANSION_RFC.md +130 -0
- package/dist/bin.js +11945 -4241
- package/dist/client/assets/index-BSMp8oq_.js +436 -0
- package/dist/client/assets/index-BwxlHx-_.css +1 -0
- package/dist/client/index.html +2 -2
- package/dist/server/index.js +11945 -4241
- package/package.json +1 -1
- package/scripts/verify-throttle.ts +6 -2
- package/scripts/worker.ts +2 -1
- package/src/client/Layout.tsx +10 -0
- package/src/client/Sidebar.tsx +9 -0
- package/src/client/ThroughputChart.tsx +9 -0
- package/src/client/WorkerStatus.tsx +14 -3
- package/src/client/components/BrandIcons.tsx +30 -0
- package/src/client/components/ConfirmDialog.tsx +24 -0
- package/src/client/components/JobInspector.tsx +18 -0
- package/src/client/components/LogArchiveModal.tsx +51 -2
- package/src/client/components/NotificationBell.tsx +9 -0
- package/src/client/components/PageHeader.tsx +9 -0
- package/src/client/components/Toaster.tsx +10 -0
- package/src/client/components/UserProfileDropdown.tsx +9 -0
- package/src/client/contexts/AuthContext.tsx +12 -0
- package/src/client/contexts/NotificationContext.tsx +25 -0
- package/src/client/pages/LoginPage.tsx +9 -0
- package/src/client/pages/MetricsPage.tsx +9 -0
- package/src/client/pages/OverviewPage.tsx +9 -0
- package/src/client/pages/PulsePage.tsx +10 -0
- package/src/client/pages/QueuesPage.tsx +9 -0
- package/src/client/pages/SchedulesPage.tsx +9 -0
- package/src/client/pages/SettingsPage.tsx +9 -0
- package/src/client/pages/WorkersPage.tsx +10 -0
- package/src/client/utils.ts +9 -0
- package/src/server/config/ServerConfigManager.ts +87 -0
- package/src/server/index.ts +19 -18
- package/src/server/services/AlertService.ts +16 -3
- package/src/server/services/LogStreamProcessor.ts +93 -0
- package/src/server/services/MaintenanceScheduler.ts +78 -0
- package/src/server/services/PulseService.ts +12 -1
- package/src/server/services/QueueMetricsCollector.ts +138 -0
- package/src/server/services/QueueService.ts +29 -283
- package/src/shared/types.ts +126 -27
- package/vite.config.ts +1 -1
- package/DEMO.md +0 -156
- package/dist/client/assets/index-C332gZ-J.css +0 -1
- package/dist/client/assets/index-D4HibwTK.js +0 -436
package/src/shared/types.ts
CHANGED
|
@@ -1,76 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metrics representing CPU usage for a specific node/process.
|
|
3
|
+
*
|
|
4
|
+
* @public
|
|
5
|
+
* @since 3.0.0
|
|
6
|
+
*/
|
|
1
7
|
export interface PulseCpu {
|
|
2
|
-
|
|
3
|
-
|
|
8
|
+
/** System-wide CPU usage percentage (0-100). */
|
|
9
|
+
system: number
|
|
10
|
+
/** Process-specific CPU usage percentage (0-100). */
|
|
11
|
+
process: number
|
|
12
|
+
/** Number of CPU cores available. */
|
|
4
13
|
cores: number
|
|
5
14
|
}
|
|
6
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Metrics representing memory usage for a specific node/process.
|
|
18
|
+
*
|
|
19
|
+
* @public
|
|
20
|
+
* @since 3.0.0
|
|
21
|
+
*/
|
|
7
22
|
export interface PulseMemory {
|
|
23
|
+
/** System-wide memory statistics. */
|
|
8
24
|
system: {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
25
|
+
/** Total system memory in bytes. */
|
|
26
|
+
total: number
|
|
27
|
+
/** Free system memory in bytes. */
|
|
28
|
+
free: number
|
|
29
|
+
/** Used system memory in bytes. */
|
|
30
|
+
used: number
|
|
12
31
|
}
|
|
32
|
+
/** Process-specific memory statistics. */
|
|
13
33
|
process: {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
34
|
+
/** Resident Set Size (RSS) in bytes. */
|
|
35
|
+
rss: number
|
|
36
|
+
/** Total allocated heap size in bytes. */
|
|
37
|
+
heapTotal: number
|
|
38
|
+
/** Used heap size in bytes. */
|
|
39
|
+
heapUsed: number
|
|
17
40
|
}
|
|
18
41
|
}
|
|
19
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Runtime metadata for a monitored process.
|
|
45
|
+
*
|
|
46
|
+
* @public
|
|
47
|
+
* @since 3.0.0
|
|
48
|
+
*/
|
|
20
49
|
export interface PulseRuntime {
|
|
21
|
-
|
|
22
|
-
|
|
50
|
+
/** Uptime in seconds. */
|
|
51
|
+
uptime: number
|
|
52
|
+
/** Framework or runtime identification (e.g., "Node 21.4"). */
|
|
53
|
+
framework: string
|
|
54
|
+
/** Current process status (e.g., 'online', 'maintenance'). */
|
|
23
55
|
status?: string
|
|
56
|
+
/** Last few error messages from the process. */
|
|
24
57
|
errors?: string[]
|
|
25
58
|
}
|
|
26
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Statistics snapshot for a specific queue.
|
|
62
|
+
*
|
|
63
|
+
* @public
|
|
64
|
+
* @since 3.0.0
|
|
65
|
+
*/
|
|
27
66
|
export interface QueueSnapshot {
|
|
67
|
+
/** The name of the queue. */
|
|
28
68
|
name: string
|
|
69
|
+
/** The driver used (redis, sqs, etc.). */
|
|
29
70
|
driver: 'redis' | 'sqs' | 'rabbitmq'
|
|
71
|
+
/** Current counts of jobs in different states. */
|
|
30
72
|
size: {
|
|
31
73
|
waiting: number
|
|
32
74
|
active: number
|
|
33
75
|
failed: number
|
|
34
76
|
delayed: number
|
|
35
77
|
}
|
|
78
|
+
/** Historical throughput data. */
|
|
36
79
|
throughput?: {
|
|
37
|
-
in: number
|
|
38
|
-
out: number
|
|
80
|
+
in: number
|
|
81
|
+
out: number
|
|
39
82
|
}
|
|
40
83
|
}
|
|
41
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Represents a single application instance (node) monitored by Zenith.
|
|
87
|
+
*
|
|
88
|
+
* @public
|
|
89
|
+
* @since 3.0.0
|
|
90
|
+
*/
|
|
42
91
|
export interface PulseNode {
|
|
43
|
-
|
|
44
|
-
|
|
92
|
+
/** Unique execution ID for the node. */
|
|
93
|
+
id: string
|
|
94
|
+
/** Service group name. */
|
|
95
|
+
service: string
|
|
96
|
+
/** Programming language or runtime type. */
|
|
45
97
|
language: 'node' | 'bun' | 'deno' | 'php' | 'go' | 'python' | 'other'
|
|
46
|
-
|
|
98
|
+
/** Application version. */
|
|
99
|
+
version: string
|
|
100
|
+
/** Process identifier. */
|
|
47
101
|
pid: number
|
|
102
|
+
/** Hostname of the machine. */
|
|
48
103
|
hostname: string
|
|
104
|
+
/** Operating system platform. */
|
|
49
105
|
platform: string
|
|
106
|
+
/** CPU metrics. */
|
|
50
107
|
cpu: PulseCpu
|
|
108
|
+
/** Memory metrics. */
|
|
51
109
|
memory: PulseMemory
|
|
110
|
+
/** Optional list of queues managed by this node. */
|
|
52
111
|
queues?: QueueSnapshot[]
|
|
112
|
+
/** Runtime details. */
|
|
53
113
|
runtime: PulseRuntime
|
|
54
|
-
|
|
55
|
-
|
|
114
|
+
/** Unstructured metadata (e.g., framework-specific details). */
|
|
115
|
+
meta?: any
|
|
116
|
+
/** Epoch timestamp of the last heartbeat. */
|
|
117
|
+
timestamp: number
|
|
56
118
|
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Definition of an alert rule for monitoring health.
|
|
122
|
+
*
|
|
123
|
+
* @public
|
|
124
|
+
* @since 3.0.0
|
|
125
|
+
*/
|
|
57
126
|
export interface AlertRule {
|
|
127
|
+
/** Unique rule ID. */
|
|
58
128
|
id: string
|
|
129
|
+
/** Human-readable name. */
|
|
59
130
|
name: string
|
|
131
|
+
/** The metric type to monitor. */
|
|
60
132
|
type: 'backlog' | 'failure' | 'worker_lost' | 'node_cpu' | 'node_ram'
|
|
133
|
+
/** The value that triggers the alert. */
|
|
61
134
|
threshold: number
|
|
62
|
-
|
|
135
|
+
/** Optional queue name (if applicable). */
|
|
136
|
+
queue?: string
|
|
137
|
+
/** Minutes to wait before re-triggering the alert. */
|
|
63
138
|
cooldownMinutes: number
|
|
64
139
|
}
|
|
65
140
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
141
|
+
/**
|
|
142
|
+
* Configuration for alert notification channels.
|
|
143
|
+
*
|
|
144
|
+
* @public
|
|
145
|
+
* @since 3.0.0
|
|
146
|
+
*/
|
|
73
147
|
export interface AlertConfig {
|
|
148
|
+
/** Map of enabled notification channels. */
|
|
74
149
|
channels: {
|
|
75
150
|
slack?: {
|
|
76
151
|
enabled: boolean
|
|
@@ -87,13 +162,37 @@ export interface AlertConfig {
|
|
|
87
162
|
smtpUser: string
|
|
88
163
|
smtpPass: string
|
|
89
164
|
from: string
|
|
90
|
-
to: string
|
|
165
|
+
to: string
|
|
91
166
|
}
|
|
92
167
|
}
|
|
93
168
|
}
|
|
94
169
|
|
|
170
|
+
/**
|
|
171
|
+
* Configuration for automated system maintenance.
|
|
172
|
+
*
|
|
173
|
+
* @public
|
|
174
|
+
* @since 3.0.0
|
|
175
|
+
*/
|
|
95
176
|
export interface MaintenanceConfig {
|
|
177
|
+
/** Whether to automatically delete old data. */
|
|
96
178
|
autoCleanup: boolean
|
|
179
|
+
/** Number of days to retain records. */
|
|
97
180
|
retentionDays: number
|
|
98
|
-
|
|
181
|
+
/** Timestamp of the last maintenance run. */
|
|
182
|
+
lastRun?: number
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Represents a historical alert event.
|
|
187
|
+
*/
|
|
188
|
+
export interface AlertEvent {
|
|
189
|
+
id?: string
|
|
190
|
+
ruleId: string
|
|
191
|
+
ruleName?: string
|
|
192
|
+
type?: string
|
|
193
|
+
severity: 'critical' | 'warning' | 'info'
|
|
194
|
+
message: string
|
|
195
|
+
timestamp: number
|
|
196
|
+
resolved?: boolean
|
|
197
|
+
resolvedAt?: number
|
|
99
198
|
}
|
package/vite.config.ts
CHANGED
package/DEMO.md
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
# ๐ฎ Flux Console - Live Demo Walkthrough
|
|
2
|
-
|
|
3
|
-
This guide provides a step-by-step script for demonstrating the capabilities of **Flux Console**. It simulates a real-world production environment with traffic spikes, worker processing, and real-time monitoring.
|
|
4
|
-
|
|
5
|
-
## ๐๏ธ Architecture Setup
|
|
6
|
-
|
|
7
|
-
In this demo, we will run three components locally:
|
|
8
|
-
1. **Redis**: The message broker (must be running on `localhost:6379`).
|
|
9
|
-
2. **Flux Console**: The monitoring dashboard.
|
|
10
|
-
3. **Demo Worker**: A simulated worker that processes jobs from queues (`orders`, `reports`, etc.).
|
|
11
|
-
4. **Traffic Generator**: A script to flood the queues with jobs.
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## ๐๏ธ Persistence & History (Optional)
|
|
16
|
-
|
|
17
|
-
To test the **Job Archive**, **Operational Logs**, and **Search** features, you need a database. Flux Console supports two modes:
|
|
18
|
-
|
|
19
|
-
### A. Zero-Config (SQLite) - **Recommended for Quick Tests**
|
|
20
|
-
Simply set the `DB_DRIVER` and `DB_NAME` environment variables. It will create a local `.sqlite` file.
|
|
21
|
-
```bash
|
|
22
|
-
export DB_DRIVER=sqlite
|
|
23
|
-
export DB_NAME=flux.sqlite
|
|
24
|
-
export PERSIST_ARCHIVE_COMPLETED=true # Archive successful jobs too
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
### B. Full Stack (MySQL + Redis) - **Using Docker**
|
|
28
|
-
If you have Docker installed, you can spin up a production-ready environment:
|
|
29
|
-
```bash
|
|
30
|
-
cd packages/flux-console
|
|
31
|
-
docker-compose up -d
|
|
32
|
-
```
|
|
33
|
-
Then set your env variables to match:
|
|
34
|
-
```bash
|
|
35
|
-
export DB_HOST=localhost
|
|
36
|
-
export DB_USER=root
|
|
37
|
-
export DB_PASSWORD=root
|
|
38
|
-
export DB_NAME=flux
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
---
|
|
42
|
-
|
|
43
|
-
## ๐ฌ Step-by-Step Demo Script
|
|
44
|
-
|
|
45
|
-
### Step 1: Start the Flux Console ๐ฅ๏ธ
|
|
46
|
-
|
|
47
|
-
Open your first terminal window and launch the console. This starts both the web server and the SSE (Server-Sent Events) stream.
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
cd packages/flux-console
|
|
51
|
-
bun run start
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
> **Verify**: Open [http://localhost:3000](http://localhost:3000) in your browser. You should see the dashboard. It might be empty or show "No Data" initially.
|
|
55
|
-
|
|
56
|
-
### Step 2: Start the Worker ๐ท
|
|
57
|
-
|
|
58
|
-
We need a worker to "eat" the jobs. Without this, jobs will just pile up in the queue.
|
|
59
|
-
Open a **second terminal window**:
|
|
60
|
-
|
|
61
|
-
```bash
|
|
62
|
-
cd packages/flux-console
|
|
63
|
-
bun run scripts/demo-worker.ts
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
> **Observe**:
|
|
67
|
-
> - You should see `[Consumer] Started`.
|
|
68
|
-
> - The console output will show it's watching queues: `orders`, `notifications`, `billing`, etc.
|
|
69
|
-
> - **In the Browser**: Go to the **Workers** page. You should see `worker-xxxxx` appear as "Online". Note the **Cluster RAM** and **Load** metrics which reflect your actual machine's status.
|
|
70
|
-
|
|
71
|
-
### Step 3: Unleash the Traffic! ๐
|
|
72
|
-
|
|
73
|
-
Now, let's simulate a traffic spike (e.g., Black Friday sale).
|
|
74
|
-
Open a **third terminal window**:
|
|
75
|
-
|
|
76
|
-
```bash
|
|
77
|
-
cd packages/flux-console
|
|
78
|
-
bun run scripts/generate-random-traffic.ts
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
This script will:
|
|
82
|
-
- Push **50 jobs** randomly distributed to different queues.
|
|
83
|
-
- Some jobs are designed to **fail** (to test error handling).
|
|
84
|
-
- Some jobs are **delayed**.
|
|
85
|
-
|
|
86
|
-
> **Pro Tip**: Run this command multiple times rapidly to simulate a higher load spike!
|
|
87
|
-
|
|
88
|
-
---
|
|
89
|
-
|
|
90
|
-
## ๐งช Understanding Test Job Behavior
|
|
91
|
-
|
|
92
|
-
The demo worker uses a special `TestJob` class that simulates different real-world scenarios:
|
|
93
|
-
|
|
94
|
-
### Intentional Failures (DLQ Testing)
|
|
95
|
-
Jobs with IDs containing `"fail"` (e.g., `job-fail-1767244949663-25`) are **designed to always throw an error**. This is intentional and serves to demonstrate:
|
|
96
|
-
|
|
97
|
-
1. **Retry Mechanism**: You'll see these jobs attempt multiple times (`Attempt: 1, 2, 3...`).
|
|
98
|
-
2. **Exponential Backoff**: Each retry waits longer than the previous one (2s, 6s, 18s...).
|
|
99
|
-
3. **Dead Letter Queue (DLQ)**: After max attempts (default: 3), the job moves to the **Failed** queue.
|
|
100
|
-
4. **Error Handling UI**: You can see these in the Console's "Failed" tab with full error stack traces.
|
|
101
|
-
|
|
102
|
-
**This is expected behavior!** These jobs represent scenarios like:
|
|
103
|
-
- Invalid order IDs
|
|
104
|
-
- Malformed email addresses
|
|
105
|
-
- External API permanently rejecting a request
|
|
106
|
-
|
|
107
|
-
### Normal Jobs
|
|
108
|
-
Jobs without `"fail"` in their ID will:
|
|
109
|
-
- Process successfully after a simulated 50ms delay
|
|
110
|
-
- Update the throughput metrics
|
|
111
|
-
- Disappear from the queue
|
|
112
|
-
|
|
113
|
-
### The `default` Queue
|
|
114
|
-
When you click **"Retry All Failed"** in the Console, failed jobs are moved back to the queue. Due to how the retry mechanism works, they may be placed in the `default` queue instead of their original queue. This is why the worker monitors both specific queues (`orders`, `email`, etc.) **and** the `default` queue.
|
|
115
|
-
|
|
116
|
-
---
|
|
117
|
-
|
|
118
|
-
## ๐ฌ Step 4: The Showcase (What to show in the UI) โจ
|
|
119
|
-
|
|
120
|
-
Now, switch to the browser window and walk through these views:
|
|
121
|
-
|
|
122
|
-
#### 1. ๐ Dashboard (Overview)
|
|
123
|
-
- **Throughput Chart**: You will see a sudden spike in the green line (Processed/min).
|
|
124
|
-
- **Active Queues**: You'll see numbers jumping in `Waiting` and `Active` columns.
|
|
125
|
-
- **Top Right Live Logs**: Watch the logs stream in real-time as the worker processes jobs.
|
|
126
|
-
- **Log Search**: Click on **"Search Archive"** in the logs panel to open the historical log browser. This allows querying through millions of past events stored in SQL.
|
|
127
|
-
|
|
128
|
-
#### 2. ๐งฑ Queues Page
|
|
129
|
-
- Navigate to the **Queues** tab.
|
|
130
|
-
- Click on `queue:orders` or `queue:email`.
|
|
131
|
-
- **Action**: You can see jobs moving from **Waiting** to **Active**.
|
|
132
|
-
- **Inspection**: Click the "Eye" icon (Inspector) on a queue to see the JSON payload of waiting jobs.
|
|
133
|
-
|
|
134
|
-
#### 3. ๐จ Retry Handling (The "Oh No!" Moment)
|
|
135
|
-
- Go to the **Queues** page and look for the **Failed** tab (Red badge).
|
|
136
|
-
- You should see jobs with an error like `Simulated permanent failure`.
|
|
137
|
-
- **Action**: Click the "Retry All" button specifically for the failed jobs.
|
|
138
|
-
- **Result**: Watch the "Failed" count drop to 0 and the "Waiting" count go up. The worker will pick them up again.
|
|
139
|
-
|
|
140
|
-
#### 4. โ๏ธ Workers Page
|
|
141
|
-
- Refresh or stay on the **Workers** page.
|
|
142
|
-
- Observe the **Avg Load** bar changing colors (Green -> Amber) depending on your CPU usage.
|
|
143
|
-
- Explain that this demonstrates the **Real-time Health Monitoring** of the infrastructure.
|
|
144
|
-
|
|
145
|
-
---
|
|
146
|
-
|
|
147
|
-
## ๐งน Cleanup
|
|
148
|
-
|
|
149
|
-
To reset the demo environment (purge all queues):
|
|
150
|
-
|
|
151
|
-
```bash
|
|
152
|
-
# In the third terminal
|
|
153
|
-
bun run scripts/debug-redis.ts
|
|
154
|
-
# OR manually flush redis if you have redis-cli installed
|
|
155
|
-
# redis-cli flushall
|
|
156
|
-
```
|
|
@@ -1 +0,0 @@
|
|
|
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:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,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}:root{--background: 0 0% 100%;--foreground: 224 71.4% 4.1%;--card: 0 0% 100%;--card-foreground: 224 71.4% 4.1%;--popover: 0 0% 100%;--popover-foreground: 224 71.4% 4.1%;--primary: 238.7 83.5% 66.7%;--primary-foreground: 210 20% 98%;--secondary: 220 14.3% 95.9%;--secondary-foreground: 238.7 83.5% 66.7%;--muted: 220 14.3% 95.9%;--muted-foreground: 220 8.9% 46.1%;--accent: 220 14.3% 95.9%;--accent-foreground: 238.7 83.5% 66.7%;--destructive: 0 84.2% 60.2%;--destructive-foreground: 210 20% 98%;--border: 220 13% 91%;--input: 220 13% 91%;--ring: 238.7 83.5% 66.7%;--radius: 1rem}.dark{--background: 222 47% 2%;--foreground: 213 31% 91%;--card: 222 47% 6%;--card-foreground: 213 31% 91%;--popover: 222 47% 4%;--popover-foreground: 213 31% 91%;--primary: 238.7 83.5% 66.7%;--primary-foreground: 222 47% 4%;--secondary: 222 47% 10%;--secondary-foreground: 213 31% 91%;--muted: 222 47% 8%;--muted-foreground: 215.4 16.3% 56.9%;--accent: 222 47% 12%;--accent-foreground: 213 31% 91%;--destructive: 0 62.8% 30.6%;--destructive-foreground: 210 20% 98%;--border: 222 47% 14%;--input: 222 47% 12%;--ring: 238.7 83.5% 66.7%}*{border-color:hsl(var(--border))}body{background-color:hsl(var(--background));color:hsl(var(--foreground));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-feature-settings:"ss01","ss02","cv01","cv02","cv03"}.dark body{background-image:radial-gradient(at 50% 0%,hsla(238,83%,66%,.05) 0%,transparent 50%),radial-gradient(at 100% 100%,hsla(238,83%,66%,.02) 0%,transparent 50%);background-attachment:fixed}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.-bottom-1{bottom:-.25rem}.-left-1\/4{left:-25%}.-right-1{right:-.25rem}.-right-1\/4{right:-25%}.bottom-0{bottom:0}.bottom-1\/4{bottom:25%}.bottom-8{bottom:2rem}.bottom-full{bottom:100%}.left-0{left:0}.left-1{left:.25rem}.left-1\/2{left:50%}.left-3{left:.75rem}.left-4{left:1rem}.right-0{right:0}.right-1\.5{right:.375rem}.right-2{right:.5rem}.right-4{right:1rem}.right-8{right:2rem}.top-0{top:0}.top-1\.5{top:.375rem}.top-1\/2{top:50%}.top-1\/4{top:25%}.top-4{top:1rem}.top-full{top:100%}.z-0{z-index:0}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.z-\[1001\]{z-index:1001}.z-\[1002\]{z-index:1002}.z-\[100\]{z-index:100}.z-\[2000\]{z-index:2000}.z-\[4000\]{z-index:4000}.z-\[5000\]{z-index:5000}.col-span-2{grid-column:span 2 / span 2}.col-span-full{grid-column:1 / -1}.-mx-2{margin-left:-.5rem;margin-right:-.5rem}.mx-auto{margin-left:auto;margin-right:auto}.mb-0\.5{margin-bottom:.125rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.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-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-auto{margin-left:auto}.mr-2{margin-right:.5rem}.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}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.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}.aspect-square{aspect-ratio:1 / 1}.h-1{height:.25rem}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-20{height:5rem}.h-24{height:6rem}.h-3{height:.75rem}.h-32{height:8rem}.h-4{height:1rem}.h-48{height:12rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-96{height:24rem}.h-\[300px\]{height:300px}.h-\[350px\]{height:350px}.h-\[400px\]{height:400px}.h-\[85vh\]{height:85vh}.h-full{height:100%}.h-screen{height:100vh}.max-h-\[400px\]{max-height:400px}.max-h-\[850px\]{max-height:850px}.min-h-0{min-height:0px}.min-h-screen{min-height:100vh}.w-1{width:.25rem}.w-1\.5{width:.375rem}.w-10{width:2.5rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-16{width:4rem}.w-2{width:.5rem}.w-2\.5{width:.625rem}.w-20{width:5rem}.w-24{width:6rem}.w-3{width:.75rem}.w-32{width:8rem}.w-4{width:1rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-72{width:18rem}.w-8{width:2rem}.w-96{width:24rem}.w-\[1px\]{width:1px}.w-full{width:100%}.w-px{width:1px}.min-w-0{min-width:0px}.min-w-\[140px\]{min-width:140px}.min-w-\[16px\]{min-width:16px}.min-w-\[200px\]{min-width:200px}.max-w-2xl{max-width:42rem}.max-w-4xl{max-width:56rem}.max-w-6xl{max-width:72rem}.max-w-7xl{max-width:80rem}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-sm{max-width:24rem}.flex-1{flex:1 1 0%}.flex-none{flex:none}.flex-shrink-0,.shrink-0{flex-shrink:0}.origin-left{transform-origin:left}.-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-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))}.-translate-y-1{--tw-translate-y: -.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-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))}.scale-110{--tw-scale-x: 1.1;--tw-scale-y: 1.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))}.scale-\[1\.02\]{--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))}.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 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-default{cursor:default}.cursor-help{cursor:help}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-10{grid-template-columns:repeat(10,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))}.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}.items-baseline{align-items:baseline}.justify-start{justify-content:flex-start}.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-5{gap:1.25rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.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-12>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(3rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(3rem * 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-2\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.625rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.625rem * 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-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * 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-border\/10>:not([hidden])~:not([hidden]){border-color:hsl(var(--border) / .1)}.divide-border\/30>:not([hidden])~:not([hidden]){border-color:hsl(var(--border) / .3)}.divide-border\/50>:not([hidden])~:not([hidden]){border-color:hsl(var(--border) / .5)}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.scroll-smooth{scroll-behavior:smooth}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.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:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-sm{border-radius:calc(var(--radius) - 4px)}.rounded-xl{border-radius:.75rem}.rounded-r-full{border-top-right-radius:9999px;border-bottom-right-radius:9999px}.rounded-t-lg{border-top-left-radius:var(--radius);border-top-right-radius:var(--radius)}.rounded-bl-full{border-bottom-left-radius:9999px}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-none{border-style:none}.border-amber-500{--tw-border-opacity: 1;border-color:rgb(245 158 11 / var(--tw-border-opacity, 1))}.border-amber-500\/10{border-color:#f59e0b1a}.border-amber-500\/20{border-color:#f59e0b33}.border-amber-500\/30{border-color:#f59e0b4d}.border-background{border-color:hsl(var(--background))}.border-blue-500{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity, 1))}.border-border{border-color:hsl(var(--border))}.border-border\/10{border-color:hsl(var(--border) / .1)}.border-border\/20{border-color:hsl(var(--border) / .2)}.border-border\/30{border-color:hsl(var(--border) / .3)}.border-border\/40{border-color:hsl(var(--border) / .4)}.border-border\/5{border-color:hsl(var(--border) / .05)}.border-border\/50{border-color:hsl(var(--border) / .5)}.border-card{border-color:hsl(var(--card))}.border-green-500{--tw-border-opacity: 1;border-color:rgb(34 197 94 / var(--tw-border-opacity, 1))}.border-green-500\/20{border-color:#22c55e33}.border-indigo-500{--tw-border-opacity: 1;border-color:rgb(99 102 241 / var(--tw-border-opacity, 1))}.border-primary{border-color:hsl(var(--primary))}.border-primary-foreground\/30{border-color:hsl(var(--primary-foreground) / .3)}.border-primary\/10{border-color:hsl(var(--primary) / .1)}.border-primary\/20{border-color:hsl(var(--primary) / .2)}.border-primary\/50{border-color:hsl(var(--primary) / .5)}.border-red-500{--tw-border-opacity: 1;border-color:rgb(239 68 68 / var(--tw-border-opacity, 1))}.border-red-500\/10{border-color:#ef44441a}.border-red-500\/20{border-color:#ef444433}.border-red-600{--tw-border-opacity: 1;border-color:rgb(220 38 38 / var(--tw-border-opacity, 1))}.border-transparent{border-color:transparent}.border-yellow-500\/20{border-color:#eab30833}.border-t-primary-foreground{border-top-color:hsl(var(--primary-foreground))}.bg-\[\#4A154B\]\/10{background-color:#4a154b1a}.bg-\[\#5865F2\]\/10{background-color:#5865f21a}.bg-amber-500{--tw-bg-opacity: 1;background-color:rgb(245 158 11 / var(--tw-bg-opacity, 1))}.bg-amber-500\/10{background-color:#f59e0b1a}.bg-amber-500\/20{background-color:#f59e0b33}.bg-amber-500\/5{background-color:#f59e0b0d}.bg-background{background-color:hsl(var(--background))}.bg-background\/50{background-color:hsl(var(--background) / .5)}.bg-background\/80{background-color:hsl(var(--background) / .8)}.bg-black\/20{background-color:#0003}.bg-black\/60{background-color:#0009}.bg-blue-500{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.bg-blue-500\/10{background-color:#3b82f61a}.bg-blue-500\/20{background-color:#3b82f633}.bg-border\/30{background-color:hsl(var(--border) / .3)}.bg-border\/50{background-color:hsl(var(--border) / .5)}.bg-card{background-color:hsl(var(--card))}.bg-card\/50{background-color:hsl(var(--card) / .5)}.bg-card\/80{background-color:hsl(var(--card) / .8)}.bg-current{background-color:currentColor}.bg-emerald-500{--tw-bg-opacity: 1;background-color:rgb(16 185 129 / var(--tw-bg-opacity, 1))}.bg-foreground{background-color:hsl(var(--foreground))}.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-green-500\/40{background-color:#22c55e66}.bg-indigo-500{--tw-bg-opacity: 1;background-color:rgb(99 102 241 / var(--tw-bg-opacity, 1))}.bg-indigo-500\/10{background-color:#6366f11a}.bg-muted{background-color:hsl(var(--muted))}.bg-muted-foreground{background-color:hsl(var(--muted-foreground))}.bg-muted-foreground\/20{background-color:hsl(var(--muted-foreground) / .2)}.bg-muted-foreground\/30{background-color:hsl(var(--muted-foreground) / .3)}.bg-muted-foreground\/40{background-color:hsl(var(--muted-foreground) / .4)}.bg-muted\/10{background-color:hsl(var(--muted) / .1)}.bg-muted\/20{background-color:hsl(var(--muted) / .2)}.bg-muted\/30{background-color:hsl(var(--muted) / .3)}.bg-muted\/40{background-color:hsl(var(--muted) / .4)}.bg-muted\/5{background-color:hsl(var(--muted) / .05)}.bg-muted\/50{background-color:hsl(var(--muted) / .5)}.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-popover{background-color:hsl(var(--popover))}.bg-primary{background-color:hsl(var(--primary))}.bg-primary-foreground{background-color:hsl(var(--primary-foreground))}.bg-primary\/10{background-color:hsl(var(--primary) / .1)}.bg-primary\/40{background-color:hsl(var(--primary) / .4)}.bg-primary\/5{background-color:hsl(var(--primary) / .05)}.bg-red-500{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.bg-red-500\/10{background-color:#ef44441a}.bg-red-500\/20{background-color:#ef444433}.bg-red-500\/5{background-color:#ef44440d}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-white\/10{background-color:#ffffff1a}.bg-white\/20{background-color:#fff3}.bg-yellow-500{--tw-bg-opacity: 1;background-color:rgb(234 179 8 / var(--tw-bg-opacity, 1))}.bg-yellow-500\/10{background-color:#eab3081a}.bg-\[linear-gradient\(rgba\(var\(--primary-rgb\)\,0\.03\)_1px\,transparent_1px\)\,linear-gradient\(90deg\,rgba\(var\(--primary-rgb\)\,0\.03\)_1px\,transparent_1px\)\]{background-image:linear-gradient(rgba(var(--primary-rgb),.03) 1px,transparent 1px),linear-gradient(90deg,rgba(var(--primary-rgb),.03) 1px,transparent 1px)}.bg-gradient-to-bl{background-image:linear-gradient(to bottom left,var(--tw-gradient-stops))}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.bg-gradient-to-l{background-image:linear-gradient(to left,var(--tw-gradient-stops))}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.from-card{--tw-gradient-from: hsl(var(--card)) var(--tw-gradient-from-position);--tw-gradient-to: hsl(var(--card) / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-emerald-500{--tw-gradient-from: #10b981 var(--tw-gradient-from-position);--tw-gradient-to: rgb(16 185 129 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-primary{--tw-gradient-from: hsl(var(--primary)) var(--tw-gradient-from-position);--tw-gradient-to: hsl(var(--primary) / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-primary\/10{--tw-gradient-from: hsl(var(--primary) / .1) var(--tw-gradient-from-position);--tw-gradient-to: hsl(var(--primary) / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-primary\/5{--tw-gradient-from: hsl(var(--primary) / .05) var(--tw-gradient-from-position);--tw-gradient-to: hsl(var(--primary) / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-red-500{--tw-gradient-from: #ef4444 var(--tw-gradient-from-position);--tw-gradient-to: rgb(239 68 68 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-yellow-500{--tw-gradient-from: #eab308 var(--tw-gradient-from-position);--tw-gradient-to: rgb(234 179 8 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.via-card{--tw-gradient-to: hsl(var(--card) / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), hsl(var(--card)) var(--tw-gradient-via-position), var(--tw-gradient-to)}.via-transparent{--tw-gradient-to: rgb(0 0 0 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), transparent var(--tw-gradient-via-position), var(--tw-gradient-to)}.to-indigo-500\/10{--tw-gradient-to: rgb(99 102 241 / .1) var(--tw-gradient-to-position)}.to-indigo-500\/5{--tw-gradient-to: rgb(99 102 241 / .05) var(--tw-gradient-to-position)}.to-indigo-600{--tw-gradient-to: #4f46e5 var(--tw-gradient-to-position)}.to-primary\/60{--tw-gradient-to: hsl(var(--primary) / .6) var(--tw-gradient-to-position)}.to-transparent{--tw-gradient-to: transparent var(--tw-gradient-to-position)}.bg-\[size\:64px_64px\]{background-size:64px 64px}.bg-clip-text{-webkit-background-clip:text;background-clip:text}.fill-current{fill:currentColor}.p-0{padding:0}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-10{padding:2.5rem}.p-12{padding:3rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-20{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-0\.5{padding-left:.125rem;padding-right:.125rem}.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-20{padding-top:5rem;padding-bottom:5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.pb-0{padding-bottom:0}.pb-20{padding-bottom:5rem}.pb-3{padding-bottom:.75rem}.pb-6{padding-bottom:1.5rem}.pl-10{padding-left:2.5rem}.pl-12{padding-left:3rem}.pl-4{padding-left:1rem}.pl-9{padding-left:2.25rem}.pl-\[3\.75rem\]{padding-left:3.75rem}.pr-12{padding-right:3rem}.pr-4{padding-right:1rem}.pt-0{padding-top:0}.pt-1{padding-top:.25rem}.pt-1\.5{padding-top:.375rem}.pt-2{padding-top:.5rem}.pt-24{padding-top:6rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.pt-6{padding-top:1.5rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[8px\]{font-size:8px}.text-\[9px\]{font-size:9px}.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-extrabold{font-weight:800}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.tracking-\[0\.1em\]{letter-spacing:.1em}.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-wider{letter-spacing:.05em}.tracking-widest{letter-spacing:.1em}.text-\[\#4A154B\]{--tw-text-opacity: 1;color:rgb(74 21 75 / var(--tw-text-opacity, 1))}.text-\[\#5865F2\]{--tw-text-opacity: 1;color:rgb(88 101 242 / var(--tw-text-opacity, 1))}.text-amber-500{--tw-text-opacity: 1;color:rgb(245 158 11 / var(--tw-text-opacity, 1))}.text-amber-600{--tw-text-opacity: 1;color:rgb(217 119 6 / var(--tw-text-opacity, 1))}.text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity, 1))}.text-blue-500{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity, 1))}.text-emerald-500{--tw-text-opacity: 1;color:rgb(16 185 129 / var(--tw-text-opacity, 1))}.text-foreground{color:hsl(var(--foreground))}.text-foreground\/80{color:hsl(var(--foreground) / .8)}.text-foreground\/90{color:hsl(var(--foreground) / .9)}.text-green-500{--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}.text-indigo-400{--tw-text-opacity: 1;color:rgb(129 140 248 / var(--tw-text-opacity, 1))}.text-indigo-400\/80{color:#818cf8cc}.text-indigo-500{--tw-text-opacity: 1;color:rgb(99 102 241 / var(--tw-text-opacity, 1))}.text-muted-foreground{color:hsl(var(--muted-foreground))}.text-muted-foreground\/20{color:hsl(var(--muted-foreground) / .2)}.text-muted-foreground\/30{color:hsl(var(--muted-foreground) / .3)}.text-muted-foreground\/40{color:hsl(var(--muted-foreground) / .4)}.text-muted-foreground\/50{color:hsl(var(--muted-foreground) / .5)}.text-muted-foreground\/60{color:hsl(var(--muted-foreground) / .6)}.text-orange-500{--tw-text-opacity: 1;color:rgb(249 115 22 / var(--tw-text-opacity, 1))}.text-popover-foreground{color:hsl(var(--popover-foreground))}.text-primary{color:hsl(var(--primary))}.text-primary-foreground{color:hsl(var(--primary-foreground))}.text-primary\/40{color:hsl(var(--primary) / .4)}.text-primary\/60{color:hsl(var(--primary) / .6)}.text-primary\/80{color:hsl(var(--primary) / .8)}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-red-500\/60{color:#ef444499}.text-red-500\/80{color:#ef4444cc}.text-red-900\/60{color:#7f1d1d99}.text-transparent{color:transparent}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-white\/80{color:#fffc}.text-yellow-500{--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity, 1))}.opacity-0{opacity:0}.opacity-10{opacity:.1}.opacity-20{opacity:.2}.opacity-25{opacity:.25}.opacity-30{opacity:.3}.opacity-5{opacity:.05}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.opacity-75{opacity:.75}.opacity-80{opacity:.8}.opacity-90{opacity:.9}.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_10px_currentColor\]{--tw-shadow: 0 0 10px currentColor;--tw-shadow-colored: 0 0 10px 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_12px_rgba\(34\,197\,94\,0\.6\)\]{--tw-shadow: 0 0 12px rgba(34,197,94,.6);--tw-shadow-colored: 0 0 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_20px_rgba\(var\(--primary-rgb\)\,0\.1\)\]{--tw-shadow: 0 0 20px rgba(var(--primary-rgb),.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-\[0_0_8px_rgba\(34\,197\,94\,0\.4\)\]{--tw-shadow: 0 0 8px rgba(34,197,94,.4);--tw-shadow-colored: 0 0 8px 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_8px_rgba\(34\,197\,94\,0\.6\)\]{--tw-shadow: 0 0 8px rgba(34,197,94,.6);--tw-shadow-colored: 0 0 8px 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-amber-500\/20{--tw-shadow-color: rgb(245 158 11 / .2);--tw-shadow: var(--tw-shadow-colored)}.shadow-green-500\/20{--tw-shadow-color: rgb(34 197 94 / .2);--tw-shadow: var(--tw-shadow-colored)}.shadow-indigo-500\/20{--tw-shadow-color: rgb(99 102 241 / .2);--tw-shadow: var(--tw-shadow-colored)}.shadow-primary\/10{--tw-shadow-color: hsl(var(--primary) / .1);--tw-shadow: var(--tw-shadow-colored)}.shadow-primary\/20{--tw-shadow-color: hsl(var(--primary) / .2);--tw-shadow: var(--tw-shadow-colored)}.shadow-primary\/30{--tw-shadow-color: hsl(var(--primary) / .3);--tw-shadow: var(--tw-shadow-colored)}.shadow-red-500\/20{--tw-shadow-color: rgb(239 68 68 / .2);--tw-shadow: var(--tw-shadow-colored)}.shadow-transparent{--tw-shadow-color: transparent;--tw-shadow: var(--tw-shadow-colored)}.outline-none{outline:2px solid transparent;outline-offset:2px}.ring-2{--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)}.ring-primary{--tw-ring-color: hsl(var(--primary))}.blur{--tw-blur: blur(8px);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-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)}.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)}.backdrop-blur-xl{--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)}.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-1000{transition-duration:1s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.duration-700{transition-duration:.7s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.scrollbar-thin::-webkit-scrollbar{width:6px;height:6px}.scrollbar-thin::-webkit-scrollbar-track{background:transparent}.scrollbar-thin::-webkit-scrollbar-thumb{border-radius:9999px;background-color:hsl(var(--muted-foreground) / .2);-webkit-transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.scrollbar-thin::-webkit-scrollbar-thumb:hover{background-color:hsl(var(--muted-foreground) / .4)}.scanline{position:relative;overflow:hidden}.scanline:after{content:" ";display:block;position:absolute;top:0;left:0;right:0;bottom:0;background:linear-gradient(to bottom,transparent 50%,rgba(var(--primary),.02) 50%);background-size:100% 4px;z-index:2;pointer-events:none;animation:scanline-move 10s linear infinite}@keyframes scanline-move{0%{background-position:0 0}to{background-position:0 100%}}.glow-pulse{animation:glow-pulse 2.5s ease-in-out infinite}@keyframes glow-pulse{0%,to{opacity:.3;transform:scale(1);filter:blur(2px)}50%{opacity:.7;transform:scale(1.5);filter:blur(4px)}}.card-premium{border-width:1px;border-color:hsl(var(--border) / .5);background-color:hsl(var(--card));--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);transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.3s}.dark .card-premium{background-color:#080c1699;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);border-color:#ffffff0d;box-shadow:0 4px 20px #00000080}.dark .card-premium:hover{border-color:#6065f033;box-shadow:0 8px 30px #6366f10d}.animate-in{animation-duration:.4s;animation-timing-function:cubic-bezier(.16,1,.3,1);fill-mode:forwards}@keyframes toast-progress{0%{transform:scaleX(1)}to{transform:scaleX(0)}}.animate-toast-progress{animation:toast-progress 5s linear forwards}.placeholder\:text-muted-foreground\/30::-moz-placeholder{color:hsl(var(--muted-foreground) / .3)}.placeholder\:text-muted-foreground\/30::placeholder{color:hsl(var(--muted-foreground) / .3)}.placeholder\:text-muted-foreground\/40::-moz-placeholder{color:hsl(var(--muted-foreground) / .4)}.placeholder\:text-muted-foreground\/40::placeholder{color:hsl(var(--muted-foreground) / .4)}.last\:hidden:last-child{display:none}.hover\:-translate-y-2:hover{--tw-translate-y: -.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))}.hover\:scale-125:hover{--tw-scale-x: 1.25;--tw-scale-y: 1.25;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-primary\/20:hover{border-color:hsl(var(--primary) / .2)}.hover\:border-primary\/30:hover{border-color:hsl(var(--primary) / .3)}.hover\:border-primary\/50:hover{border-color:hsl(var(--primary) / .5)}.hover\:bg-amber-500:hover{--tw-bg-opacity: 1;background-color:rgb(245 158 11 / var(--tw-bg-opacity, 1))}.hover\:bg-amber-500\/10:hover{background-color:#f59e0b1a}.hover\:bg-amber-500\/20:hover{background-color:#f59e0b33}.hover\:bg-amber-600:hover{--tw-bg-opacity: 1;background-color:rgb(217 119 6 / var(--tw-bg-opacity, 1))}.hover\:bg-background:hover{background-color:hsl(var(--background))}.hover\:bg-blue-500\/10:hover{background-color:#3b82f61a}.hover\:bg-blue-600:hover{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity, 1))}.hover\:bg-emerald-500\/20:hover{background-color:#10b98133}.hover\:bg-green-500\/10:hover{background-color:#22c55e1a}.hover\:bg-muted:hover{background-color:hsl(var(--muted))}.hover\:bg-muted\/10:hover{background-color:hsl(var(--muted) / .1)}.hover\:bg-muted\/30:hover{background-color:hsl(var(--muted) / .3)}.hover\:bg-muted\/5:hover{background-color:hsl(var(--muted) / .05)}.hover\:bg-muted\/50:hover{background-color:hsl(var(--muted) / .5)}.hover\:bg-muted\/60:hover{background-color:hsl(var(--muted) / .6)}.hover\:bg-muted\/80:hover{background-color:hsl(var(--muted) / .8)}.hover\:bg-primary:hover{background-color:hsl(var(--primary))}.hover\:bg-primary\/10:hover{background-color:hsl(var(--primary) / .1)}.hover\:bg-primary\/20:hover{background-color:hsl(var(--primary) / .2)}.hover\:bg-primary\/5:hover{background-color:hsl(var(--primary) / .05)}.hover\:bg-primary\/\[0\.02\]:hover{background-color:hsl(var(--primary) / .02)}.hover\:bg-red-500:hover{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.hover\:bg-red-500\/10:hover{background-color:#ef44441a}.hover\:bg-red-500\/20:hover{background-color:#ef444433}.hover\:bg-red-600:hover{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity, 1))}.hover\:bg-white\/10:hover{background-color:#ffffff1a}.hover\:bg-white\/\[0\.02\]:hover{background-color:#ffffff05}.hover\:text-amber-500:hover{--tw-text-opacity: 1;color:rgb(245 158 11 / var(--tw-text-opacity, 1))}.hover\:text-foreground:hover{color:hsl(var(--foreground))}.hover\:text-primary:hover{color:hsl(var(--primary))}.hover\:text-primary-foreground:hover{color:hsl(var(--primary-foreground))}.hover\:text-red-500:hover{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.hover\:text-white:hover{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.hover\:shadow-2xl:hover{--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)}.hover\:shadow-md:hover{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.hover\:shadow-xl:hover{--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)}.hover\:shadow-primary\/20:hover{--tw-shadow-color: hsl(var(--primary) / .2);--tw-shadow: var(--tw-shadow-colored)}.hover\:shadow-primary\/40:hover{--tw-shadow-color: hsl(var(--primary) / .4);--tw-shadow: var(--tw-shadow-colored)}.focus\:border-primary\/50:focus{border-color:hsl(var(--primary) / .5)}.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-inset:focus{--tw-ring-inset: inset}.focus\:ring-primary:focus{--tw-ring-color: hsl(var(--primary))}.focus\:ring-primary\/20:focus{--tw-ring-color: hsl(var(--primary) / .2)}.focus\:ring-primary\/30:focus{--tw-ring-color: hsl(var(--primary) / .3)}.active\:scale-90:active{--tw-scale-x: .9;--tw-scale-y: .9;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))}.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))}.active\:scale-\[0\.98\]:active{--tw-scale-x: .98;--tw-scale-y: .98;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-30:disabled{opacity:.3}.disabled\:opacity-50:disabled{opacity:.5}.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\:rotate-12{--tw-rotate: 12deg;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\: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))}.group:hover .group-hover\:rotate-\[15deg\]{--tw-rotate: 15deg;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\/item:hover .group-hover\/item\:scale-110{--tw-scale-x: 1.1;--tw-scale-y: 1.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\: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))}.group:hover .group-hover\:scale-110{--tw-scale-x: 1.1;--tw-scale-y: 1.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\:scale-150{--tw-scale-x: 1.5;--tw-scale-y: 1.5;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\:border-border\/10{border-color:hsl(var(--border) / .1)}.group:hover .group-hover\:border-primary\/20{border-color:hsl(var(--primary) / .2)}.group:hover .group-hover\:bg-primary\/10{background-color:hsl(var(--primary) / .1)}.group:hover .group-hover\:bg-primary\/20{background-color:hsl(var(--primary) / .2)}.group:hover .group-hover\:text-foreground{color:hsl(var(--foreground))}.group:hover .group-hover\:text-primary{color:hsl(var(--primary))}.group\/tile:hover .group-hover\/tile\:opacity-100,.group:hover .group-hover\:opacity-100{opacity:1}.group:hover .group-hover\:opacity-20{opacity:.2}@media(min-width:640px){.sm\:block{display:block}.sm\:inline{display:inline}.sm\:w-auto{width:auto}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:p-6{padding:1.5rem}.sm\:p-8{padding:2rem}}@media(min-width:768px){.md\:col-span-2{grid-column:span 2 / span 2}.md\:inline{display:inline}.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\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:p-10{padding:2.5rem}}@media(min-width:1024px){.lg\:col-span-1{grid-column:span 1 / span 1}.lg\:col-span-2{grid-column:span 2 / span 2}.lg\:inline{display:inline}.lg\:flex{display:flex}.lg\:grid{display:grid}.lg\:h-\[600px\]{height:600px}.lg\:h-full{height:100%}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.lg\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.lg\:grid-rows-2{grid-template-rows:repeat(2,minmax(0,1fr))}}@media(min-width:1280px){.xl\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media(prefers-color-scheme:dark){.dark\:bg-card{background-color:hsl(var(--card))}.dark\:text-\[\#E01E5A\]{--tw-text-opacity: 1;color:rgb(224 30 90 / var(--tw-text-opacity, 1))}.dark\:text-amber-400{--tw-text-opacity: 1;color:rgb(251 191 36 / var(--tw-text-opacity, 1))}.dark\:text-red-400\/60{color:#f8717199}}
|