polymo 0.1.0__py3-none-any.whl
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.
- polymo/__init__.py +32 -0
- polymo/builder/__init__.py +5 -0
- polymo/builder/app.py +339 -0
- polymo/builder/static/examples/githubrepos.yml +15 -0
- polymo/builder/static/examples/jsonplaceholder.yml +9 -0
- polymo/builder/static/favicon.ico +0 -0
- polymo/builder/static/index.html +17 -0
- polymo/builder/static/logo.png +0 -0
- polymo/builder/static/logo192.png +0 -0
- polymo/builder/static/main.css +1 -0
- polymo/builder/static/main.js +117 -0
- polymo/builder/static/mockServiceWorker.js +335 -0
- polymo/builder/templates/index.html +21 -0
- polymo/cli.py +73 -0
- polymo/config.py +480 -0
- polymo/datasource.py +184 -0
- polymo/py.typed +0 -0
- polymo/rest_client.py +416 -0
- polymo/scripts/__init__.py +0 -0
- polymo/scripts/smoke.py +57 -0
- polymo-0.1.0.dist-info/METADATA +82 -0
- polymo-0.1.0.dist-info/RECORD +24 -0
- polymo-0.1.0.dist-info/WHEEL +4 -0
- polymo-0.1.0.dist-info/entry_points.txt +3 -0
polymo/__init__.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Public entrypoints for the polymo REST data source."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pyspark.sql import SparkSession
|
|
6
|
+
|
|
7
|
+
from .config import RestSourceConfig, config_to_dict, dump_config, load_config, parse_config
|
|
8
|
+
from .datasource import ApiReader
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"register",
|
|
12
|
+
"ApiReader",
|
|
13
|
+
"RestSourceConfig",
|
|
14
|
+
"config_to_dict",
|
|
15
|
+
"dump_config",
|
|
16
|
+
"load_config",
|
|
17
|
+
"parse_config",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _alias_datasource(name: str) -> type[ApiReader]:
|
|
22
|
+
alias_name = name
|
|
23
|
+
|
|
24
|
+
class AliasRestDataSource(ApiReader):
|
|
25
|
+
@classmethod
|
|
26
|
+
def name(cls) -> str: # type: ignore[override]
|
|
27
|
+
return alias_name
|
|
28
|
+
|
|
29
|
+
AliasRestDataSource.__name__ = f"RestDataSource_{name.replace('.', '_')}"
|
|
30
|
+
AliasRestDataSource.__qualname__ = AliasRestDataSource.__name__
|
|
31
|
+
AliasRestDataSource.__module__ = ApiReader.__module__
|
|
32
|
+
return AliasRestDataSource
|
polymo/builder/app.py
ADDED
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
"""FastAPI application powering the polymo web builder."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from functools import partial
|
|
6
|
+
from importlib import resources
|
|
7
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
8
|
+
|
|
9
|
+
import yaml
|
|
10
|
+
from fastapi import FastAPI, HTTPException, Request
|
|
11
|
+
from fastapi.responses import FileResponse
|
|
12
|
+
from fastapi.staticfiles import StaticFiles
|
|
13
|
+
from fastapi.templating import Jinja2Templates
|
|
14
|
+
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
|
15
|
+
from starlette.concurrency import run_in_threadpool
|
|
16
|
+
|
|
17
|
+
from ..config import (
|
|
18
|
+
ConfigError,
|
|
19
|
+
RestSourceConfig,
|
|
20
|
+
config_to_dict,
|
|
21
|
+
dump_config,
|
|
22
|
+
parse_config,
|
|
23
|
+
)
|
|
24
|
+
from ..rest_client import RestClient
|
|
25
|
+
|
|
26
|
+
PACKAGE_ROOT = resources.files(__package__)
|
|
27
|
+
TEMPLATES = Jinja2Templates(directory=str(PACKAGE_ROOT.joinpath("templates")))
|
|
28
|
+
STATIC_PATH = PACKAGE_ROOT.joinpath("static")
|
|
29
|
+
|
|
30
|
+
SAMPLE_CONFIG = """\
|
|
31
|
+
version: 0.1
|
|
32
|
+
source:
|
|
33
|
+
type: rest
|
|
34
|
+
base_url: https://jsonplaceholder.typicode.com
|
|
35
|
+
stream:
|
|
36
|
+
name: posts
|
|
37
|
+
path: /posts
|
|
38
|
+
params:
|
|
39
|
+
_limit: 25
|
|
40
|
+
pagination:
|
|
41
|
+
type: none
|
|
42
|
+
incremental:
|
|
43
|
+
mode: null
|
|
44
|
+
cursor_param: null
|
|
45
|
+
cursor_field: null
|
|
46
|
+
infer_schema: true
|
|
47
|
+
schema: null
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
SAMPLE_CONFIG_OBJECT = parse_config(yaml.safe_load(SAMPLE_CONFIG))
|
|
51
|
+
SAMPLE_CONFIG_DICT = config_to_dict(SAMPLE_CONFIG_OBJECT)
|
|
52
|
+
SAMPLE_CONFIG_YAML = dump_config(SAMPLE_CONFIG_OBJECT)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class ValidationRequest(BaseModel):
|
|
56
|
+
config: Optional[str] = Field(None, description="YAML configuration text")
|
|
57
|
+
config_dict: Optional[Dict[str, Any]] = Field(
|
|
58
|
+
None, description="Configuration provided as a dictionary"
|
|
59
|
+
)
|
|
60
|
+
token: Optional[str] = Field(None, description="Bearer token supplied separately (not stored)")
|
|
61
|
+
options: Optional[Dict[str, Any]] = Field(
|
|
62
|
+
default=None, description="Spark reader options provided alongside the config"
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
model_config = ConfigDict(extra="ignore")
|
|
66
|
+
|
|
67
|
+
@model_validator(mode="after")
|
|
68
|
+
def _ensure_payload(self) -> "ValidationRequest":
|
|
69
|
+
if self.config is None and self.config_dict is None:
|
|
70
|
+
raise ValueError("Either 'config' or 'config_dict' must be provided")
|
|
71
|
+
return self
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class ValidationResponse(BaseModel):
|
|
75
|
+
valid: bool
|
|
76
|
+
stream: str | None = None
|
|
77
|
+
message: Optional[str] = None
|
|
78
|
+
config: Optional[Dict[str, Any]] = None
|
|
79
|
+
yaml: Optional[str] = None
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class SampleRequest(BaseModel):
|
|
83
|
+
config: Optional[str] = None
|
|
84
|
+
config_dict: Optional[Dict[str, Any]] = None
|
|
85
|
+
token: Optional[str] = None
|
|
86
|
+
limit: int = Field(20, ge=1, le=500, description="Maximum records to preview")
|
|
87
|
+
options: Optional[Dict[str, Any]] = Field(
|
|
88
|
+
default=None, description="Spark reader options provided alongside the config"
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
model_config = ConfigDict(extra="ignore")
|
|
92
|
+
|
|
93
|
+
@model_validator(mode="after")
|
|
94
|
+
def _ensure_payload(self) -> "SampleRequest":
|
|
95
|
+
if self.config is None and self.config_dict is None:
|
|
96
|
+
raise ValueError("Either 'config' or 'config_dict' must be provided")
|
|
97
|
+
return self
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class SampleResponse(BaseModel):
|
|
101
|
+
stream: str
|
|
102
|
+
records: List[Dict[str, Any]]
|
|
103
|
+
dtypes: List[Dict[str, str]] = Field(default_factory=list, description="Spark column data types")
|
|
104
|
+
raw_pages: List[Dict[str, Any]] = Field(
|
|
105
|
+
default_factory=list, description="Raw REST API responses captured per page"
|
|
106
|
+
)
|
|
107
|
+
rest_error: Optional[str] = None
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class FormatRequest(BaseModel):
|
|
111
|
+
config_dict: Dict[str, Any]
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class FormatResponse(BaseModel):
|
|
115
|
+
yaml: str
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def create_app() -> FastAPI:
|
|
119
|
+
app = FastAPI(title="polymo builder", version="0.1.0")
|
|
120
|
+
|
|
121
|
+
app.mount("/static", StaticFiles(directory=str(STATIC_PATH)), name="static")
|
|
122
|
+
|
|
123
|
+
@app.get("/favicon.ico", include_in_schema=False)
|
|
124
|
+
async def favicon() -> FileResponse: # pragma: no cover - static convenience endpoint
|
|
125
|
+
return FileResponse(STATIC_PATH / "favicon.ico")
|
|
126
|
+
|
|
127
|
+
@app.get("/apple-touch-icon.png", include_in_schema=False)
|
|
128
|
+
@app.get("/apple-touch-icon-precomposed.png", include_in_schema=False)
|
|
129
|
+
async def apple_touch_icon() -> FileResponse: # pragma: no cover - static convenience endpoint
|
|
130
|
+
# Re-use existing high-res logo as apple touch icon
|
|
131
|
+
return FileResponse(STATIC_PATH / "logo192.png")
|
|
132
|
+
|
|
133
|
+
@app.get("/")
|
|
134
|
+
async def index(request: Request) -> Any:
|
|
135
|
+
return TEMPLATES.TemplateResponse(
|
|
136
|
+
"index.html",
|
|
137
|
+
{
|
|
138
|
+
"request": request,
|
|
139
|
+
"sample_config": SAMPLE_CONFIG_YAML,
|
|
140
|
+
"sample_config_dict": SAMPLE_CONFIG_DICT,
|
|
141
|
+
},
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
@app.post("/api/validate", response_model=ValidationResponse)
|
|
145
|
+
async def validate_config(payload: ValidationRequest) -> ValidationResponse:
|
|
146
|
+
try:
|
|
147
|
+
config = _load_config_payload(
|
|
148
|
+
payload.config, payload.config_dict, payload.token, payload.options
|
|
149
|
+
)
|
|
150
|
+
except ConfigError as exc:
|
|
151
|
+
return ValidationResponse(valid=False, stream=None, message=str(exc))
|
|
152
|
+
except ValueError as exc:
|
|
153
|
+
return ValidationResponse(valid=False, stream=None, message=str(exc))
|
|
154
|
+
|
|
155
|
+
config_dict = config_to_dict(config)
|
|
156
|
+
return ValidationResponse(
|
|
157
|
+
valid=True,
|
|
158
|
+
stream=config.stream.name,
|
|
159
|
+
message="Configuration is valid",
|
|
160
|
+
config=config_dict,
|
|
161
|
+
yaml=dump_config(config),
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
@app.post("/api/sample", response_model=SampleResponse)
|
|
165
|
+
async def sample_records(payload: SampleRequest) -> SampleResponse:
|
|
166
|
+
try:
|
|
167
|
+
config = _load_config_payload(
|
|
168
|
+
payload.config, payload.config_dict, payload.token, payload.options
|
|
169
|
+
)
|
|
170
|
+
except ConfigError as exc:
|
|
171
|
+
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
172
|
+
except ValueError as exc:
|
|
173
|
+
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
174
|
+
|
|
175
|
+
stream_config = config.stream
|
|
176
|
+
|
|
177
|
+
raw_pages, rest_error = await run_in_threadpool(
|
|
178
|
+
partial(_collect_rest_preview, config, payload.limit)
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
if rest_error:
|
|
182
|
+
return SampleResponse(
|
|
183
|
+
stream=stream_config.name,
|
|
184
|
+
records=[],
|
|
185
|
+
dtypes=[],
|
|
186
|
+
raw_pages=raw_pages,
|
|
187
|
+
rest_error=rest_error,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
try:
|
|
191
|
+
records, dtypes = await run_in_threadpool(
|
|
192
|
+
partial(_collect_records, config, payload.token, payload.limit)
|
|
193
|
+
)
|
|
194
|
+
except Exception as exc: # pragma: no cover - surfaced to UI
|
|
195
|
+
raise HTTPException(status_code=502, detail=str(exc)) from exc
|
|
196
|
+
|
|
197
|
+
return SampleResponse(
|
|
198
|
+
stream=stream_config.name,
|
|
199
|
+
records=records,
|
|
200
|
+
dtypes=dtypes,
|
|
201
|
+
raw_pages=raw_pages,
|
|
202
|
+
rest_error=None,
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
@app.post("/api/format", response_model=FormatResponse)
|
|
206
|
+
async def format_config(payload: FormatRequest) -> FormatResponse:
|
|
207
|
+
try:
|
|
208
|
+
config = parse_config(payload.config_dict)
|
|
209
|
+
except ConfigError as exc:
|
|
210
|
+
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
211
|
+
return FormatResponse(yaml=dump_config(config))
|
|
212
|
+
|
|
213
|
+
return app
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _load_config_payload(
|
|
217
|
+
config_text: Optional[str],
|
|
218
|
+
config_dict: Optional[Dict[str, Any]],
|
|
219
|
+
token: Optional[str] = None,
|
|
220
|
+
options: Optional[Dict[str, Any]] = None,
|
|
221
|
+
) -> RestSourceConfig:
|
|
222
|
+
if config_dict is not None:
|
|
223
|
+
return parse_config(config_dict, token=token, options=options)
|
|
224
|
+
if config_text is None:
|
|
225
|
+
raise ConfigError("Configuration payload is missing")
|
|
226
|
+
return _parse_yaml(config_text, token=token, options=options)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _parse_yaml(
|
|
230
|
+
text: str,
|
|
231
|
+
token: Optional[str] = None,
|
|
232
|
+
options: Optional[Dict[str, Any]] = None,
|
|
233
|
+
) -> RestSourceConfig:
|
|
234
|
+
try:
|
|
235
|
+
parsed = yaml.safe_load(text)
|
|
236
|
+
except yaml.YAMLError as exc:
|
|
237
|
+
raise ConfigError(f"Invalid YAML: {exc}") from exc
|
|
238
|
+
return parse_config(parsed, token=token, options=options)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def _collect_rest_preview(config: RestSourceConfig, limit: int) -> Tuple[List[Dict[str, Any]], Optional[str]]:
|
|
242
|
+
pages: List[Dict[str, Any]] = []
|
|
243
|
+
total_records = 0
|
|
244
|
+
|
|
245
|
+
try:
|
|
246
|
+
with RestClient(base_url=config.base_url, auth=config.auth, options=config.options) as client:
|
|
247
|
+
for index, page in enumerate(client.fetch_pages(config.stream), start=1):
|
|
248
|
+
remaining = max(0, limit - total_records)
|
|
249
|
+
if remaining <= 0:
|
|
250
|
+
break
|
|
251
|
+
|
|
252
|
+
page_records = list(page.records)
|
|
253
|
+
if remaining < len(page_records):
|
|
254
|
+
page_records = page_records[:remaining]
|
|
255
|
+
|
|
256
|
+
total_records += len(page_records)
|
|
257
|
+
|
|
258
|
+
pages.append(
|
|
259
|
+
{
|
|
260
|
+
"page": index,
|
|
261
|
+
"url": page.url,
|
|
262
|
+
"status_code": page.status_code,
|
|
263
|
+
"headers": dict(page.headers),
|
|
264
|
+
"records": page_records,
|
|
265
|
+
"payload": page.payload,
|
|
266
|
+
}
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
if total_records >= limit:
|
|
270
|
+
break
|
|
271
|
+
return pages, None
|
|
272
|
+
except Exception as exc:
|
|
273
|
+
return pages, str(exc)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def _collect_records(config: RestSourceConfig, token: str | None, limit: int) -> Tuple[List[Dict[str, Any]], List[Dict[str, str]]]:
|
|
277
|
+
"""Collect processed records and dtypes using PySpark DataSource."""
|
|
278
|
+
import tempfile
|
|
279
|
+
import os
|
|
280
|
+
from ..config import dump_config
|
|
281
|
+
|
|
282
|
+
# Create a temporary config file for Spark to use
|
|
283
|
+
with tempfile.NamedTemporaryFile(mode='w', suffix='.yml', delete=False) as f:
|
|
284
|
+
config_yaml = dump_config(config)
|
|
285
|
+
f.write(config_yaml)
|
|
286
|
+
config_path = f.name
|
|
287
|
+
|
|
288
|
+
spark = _get_or_create_spark()
|
|
289
|
+
try:
|
|
290
|
+
df = _get_preview_df(config_path, token, spark, config.options)
|
|
291
|
+
records = df.limit(limit).collect()
|
|
292
|
+
dtypes = df.dtypes
|
|
293
|
+
record_dicts = [row.asDict(recursive=True) for row in records]
|
|
294
|
+
dtype_dicts: List[Dict[str, str]] = []
|
|
295
|
+
sample_row = record_dicts[0] if record_dicts else {}
|
|
296
|
+
for column, dtype in dtypes:
|
|
297
|
+
if sample_row and column in sample_row:
|
|
298
|
+
dtype_dicts.append({"column": column, "type": str(dtype)})
|
|
299
|
+
return record_dicts, dtype_dicts
|
|
300
|
+
finally:
|
|
301
|
+
spark.stop()
|
|
302
|
+
os.unlink(config_path)
|
|
303
|
+
|
|
304
|
+
def _get_preview_df(
|
|
305
|
+
config_path: str,
|
|
306
|
+
token: str | None,
|
|
307
|
+
spark: "SparkSession",
|
|
308
|
+
reader_options: Dict[str, Any],
|
|
309
|
+
):
|
|
310
|
+
"""Get a Spark DataFrame for previewing data from the specified stream."""
|
|
311
|
+
|
|
312
|
+
from polymo import ApiReader
|
|
313
|
+
|
|
314
|
+
_get_or_create_spark()
|
|
315
|
+
spark.dataSource.register(ApiReader)
|
|
316
|
+
|
|
317
|
+
# Alternative approach: Use the DataSource directly without format registration
|
|
318
|
+
# Create the DataSource instance manually
|
|
319
|
+
options = {
|
|
320
|
+
"config_path": config_path,
|
|
321
|
+
}
|
|
322
|
+
if token is not None:
|
|
323
|
+
options["token"] = token
|
|
324
|
+
for key, value in reader_options.items():
|
|
325
|
+
if key in {"config_path", "token"}:
|
|
326
|
+
continue
|
|
327
|
+
options[key] = value
|
|
328
|
+
return spark.read.format("polymo").options(**options).load()
|
|
329
|
+
|
|
330
|
+
def _get_or_create_spark() -> Any:
|
|
331
|
+
"""Get or create a Spark session."""
|
|
332
|
+
from pyspark.sql import SparkSession
|
|
333
|
+
|
|
334
|
+
spark = SparkSession.builder \
|
|
335
|
+
.appName("polymo-builder") \
|
|
336
|
+
.config("spark.sql.adaptive.enabled", "false") \
|
|
337
|
+
.config("spark.sql.adaptive.coalescePartitions.enabled", "false") \
|
|
338
|
+
.getOrCreate()
|
|
339
|
+
return spark
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
version: 0.1
|
|
2
|
+
source:
|
|
3
|
+
type: rest
|
|
4
|
+
base_url: https://api.github.com/orgs/godatadriven
|
|
5
|
+
stream:
|
|
6
|
+
path: /repos
|
|
7
|
+
infer_schema: true
|
|
8
|
+
schema: null
|
|
9
|
+
pagination:
|
|
10
|
+
type: none
|
|
11
|
+
record_selector:
|
|
12
|
+
field_path:
|
|
13
|
+
- owner
|
|
14
|
+
record_filter: null
|
|
15
|
+
cast_to_schema_types: false
|
|
Binary file
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" href="/favicon.ico" sizes="any" />
|
|
6
|
+
<link rel="icon" type="image/png" sizes="32x32" href="/favicon.ico" />
|
|
7
|
+
<link rel="icon" type="image/png" sizes="192x192" href="/favicon.ico" />
|
|
8
|
+
<link rel="apple-touch-icon" href="/favicon.ico" />
|
|
9
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
10
|
+
<title>polymo Connector Builder</title>
|
|
11
|
+
<script type="module" crossorigin src="/main.js"></script>
|
|
12
|
+
<link rel="stylesheet" crossorigin href="/main.css">
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<div id="root"></div>
|
|
16
|
+
</body>
|
|
17
|
+
</html>
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap";*,: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:Inter,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,ui-monospace,SFMono-Regular,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}.\!container{width:100%!important}.container{width:100%}@media (min-width: 640px){.\!container{max-width:640px!important}.container{max-width:640px}}@media (min-width: 768px){.\!container{max-width:768px!important}.container{max-width:768px}}@media (min-width: 1024px){.\!container{max-width:1024px!important}.container{max-width:1024px}}@media (min-width: 1280px){.\!container{max-width:1280px!important}.container{max-width:1280px}}@media (min-width: 1536px){.\!container{max-width:1536px!important}.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.-right-2{right:-.5rem}.-top-2{top:-.5rem}.left-1\/2{left:50%}.right-0{right:0}.right-3{right:.75rem}.top-0{top:0}.top-1\/2{top:50%}.top-full{top:100%}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.mx-auto{margin-left:auto;margin-right:auto}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-auto{margin-top:auto}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-10{height:2.5rem}.h-12{height:3rem}.h-16{height:4rem}.h-2{height:.5rem}.h-3{height:.75rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-\[520px\]{height:520px}.h-full{height:100%}.min-h-\[260px\]{min-height:260px}.min-h-\[96px\]{min-height:96px}.min-h-screen{min-height:100vh}.w-10{width:2.5rem}.w-12{width:3rem}.w-16{width:4rem}.w-2{width:.5rem}.w-24{width:6rem}.w-3{width:.75rem}.w-4{width:1rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-60{width:15rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-full{width:100%}.w-max{width:-moz-max-content;width:max-content}.min-w-0{min-width:0px}.min-w-full{min-width:100%}.min-w-max{min-width:-moz-max-content;min-width:max-content}.max-w-2xl{max-width:42rem}.max-w-4xl{max-width:56rem}.max-w-7xl{max-width:80rem}.max-w-\[140px\]{max-width:140px}.max-w-full{max-width:100%}.max-w-md{max-width:28rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.flex-shrink-0,.shrink-0{flex-shrink:0}.border-collapse{border-collapse:collapse}.-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\/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-y-2{--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))}.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))}.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))}.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))}.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-stretch{align-items:stretch}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-12{gap:3rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.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-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-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-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-t{border-top-width:1px}.border-border{--tw-border-opacity: 1;border-color:rgb(219 216 224 / var(--tw-border-opacity, 1))}.border-border\/60{border-color:#dbd8e099}.border-border\/70{border-color:#dbd8e0b3}.border-error\/40{border-color:#e5484d66}.border-red-7{--tw-border-opacity: 1;border-color:rgb(244 169 170 / var(--tw-border-opacity, 1))}.border-red-7\/50{border-color:#f4a9aa80}.bg-background{--tw-bg-opacity: 1;background-color:rgb(250 249 251 / var(--tw-bg-opacity, 1))}.bg-background\/50{background-color:#faf9fb80}.bg-background\/60{background-color:#faf9fb99}.bg-background\/70{background-color:#faf9fbb3}.bg-background\/80{background-color:#faf9fbcc}.bg-black\/50{background-color:#00000080}.bg-blue-4\/50{background-color:#d5efff80}.bg-blue-5{--tw-bg-opacity: 1;background-color:rgb(194 229 255 / var(--tw-bg-opacity, 1))}.bg-blue-9{--tw-bg-opacity: 1;background-color:rgb(0 144 255 / var(--tw-bg-opacity, 1))}.bg-current{background-color:currentColor}.bg-error{--tw-bg-opacity: 1;background-color:rgb(229 72 77 / var(--tw-bg-opacity, 1))}.bg-red-3{--tw-bg-opacity: 1;background-color:rgb(254 235 236 / var(--tw-bg-opacity, 1))}.bg-red-3\/50{background-color:#feebec80}.bg-red-3\/60{background-color:#feebec99}.bg-red-9{--tw-bg-opacity: 1;background-color:rgb(229 72 77 / var(--tw-bg-opacity, 1))}.bg-slate-12{--tw-bg-opacity: 1;background-color:rgb(28 32 36 / var(--tw-bg-opacity, 1))}.bg-slate-2{--tw-bg-opacity: 1;background-color:rgb(249 249 251 / var(--tw-bg-opacity, 1))}.bg-surface{--tw-bg-opacity: 1;background-color:rgb(242 239 243 / var(--tw-bg-opacity, 1))}.bg-surface\/70{background-color:#f2eff3b3}.bg-surface\/80{background-color:#f2eff3cc}.bg-surface\/90{background-color:#f2eff3e6}.bg-surface\/95{background-color:#f2eff3f2}.object-contain{-o-object-fit:contain;object-fit:contain}.p-1{padding:.25rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.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-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-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-8{padding-top:2rem;padding-bottom:2rem}.pr-9{padding-right:2.25rem}.pt-1{padding-top:.25rem}.pt-2{padding-top:.5rem}.text-left{text-align:left}.text-center{text-align:center}.align-top{vertical-align:top}.align-bottom{vertical-align:bottom}.font-mono{font-family:JetBrains Mono,ui-monospace,SFMono-Regular,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.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-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.leading-5{line-height:1.25rem}.leading-relaxed{line-height:1.625}.leading-snug{line-height:1.375}.leading-tight{line-height:1.25}.tracking-wide{letter-spacing:.025em}.text-background-foreground{--tw-text-opacity: 1;color:rgb(33 31 38 / var(--tw-text-opacity, 1))}.text-blue-9{--tw-text-opacity: 1;color:rgb(0 144 255 / var(--tw-text-opacity, 1))}.text-error{--tw-text-opacity: 1;color:rgb(229 72 77 / var(--tw-text-opacity, 1))}.text-muted{--tw-text-opacity: 1;color:rgb(188 186 199 / var(--tw-text-opacity, 1))}.text-red-11{--tw-text-opacity: 1;color:rgb(206 44 49 / var(--tw-text-opacity, 1))}.text-slate-10{--tw-text-opacity: 1;color:rgb(128 131 141 / var(--tw-text-opacity, 1))}.text-slate-11{--tw-text-opacity: 1;color:rgb(96 100 108 / var(--tw-text-opacity, 1))}.text-slate-12{--tw-text-opacity: 1;color:rgb(28 32 36 / var(--tw-text-opacity, 1))}.text-slate-9{--tw-text-opacity: 1;color:rgb(139 141 152 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.accent-blue-9{accent-color:#0090ff}.opacity-0{opacity:0}.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-soft{--tw-shadow: 0 10px 40px -15px rgba(15, 23, 42, .25);--tw-shadow-colored: 0 10px 40px -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-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}.ring-1{--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)}.ring-border\/40{--tw-ring-color: rgb(219 216 224 / .4)}.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)}.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{--tw-backdrop-blur: blur(8px);-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-filter{-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-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-200{transition-duration:.2s}:root{color-scheme:light dark}body{--tw-bg-opacity: 1;background-color:rgb(250 249 251 / var(--tw-bg-opacity, 1));font-family:Inter,system-ui,sans-serif;--tw-text-opacity: 1;color:rgb(33 31 38 / var(--tw-text-opacity, 1));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.dark body{background-color:#282a36}.theme-fade{animation:theme-fade .24s ease-out}@keyframes theme-fade{0%{opacity:.4;filter:saturate(.6) brightness(.9)}to{opacity:1;filter:none}}.animate-param-enter{animation:param-enter .22s ease-out}@keyframes param-enter{0%{opacity:0;transform:scale(.97) translateY(4px)}to{opacity:1;transform:scale(1) translateY(0)}}.modern-select{width:100%;-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.5rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(219 216 224 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(250 249 251 / var(--tw-bg-opacity, 1));padding:.5rem 2.25rem .5rem .75rem;font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(28 32 36 / var(--tw-text-opacity, 1));--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: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}.dark .modern-select{background-color:#282a36;border-color:#44475a;color:#f8f8f2}.modern-select:focus-visible{--tw-border-opacity: 1;border-color:rgb(142 200 246 / var(--tw-border-opacity, 1));outline:2px solid transparent;outline-offset:2px}.modern-select:is(.dark *){--tw-border-opacity: 1;border-color:rgb(68 71 90 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(48 50 65 / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(248 248 242 / var(--tw-text-opacity, 1))}.modern-select:focus-visible:is(.dark *){--tw-border-opacity: 1;border-color:rgb(189 147 249 / var(--tw-border-opacity, 1))}.dark input:not([type=checkbox]),.dark textarea,.dark select{--tw-border-opacity: 1;border-color:rgb(68 71 90 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(48 50 65 / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(248 248 242 / var(--tw-text-opacity, 1))}.dark input:not([type=checkbox])::-moz-placeholder,.dark textarea::-moz-placeholder,.dark select::-moz-placeholder{--tw-placeholder-opacity: 1;color:rgb(98 114 164 / var(--tw-placeholder-opacity, 1))}.dark input:not([type=checkbox])::placeholder,.dark textarea::placeholder,.dark select::placeholder{--tw-placeholder-opacity: 1;color:rgb(98 114 164 / var(--tw-placeholder-opacity, 1))}.dark ::-moz-placeholder{--tw-text-opacity: 1;color:rgb(98 114 164 / var(--tw-text-opacity, 1))}.dark ::placeholder{--tw-text-opacity: 1;color:rgb(98 114 164 / var(--tw-text-opacity, 1))}.dark .bg-background{background-color:#282a36!important}.dark .bg-surface{background-color:#303241!important}.dark .border-border{border-color:#44475a!important}.dark .text-muted{color:#6272a4!important}.dark .shadow-soft{box-shadow:0 10px 40px -15px #000000a6}.dark .text-slate-12,.dark .text-slate-11,.dark .text-slate-10{color:#f8f8f2!important}.dark .text-slate-9,.dark .text-slate-8{color:#6272a4!important}.dark .group:hover.bg-background\/60{background-color:#484c5e8c!important}.radix-scroll-area-scrollbar{display:flex;touch-action:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;background-color:transparent;padding:.125rem;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-timing-function:cubic-bezier(0,0,.2,1)}.radix-scroll-area-thumb{flex:1 1 0%;border-radius:9999px;--tw-bg-opacity: 1;background-color:rgb(188 186 199 / var(--tw-bg-opacity, 1))}.radix-scroll-area-thumb:hover{--tw-bg-opacity: 1;background-color:rgb(142 140 153 / var(--tw-bg-opacity, 1))}.radix-scroll-area-thumb:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(68 71 90 / var(--tw-bg-opacity, 1))}.radix-scroll-area-thumb:hover:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(98 114 164 / var(--tw-bg-opacity, 1))}button:focus-visible,input:focus-visible,textarea:focus-visible,select:focus-visible{outline:2px solid transparent;outline-offset:2px;--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);--tw-ring-opacity: 1;--tw-ring-color: rgb(142 200 246 / var(--tw-ring-opacity, 1));--tw-ring-offset-width: 2px;--tw-ring-offset-color: #f2eff3}button:focus-visible:is(.dark *),input:focus-visible:is(.dark *),textarea:focus-visible:is(.dark *),select:focus-visible:is(.dark *){--tw-ring-opacity: 1;--tw-ring-color: rgb(189 147 249 / var(--tw-ring-opacity, 1));--tw-ring-offset-color: #303241}[data-status=success]{--tw-text-opacity: 1;color:rgb(48 164 108 / var(--tw-text-opacity, 1))}[data-status=warn],[data-status=warning]{--tw-text-opacity: 1;color:rgb(255 197 61 / var(--tw-text-opacity, 1))}[data-status=error]{--tw-text-opacity: 1;color:rgb(229 72 77 / var(--tw-text-opacity, 1))}[data-status=info]{--tw-text-opacity: 1;color:rgb(13 116 206 / var(--tw-text-opacity, 1))}[data-status=info]:is(.dark *){--tw-text-opacity: 1;color:rgb(189 147 249 / var(--tw-text-opacity, 1))}pre{overflow-x:auto;border-radius:.5rem;--tw-bg-opacity: 1;background-color:rgb(249 249 251 / var(--tw-bg-opacity, 1));padding:1rem;font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(28 32 36 / var(--tw-text-opacity, 1))}.dark pre{color:#f8f8f2}pre:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(48 50 65 / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(248 248 242 / var(--tw-text-opacity, 1))}.dark table thead tr{background-color:#ffffff0a!important}.dark table tbody tr.even\:bg-slate-2\/40{background-color:#ffffff05!important}.dark table tbody tr:hover{background-color:#bd93f91f!important}.prism-container{position:relative;height:100%;font-family:JetBrains Mono,ui-monospace,SFMono-Regular,monospace;font-size:.875rem;line-height:1.25rem}.prism-editor{position:absolute;top:0;right:0;bottom:0;left:0;height:100%;width:100%;resize:none;background-color:transparent;line-height:1.25rem;color:transparent;caret-color:#fff;outline:2px solid transparent;outline-offset:2px}.prism-highlight{pointer-events:none;white-space:pre-wrap;overflow-wrap:break-word;text-align:left;font-family:JetBrains Mono,ui-monospace,SFMono-Regular,monospace;line-height:1.25rem}.dark .prism-highlight{color:#f8f8f2}.prism-highlight .token.comment{color:#6272a4}.prism-highlight .token.key{color:#ff79c6}.prism-highlight .token.punctuation{color:#f8f8f2}.prism-highlight .token.string{color:#f1fa8c}.prism-highlight .token.number{color:#bd93f9}.prism-highlight .token.boolean{color:#ffb86c}.prism-highlight .token.null{color:#f55}.prism-highlight .token.directive{color:#8be9fd}.prism-highlight{position:relative;--ch: .62ch}.prism-highlight .editor-line{position:relative;padding-left:0}.prism-highlight .editor-line:before{content:attr(data-line);position:absolute;left:-.75rem;transform:translate(-100%);width:3rem;text-align:right;padding-right:.75rem;color:#64748b;font-size:.75rem;line-height:1.25rem;font-variant-numeric:tabular-nums;opacity:.65}.dark .prism-highlight .editor-line:before{color:#6272a4;opacity:.55}.prism-highlight .editor-line.error{background:#ff55551a;box-shadow:inset 0 0 0 1px #ff555559}.dark .prism-highlight .editor-line.error{background:#ff55552b;box-shadow:inset 0 0 0 1px #ff555573}.prism-highlight .editor-line .col-marker{position:absolute;top:0;bottom:0;width:2px;background:#f55;left:calc(var(--col) * var(--ch));pointer-events:none;opacity:.4}.dark .prism-highlight .editor-line .col-marker{background:#f55;opacity:.55}.prism-highlight .editor-line .err-char{background:linear-gradient(transparent 70%,#ff55558c 70%);border-radius:2px}.dark .prism-highlight .editor-line .err-char{background:linear-gradient(transparent 65%,#ff5555bf 65%)}.prism-highlight::-webkit-scrollbar{width:10px;height:10px}.prism-highlight::-webkit-scrollbar-track{background:transparent}.prism-highlight::-webkit-scrollbar-thumb{background:#64748b59;border-radius:6px}.dark .prism-highlight::-webkit-scrollbar-thumb{background:#f8f8f233}.prism-highlight::-webkit-scrollbar-thumb:hover{background:#64748b8c}.dark .prism-highlight::-webkit-scrollbar-thumb:hover{background:#f8f8f259}.prism-highlight,.prism-highlight .editor-line,.prism-highlight .line-content{pointer-events:none}.prism-editor{color:transparent;text-shadow:none}.dark .prism-editor{color:transparent}.prism-editor{caret-color:#111}.dark .prism-editor{caret-color:#f8f8f2}[role=tooltip]{animation:fadeIn .12s ease-out}@keyframes fadeIn{0%{opacity:0;transform:translate(-50%,4px)}to{opacity:1;transform:translate(-50%)}}.dark .btn-accent{--tw-bg-opacity: 1;background-color:rgb(189 147 249 / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(248 248 242 / var(--tw-text-opacity, 1))}.dark .btn-accent:hover{--tw-bg-opacity: 1;background-color:rgb(255 121 198 / var(--tw-bg-opacity, 1))}.dark .border-accent{--tw-border-opacity: 1;border-color:rgb(189 147 249 / var(--tw-border-opacity, 1))}.validate-flash-success{animation:validateFlashSuccess 4s ease-in-out forwards}.validate-flash-error{animation:validateFlashError 4s ease-in-out forwards}@keyframes validateFlashSuccess{0%,85%{background:#30a46c;color:#fff}to{background:transparent;color:inherit}}@keyframes validateFlashError{0%,85%{background:#e5484d;color:#fff}to{background:transparent;color:inherit}}.dark button.validate-flash-success,.dark .validate-flash-success{animation:darkValidateFlashSuccess 4s ease-in-out forwards;position:relative}.dark button.validate-flash-error,.dark .validate-flash-error{animation:darkValidateFlashError 4s ease-in-out forwards;position:relative}.dark button.validate-flash-success:after,.dark .validate-flash-success:after,.dark button.validate-flash-error:after,.dark .validate-flash-error:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:inherit;pointer-events:none}.dark button.validate-flash-success:after,.dark .validate-flash-success:after{background:radial-gradient(circle at 30% 30%,#50fa7b59,#50fa7b0d)}.dark button.validate-flash-error:after,.dark .validate-flash-error:after{background:radial-gradient(circle at 30% 30%,#f556,#ff55550f)}@keyframes darkValidateFlashSuccess{0%,85%{background-color:#50fa7b40!important;color:#fff!important;border-color:#50fa7b8c!important;box-shadow:0 0 #50fa7b99,0 0 16px 4px #50fa7b59}to{background-color:transparent!important;color:inherit!important;border-color:var(--border-color,rgba(100,100,120,.4))!important;box-shadow:none}}@keyframes darkValidateFlashError{0%,85%{background-color:#ff555547!important;color:#fff!important;border-color:#ff55558c!important;box-shadow:0 0 #f559,0 0 16px 4px #ff555561}to{background-color:transparent!important;color:inherit!important;border-color:var(--border-color,rgba(100,100,120,.4))!important;box-shadow:none}}.dark .bg-blue-9{transition:background-color .3s ease,box-shadow .4s ease}.dark .bg-blue-9:hover{box-shadow:0 0 #bd93f900,0 0 12px 2px #bd93f959}.even\:bg-slate-2\/40:nth-child(2n){background-color:#f9f9fb66}.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\:border-blue-7:hover{--tw-border-opacity: 1;border-color:rgb(142 200 246 / var(--tw-border-opacity, 1))}.hover\:border-blue-7\/60:hover{border-color:#8ec8f699}.hover\:border-red-7:hover{--tw-border-opacity: 1;border-color:rgb(244 169 170 / var(--tw-border-opacity, 1))}.hover\:bg-blue-10:hover{--tw-bg-opacity: 1;background-color:rgb(5 136 240 / var(--tw-bg-opacity, 1))}.hover\:bg-blue-3\/20:hover{background-color:#e6f4fe33}.hover\:bg-blue-3\/40:hover{background-color:#e6f4fe66}.hover\:bg-blue-3\/50:hover{background-color:#e6f4fe80}.hover\:bg-blue-3\/60:hover{background-color:#e6f4fe99}.hover\:bg-red-10:hover{--tw-bg-opacity: 1;background-color:rgb(220 62 66 / var(--tw-bg-opacity, 1))}.hover\:bg-red-3\/60:hover{background-color:#feebec99}.hover\:bg-slate-3:hover{--tw-bg-opacity: 1;background-color:rgb(240 240 243 / var(--tw-bg-opacity, 1))}.hover\:text-blue-11:hover{--tw-text-opacity: 1;color:rgb(13 116 206 / var(--tw-text-opacity, 1))}.hover\:text-red-10:hover{--tw-text-opacity: 1;color:rgb(220 62 66 / var(--tw-text-opacity, 1))}.hover\:text-slate-12:hover{--tw-text-opacity: 1;color:rgb(28 32 36 / var(--tw-text-opacity, 1))}.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-sm:hover{--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)}.focus\:border-blue-7:focus{--tw-border-opacity: 1;border-color:rgb(142 200 246 / var(--tw-border-opacity, 1))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-blue-7:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(142 200 246 / var(--tw-ring-opacity, 1))}.focus-visible\:border-blue-7:focus-visible{--tw-border-opacity: 1;border-color:rgb(142 200 246 / var(--tw-border-opacity, 1))}.focus-visible\:bg-blue-9:focus-visible{--tw-bg-opacity: 1;background-color:rgb(0 144 255 / var(--tw-bg-opacity, 1))}.focus-visible\:text-white:focus-visible{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.focus-visible\:opacity-100:focus-visible{opacity:1}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-1:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(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-visible\:ring-2:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-blue-5:focus-visible{--tw-ring-opacity: 1;--tw-ring-color: rgb(194 229 255 / var(--tw-ring-opacity, 1))}.focus-visible\:ring-blue-7:focus-visible{--tw-ring-opacity: 1;--tw-ring-color: rgb(142 200 246 / var(--tw-ring-opacity, 1))}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.group:hover .group-hover\:border-blue-7\/50{border-color:#8ec8f680}.group:hover .group-hover\:bg-blue-5\/80{background-color:#c2e5ffcc}.group:hover .group-hover\:opacity-100{opacity:1}.data-\[state\=active\]\:border-b-2[data-state=active]{border-bottom-width:2px}.data-\[state\=active\]\:border-blue-9[data-state=active]{--tw-border-opacity: 1;border-color:rgb(0 144 255 / var(--tw-border-opacity, 1))}.data-\[state\=active\]\:bg-blue-9[data-state=active]{--tw-bg-opacity: 1;background-color:rgb(0 144 255 / var(--tw-bg-opacity, 1))}.data-\[state\=checked\]\:bg-blue-4[data-state=checked]{--tw-bg-opacity: 1;background-color:rgb(213 239 255 / var(--tw-bg-opacity, 1))}.data-\[state\=active\]\:text-blue-11[data-state=active]{--tw-text-opacity: 1;color:rgb(13 116 206 / var(--tw-text-opacity, 1))}.data-\[state\=active\]\:text-white[data-state=active]{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.data-\[state\=active\]\:shadow-sm[data-state=active]{--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)}@supports (backdrop-filter: var(--tw)){.supports-\[backdrop-filter\]\:bg-slate-2\/75{background-color:#f9f9fbbf}}.dark\:border-\[\#2c313a\]:is(.dark *){--tw-border-opacity: 1;border-color:rgb(44 49 58 / var(--tw-border-opacity, 1))}.dark\:border-drac-border:is(.dark *){--tw-border-opacity: 1;border-color:rgb(68 71 90 / var(--tw-border-opacity, 1))}.dark\:border-drac-border\/40:is(.dark *){border-color:#44475a66}.dark\:border-drac-border\/50:is(.dark *){border-color:#44475a80}.dark\:border-drac-border\/60:is(.dark *){border-color:#44475a99}.dark\:border-drac-red\/40:is(.dark *){border-color:#f556}.dark\:border-red-9\/30:is(.dark *){border-color:#e5484d4d}.dark\:border-slate-6:is(.dark *){--tw-border-opacity: 1;border-color:rgb(217 217 224 / var(--tw-border-opacity, 1))}.dark\:bg-\[\#1d2026\]:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(29 32 38 / var(--tw-bg-opacity, 1))}.dark\:bg-\[\#1f232b\]\/60:is(.dark *){background-color:#1f232b99}.dark\:bg-\[\#1f232b\]\/80:is(.dark *){background-color:#1f232bcc}.dark\:bg-\[\#242a33\]:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(36 42 51 / var(--tw-bg-opacity, 1))}.dark\:bg-\[\#262c35\]:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(38 44 53 / var(--tw-bg-opacity, 1))}.dark\:bg-\[\#272d38\]:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(39 45 56 / var(--tw-bg-opacity, 1))}.dark\:bg-\[\#282a36\]\/70:is(.dark *){background-color:#282a36b3}.dark\:bg-\[\#2d3541\]:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(45 53 65 / var(--tw-bg-opacity, 1))}.dark\:bg-\[\#303745\]:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(48 55 69 / var(--tw-bg-opacity, 1))}.dark\:bg-\[\#313341\]\/50:is(.dark *){background-color:#31334180}.dark\:bg-blue-7\/40:is(.dark *){background-color:#8ec8f666}.dark\:bg-blue-9\/20:is(.dark *){background-color:#0090ff33}.dark\:bg-drac-accent:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(189 147 249 / var(--tw-bg-opacity, 1))}.dark\:bg-drac-base:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(40 42 54 / var(--tw-bg-opacity, 1))}.dark\:bg-drac-red\/25:is(.dark *){background-color:#ff555540}.dark\:bg-drac-surface:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(48 50 65 / var(--tw-bg-opacity, 1))}.dark\:bg-drac-surface\/60:is(.dark *){background-color:#30324199}.dark\:bg-drac-surface\/80:is(.dark *){background-color:#303241cc}.dark\:bg-red-9\/15:is(.dark *){background-color:#e5484d26}.dark\:bg-red-9\/20:is(.dark *){background-color:#e5484d33}.dark\:bg-slate-1:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(252 252 253 / var(--tw-bg-opacity, 1))}.dark\:bg-slate-2:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(249 249 251 / var(--tw-bg-opacity, 1))}.dark\:text-blue-9:is(.dark *){--tw-text-opacity: 1;color:rgb(0 144 255 / var(--tw-text-opacity, 1))}.dark\:text-drac-foreground:is(.dark *){--tw-text-opacity: 1;color:rgb(248 248 242 / var(--tw-text-opacity, 1))}.dark\:text-drac-foreground\/80:is(.dark *){color:#f8f8f2cc}.dark\:text-drac-foreground\/90:is(.dark *){color:#f8f8f2e6}.dark\:text-drac-muted:is(.dark *){--tw-text-opacity: 1;color:rgb(98 114 164 / var(--tw-text-opacity, 1))}.dark\:text-red-9:is(.dark *){--tw-text-opacity: 1;color:rgb(229 72 77 / var(--tw-text-opacity, 1))}.dark\:text-slate-12:is(.dark *){--tw-text-opacity: 1;color:rgb(28 32 36 / var(--tw-text-opacity, 1))}.dark\:accent-drac-accent:is(.dark *){accent-color:#bd93f9}.dark\:shadow-\[0_8px_24px_-6px_rgba\(0\,0\,0\,0\.7\)\]:is(.dark *){--tw-shadow: 0 8px 24px -6px rgba(0,0,0,.7);--tw-shadow-colored: 0 8px 24px -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)}.dark\:ring-drac-border\/30:is(.dark *){--tw-ring-color: rgb(68 71 90 / .3)}.dark\:hover\:border-drac-accent:hover:is(.dark *){--tw-border-opacity: 1;border-color:rgb(189 147 249 / var(--tw-border-opacity, 1))}.dark\:hover\:border-drac-accent\/60:hover:is(.dark *){border-color:#bd93f999}.dark\:hover\:border-drac-red\/80:hover:is(.dark *){border-color:#f55c}.dark\:hover\:bg-\[\#273242\]:hover:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(39 50 66 / var(--tw-bg-opacity, 1))}.dark\:hover\:bg-\[\#383f4c\]:hover:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(56 63 76 / var(--tw-bg-opacity, 1))}.dark\:hover\:bg-blue-9\/20:hover:is(.dark *){background-color:#0090ff33}.dark\:hover\:bg-blue-9\/25:hover:is(.dark *){background-color:#0090ff40}.dark\:hover\:bg-blue-9\/30:hover:is(.dark *){background-color:#0090ff4d}.dark\:hover\:bg-drac-base\/60:hover:is(.dark *){background-color:#282a3699}.dark\:hover\:text-drac-accent:hover:is(.dark *){--tw-text-opacity: 1;color:rgb(189 147 249 / var(--tw-text-opacity, 1))}.dark\:hover\:text-drac-foreground:hover:is(.dark *){--tw-text-opacity: 1;color:rgb(248 248 242 / var(--tw-text-opacity, 1))}.dark\:hover\:text-drac-red:hover:is(.dark *){--tw-text-opacity: 1;color:rgb(255 85 85 / var(--tw-text-opacity, 1))}.dark\:hover\:shadow-\[0_0_8px_rgba\(80\,250\,123\,0\.15\)\]:hover:is(.dark *){--tw-shadow: 0 0 8px rgba(80,250,123,.15);--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)}.dark\:focus\:border-drac-accent:focus:is(.dark *){--tw-border-opacity: 1;border-color:rgb(189 147 249 / var(--tw-border-opacity, 1))}.dark\:focus\:ring-drac-accent:focus:is(.dark *){--tw-ring-opacity: 1;--tw-ring-color: rgb(189 147 249 / var(--tw-ring-opacity, 1))}.dark\:focus-visible\:border-drac-accent:focus-visible:is(.dark *){--tw-border-opacity: 1;border-color:rgb(189 147 249 / var(--tw-border-opacity, 1))}.dark\:focus-visible\:bg-drac-accent:focus-visible:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(189 147 249 / var(--tw-bg-opacity, 1))}.dark\:focus-visible\:ring-drac-accent:focus-visible:is(.dark *){--tw-ring-opacity: 1;--tw-ring-color: rgb(189 147 249 / var(--tw-ring-opacity, 1))}.dark\:focus-visible\:ring-drac-accent\/40:focus-visible:is(.dark *){--tw-ring-color: rgb(189 147 249 / .4)}.group:hover .dark\:group-hover\:bg-blue-9\/30:is(.dark *){background-color:#0090ff4d}.dark\:data-\[state\=active\]\:border-drac-accent[data-state=active]:is(.dark *){--tw-border-opacity: 1;border-color:rgb(189 147 249 / var(--tw-border-opacity, 1))}.dark\:data-\[state\=active\]\:text-drac-accent[data-state=active]:is(.dark *){--tw-text-opacity: 1;color:rgb(189 147 249 / var(--tw-text-opacity, 1))}@supports (backdrop-filter: var(--tw)){.dark\:supports-\[backdrop-filter\]\:bg-drac-surface\/70:is(.dark *){background-color:#303241b3}}@media (min-width: 768px){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (min-width: 1024px){.lg\:grid-cols-\[minmax\(0\,1fr\)_minmax\(200px\,auto\)\]{grid-template-columns:minmax(0,1fr) minmax(200px,auto)}.lg\:items-end{align-items:flex-end}.lg\:px-6{padding-left:1.5rem;padding-right:1.5rem}}.\[\&_td\]\:whitespace-nowrap td{white-space:nowrap}.\[\&_td\]\:whitespace-pre-wrap td{white-space:pre-wrap}
|